简体   繁体   中英

python (deI) statement and python behavior

When a del statement is issued:

del var

Shouldn't it be removed from the list of known variable and shouldn't the python interpreter spit out "unresolved reference" error?

Or is it simply just deleting the object and leaving the name (var) not pointing anywhere? Why would that kind of behavior be useful? In what cases?

Also I am talking simply about deleting a single variable. Not del list[3] or alike.

note: I am asking if this python's behavior is meant that way. And in what cases, it would be still useful.

EDIT: Charles Addis gave a detailed explanation. I also admit my mistake that I mistook the pycharm behavior as official python's. I am now trying out ipython along with official python interactive shell. Despite this being my mistake, I am glad that I learnt a lot about python variables along with some python debug commands.

Not sure what you're asking, as clearly thats what happens...

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x = 10
>>> 'x' in vars()
True
>>> vars()['x']
10
>>> del x
>>> 'x' in vars()
False
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

As you can see, Python allows access to valid identifiers from the current scope in locals() (and vars() works similarly - there is also dir(obj) which will display attributes of an object)... So del essentially removes it from memory, which removes it from the data structures returned by these functions as well. So the identifier is no longer valid. It's not like in C where you might free some memory and set the value to NULL .

>>> x = 10
>>> def func():
...   global x
...   del x
...
>>> x
10
>>> func()
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>>

Update:

Raymond made a good point when he mentioned that the object itself (read: the actual data in memory that the identifier points too, for lack of a more detailed explanation) is only freed when it's reference count goes to 0. IMO he could have done a better job detailing this in the python interpreter, so I'll have a go at it.

We'll use the ID function to prove this:

Help on built-in function id in module __builtin__:

id(...)
    id(object) -> integer

    Return the identity of an object.  This is guaranteed to be unique among
    simultaneously existing objects.  (Hint: it's the object's memory address.)

Pay attention to whats going on here, you'll see that for immutable types, different variables reference the same memory (strings are immutable in python and are interned, which means only one copy of each unique string is stored -- in ruby, symbols are interned strings).

>>> import sys
>>> x = 10     # 10 is a common value, probably exists in memory already
>>> sys.getrefcount(x)
26
>>> id(x)      # memory location of x
140266396760096
>>> y = x
>>> id(y) == id(x)
True
>>> z = 10
>>> id(z) == id(y) == id(x)
True
>>> sys.getrefcount(y)
28
>>> sys.getrefcount(z)
28
>>> del y, z
>>> sys.getrefcount(x)
26
>>> del x
>>> x = 'charlie'
>>> id(x)
4442795056
>>> y = 'charlie'
>>> z = x
>>> id(x) == id(y) == id(z)
True
>>> sys.getrefcount(x)
4
>>> sys.getrefcount(y)
4
>>> sys.getrefcount(z)
4
>>> del y
>>> del x
>>> sys.getrefcount(z)     # will be two because this line is an additional reference
2
>>> id(z)                  # pay attention to this memory location because this 
4442795056                 # is the last remaining reference to 'charlie', and
>>> del z                  # when it goes out of scope 'charlie' is removed from
>>>                        # memory.
>>> id('charlie')          # This has a different memory location because 'charlie'
4442795104                 # had to be re-created.

First we set the identifier 'x' == 10, a common integer value. Since 10 is such a common value, it's almost guaranteed that something in the processes memory already has that value. Since integers are immutable in python, we only ever need one copy of each unique value stored in memory. In this case, there are 24 other references to 10 in memory. Setting x = 10 creates the 25th reference, and calling sys.getrefcount(x) is the 26th reference (though it quickly goes out of scope). When we set y = 10 and z = x , we know that they all point to the same data because they all have the same memory location. Calling del alters the reference count, but even when all 3 are deleted the integer 10 still exists in memory.

Next we create set x = 'charlie' , followed by y = 'charlie' , and finally z = x . You can see all of these variables have the same memory address. Once we delete all of these variables there are no more references to 'charlie' . We can verify this by calling id('charlie') which will produce a different memory address meaning the string did not exist in memory when we called that function.

One more thing to note is the location of 'charlie' and 10 in memory. 10 has a significantly higher memory address than Charlie does. This is because they exist in different locations of memory. 'charlie' exists on the heap whereas 10 exists on the stack.

>>> hex(id(10))         # high address, this is on the stack
'0x7f9250c0b820'
>>> hex(id('charlie'))  # lower address, this is on the heap
'0x108cfac60

Shouldn't it be removed from the list of known variable and shouldn't the python interpreter spit out "unresolved reference" error?

This is exactly what happens. Once you del something, the next reference to it will raise NameError .

Or is it simply just deleting the object and leaving the name (var) not pointing anywhere? Why would that kind of behavior be useful? In what cases?

In Python, things are a bit different. There are no "variables" as you might be used to in other languages.

There is the object space, where data lives - and the namespace, where names live.

names are what we normally refer to in other languages as variables but in Python they are simply labels to an object in the data space.

Once the label (name) is removed with del , its simply taking away the label that points to the object. The object (which has the value) remains; unless its not referred to by any other name, in which case Python will then garbage collect it. Names are just lightweight labels that point to objects in the object space, and are the only way we can access those objects.

Here is an example to illustrate this:

>>> x = 5
>>> y = x
>>> del x
>>> y
5

Now I deleted x , but since y is still pointing to the same object as x (the integer 5 ), it remains and I can access it again; but if I try to access x :

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

The "del" removes the name from the current namespace. If the underlying object has its reference count drop to zero, then the object itself is freed.

>>> import sys
>>> x = 123456
>>> y = x               # create a second reference to the number
>>> dir()               # known variables include "x" and "y"
['__builtins__', '__doc__', '__name__', '__package__', 'sys', 'x', 'y']
>>> sys.getrefcount(x)
3
>>> del x               # remove "x" as a known variable
>>> dir()               # known variables includes only "y"
['__builtins__', '__doc__', '__name__', '__package__', 'sys', 'y']
>>> sys.getrefcount(y)  # reference count is now lower by 1
2
>>> del y               # remove "y" as a known variable
>>> dir()               # known variables no longer include "x" and "y"
['__builtins__', '__doc__', '__name__', '__package__', 'sys']
>>> x                   # unresolved variable raises a "NameError"

Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    x                  # unresolved variable raises a "NameError"
NameError: name 'x' is not defined

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM