I deleted my dict, but my dict_keys don't mind, why?

Since dict.keys (and dict.items and dict.values same) returns a representation of the dictionary object, I would suggest that deleting the dictionary from which they were created to actually affect dict_keys , we got them from.

With a simple dictionary and its keys:

 d = {i:i for i in range(20)} k = d.keys() # similarly with d.values and d.items 

Apparently this is not the case:

 del d i = iter(k) list(i) # works fine and prints the keys 

Does anyone know why this is so?

+5
source share
2 answers

del d deletes the variable d , but the object to which it refers will continue to exist if there are other references. You don't need a dictionary to watch this:

 >>> d = {i:i for i in range(5)} >>> dd = d >>> d['x'] = 'x' >>> del d >>> d Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'd' is not defined >>> dd {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 'x': 'x'} 

(The string d['x']='x' shows that dd=d does not copy the dictionary itself, but makes only an additional reference.)

Also compare the clear behavior that modifies the actual object:

 >>> d = {i:i for i in range(5)} >>> k = d.keys() >>> del d >>> list(k) [0, 1, 2, 3, 4] >>> d = {i:i for i in range(5)} >>> k = d.keys() >>> d.clear() >>> list(k) [] 
+9
source

Calling the d.keys() object simply increments the reference count for the dictionary object; del d will not call the garbage collector for the object labeled d , since the link will always be greater than zero.

You can see the reference counter for increasing the dictionary object when d.keys() is called using sys.getrefcount :

 from sys import getrefcount d = {i:i for i in range(20)} getrefcount(d) # 2 k = d.keys() getrefcount(d) # 3 (+1 due to d.keys()) 

in a call that builds a dictionary, displays this reference increment :

 Py_INCREF(dict); dv->dv_dict = (PyDictObject *)dict; 

It is executed immediately before the object is stored in the corresponding record of the structure of the view object.

Since the view is actually just an iterable object with a reference to the underlying dict, you can also take one step deeper and delete the keys object after receiving its iterator and still be able to get the values:

 i = iter(k) # +1 reference del k, d next(i) # 0 

iter(k) again increases the reference count for the source dictionary, keeping the object away from the collection.

+4
source

Source: https://habr.com/ru/post/1264080/


All Articles