通过删除引用来删除主对象
Deleting main object by deleting reference
我正在使用大型嵌套词典,并试图删除嵌套子词典。我想知道为什么会出现以下行为。
当我设置对字典 d 的引用(称为 ref)时,然后我更改 ref 并打印 d,它显示了添加了第三个元素的 d 的更新版本。
input:
d={"a":1,"b":2}
ref=d
ref["c"]=3
print(d)
output:
{'a': 1, 'b': 2, 'c': 3}
鉴于此行为,我希望能够通过 delete
删除字典
input:
d={"a":1,"b":2}
ref=d
del ref
print(d)
output:
{'a': 1, 'b': 2}
我想知道有没有办法在我删除引用的时候删除原来的对象(意思是第二个程序的输出会出错,因为d被删除了。
del
statement 的行为因删除的内容而异。稍微解释一下:
Deletion of a name removes the binding of that name from the local or global namespace
这是第二个案例。您有两个对同一对象的引用。名称 ref
已被删除,但名称 d
仍然存在并且指向同一个对象总是如此。
但是,属性、订阅和切片具有不同的行为:
Deletion of attribute references, subscriptions and slicings is passed to the primary object involved
这更像是第一种情况 - 从任一名称中删除一个元素将反映在另一个名称中:
input:
d = {"a":1, "b":2}
ref = d
del ref["a"]
print(d)
output:
{'b': 2}
因此,将引用包装在字典(或其他容器)中,将允许通过任何引用进行删除。
del
实际上并不处理任何内存的取消分配,它只是 unbinds a value from a name,然后将该对象的引用计数减一。在给定单个引用的情况下,无法系统地解除所有名称与对象的绑定。
直到引用计数降为 0 之后的某个时间点,对象才会被垃圾回收。您可以使用 sys.getrefcount
方法查看对象的引用计数(通常比实际值高一个,因为方法本身中的临时引用)。
我们可以在实践中使用此方法和 __del__
方法(仅当对象的引用计数递减为 0 时调用)来演示 del
:
>>> # print something when refcount == 0 and object is about to be collected
>>> class Deleted:
... def __del__(self):
... print("actually deleted")
...
>>> a = Deleted()
>>> # just a
>>> sys.getrefcount(a) - 1
1
>>> b = a
>>> # a and b
>>> sys.getrefcount(a) - 1
2
>>> del a
>>> # now it's just b
>>> sys.getrefcount(b) - 1
1
>>> del b
actually deleted
如果您想详细了解所有这些在内部是如何工作的,请查看 C
API documentation on the internal calls for reference counting, and check out the gc
module,这是用于检查垃圾收集子系统的高级 python 接口。
鉴于您的具体问题,由于您使用的是可变类型的字典,您可以 clear
字典:
>>> a = {"a": 1}
>>> b = a
>>> # will clear the dict that both a and b are referencing
>>> b.clear()
>>> a
{}
或者,您可以使用等效的 range
语法来清除字典 del a[:]
。
我正在使用大型嵌套词典,并试图删除嵌套子词典。我想知道为什么会出现以下行为。
当我设置对字典 d 的引用(称为 ref)时,然后我更改 ref 并打印 d,它显示了添加了第三个元素的 d 的更新版本。
input:
d={"a":1,"b":2}
ref=d
ref["c"]=3
print(d)
output:
{'a': 1, 'b': 2, 'c': 3}
鉴于此行为,我希望能够通过 delete
删除字典input:
d={"a":1,"b":2}
ref=d
del ref
print(d)
output:
{'a': 1, 'b': 2}
我想知道有没有办法在我删除引用的时候删除原来的对象(意思是第二个程序的输出会出错,因为d被删除了。
del
statement 的行为因删除的内容而异。稍微解释一下:
Deletion of a name removes the binding of that name from the local or global namespace
这是第二个案例。您有两个对同一对象的引用。名称 ref
已被删除,但名称 d
仍然存在并且指向同一个对象总是如此。
但是,属性、订阅和切片具有不同的行为:
Deletion of attribute references, subscriptions and slicings is passed to the primary object involved
这更像是第一种情况 - 从任一名称中删除一个元素将反映在另一个名称中:
input:
d = {"a":1, "b":2}
ref = d
del ref["a"]
print(d)
output:
{'b': 2}
因此,将引用包装在字典(或其他容器)中,将允许通过任何引用进行删除。
del
实际上并不处理任何内存的取消分配,它只是 unbinds a value from a name,然后将该对象的引用计数减一。在给定单个引用的情况下,无法系统地解除所有名称与对象的绑定。
直到引用计数降为 0 之后的某个时间点,对象才会被垃圾回收。您可以使用 sys.getrefcount
方法查看对象的引用计数(通常比实际值高一个,因为方法本身中的临时引用)。
我们可以在实践中使用此方法和 __del__
方法(仅当对象的引用计数递减为 0 时调用)来演示 del
:
>>> # print something when refcount == 0 and object is about to be collected
>>> class Deleted:
... def __del__(self):
... print("actually deleted")
...
>>> a = Deleted()
>>> # just a
>>> sys.getrefcount(a) - 1
1
>>> b = a
>>> # a and b
>>> sys.getrefcount(a) - 1
2
>>> del a
>>> # now it's just b
>>> sys.getrefcount(b) - 1
1
>>> del b
actually deleted
如果您想详细了解所有这些在内部是如何工作的,请查看 C
API documentation on the internal calls for reference counting, and check out the gc
module,这是用于检查垃圾收集子系统的高级 python 接口。
鉴于您的具体问题,由于您使用的是可变类型的字典,您可以 clear
字典:
>>> a = {"a": 1}
>>> b = a
>>> # will clear the dict that both a and b are referencing
>>> b.clear()
>>> a
{}
或者,您可以使用等效的 range
语法来清除字典 del a[:]
。