【问题标题】:Deleting main object by deleting reference通过删除引用删除主对象
【发布时间】:2018-08-14 00:05:50
【问题描述】:

我正在使用大型嵌套字典,并尝试删除嵌套子字典。我想知道为什么会出现以下行为。

当我设置对字典 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 被删除了。

【问题讨论】:

  • 不能在 Python 中删除对象——你所能做的就是删除引用,对象会在所有对它的引用消失后自动消失。
  • 您正在删除该名称。如果一个对象没有更多名称,Python 可能会也可能不会对它进行垃圾收集。
  • @PeterWood 我相信 CPython 会立即回收一个引用计数变为 0 的对象。当然,语言不能保证这一点,实际上,这不起作用比如说,Jython。

标签: python dictionary ref


【解决方案1】:

del 实际上并不处理任何内存的取消分配,它只是unbinds a value from a name,然后将该对象的引用计数减一。没有办法从给定单个引用的对象中系统地解除所有名称的绑定。

直到引用计数降至 0 后的某个时间点才会对对象进行垃圾回收。您可以使用 sys.getrefcount 方法查看对象的引用计数(通常比实际高 1 是因为其中的临时引用方法本身)。

我们可以在实践中使用该方法和__del__ 方法演示del(仅在对象的引用计数减为0时调用):

>>> # 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 关于引用计数的内部调用的文档,并查看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[:]

【讨论】:

  • gc 模块不会影响“正常”引用计数系统本身,相反,它允许您控制循环垃圾收集器的各个方面,这就是清理无法访问的引用循环。
  • 我没有说它控制系统,只是说它是一个自省的接口。
  • 当然,但我认为这应该在你的帖子中更清楚。有很多问题基本上归结为人们不了解gc.enablegc.disable 会实际影响
  • 很高兴做出或接受编辑。你会发现什么更清楚?
【解决方案2】:

del statement 的行为因要删除的内容而异。稍微解释一下:

删除名称会从本地或全局命名空间中删除该名称的绑定

这是提出的第二种情况。你有两个对同一个对象的引用。名称ref 已被删除,但名称d 仍然存在并且始终指向同一个对象。

但是,属性、订阅和切片具有不同的行为:

属性引用、订阅和切片的删除被传递给所涉及的主要对象

这更像第一种情况 - 从任一名称中删除一个元素将反映在另一个名称中:

input:
d = {"a":1, "b":2}
ref = d
del ref["a"]
print(d)

output:
{'b': 2}

因此,将引用包装在字典(或其他容器)中,将允许任何引用删除。

【讨论】:

  • 这与手头的问题无关,这就是为什么在引用计数为 2 的对象上调用 del 实际上并没有删除该对象。
  • 我同意引用计数是它的核心。这个解释的目的是为什么这种行为存在,而不是 Python 是如何处理它的。不同之处在于订阅的修改,最初用ref["c"]=3 突出显示。提问者发现了与所需内容相似的内容,并且通过删除字典的一部分,它可能与预期的行为非常接近而有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2020-01-31
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-05
相关资源
最近更新 更多