【问题标题】:dir(object) vs object.__dir__() [duplicate]dir(object) vs object.__dir__() [重复]
【发布时间】:2015-08-08 23:07:39
【问题描述】:

这是简单的 Python 代码:案例 1 和案例 2 之间有什么区别——为什么我在第一种情况下得到的结果为 False 而在其他情况下为 True?为什么在案例 2 中 ids 相等? dir(object) 是否也在内部调用 object._dir__()?如果是这样,两个调用的返回对象/结果应该是相同的。

class Hello:
    def __init__(self):
        self.a1 = "a1"


hello = Hello()
print(hello)

# Case 1
var1 = dir(hello)
var2 = hello.__dir__()
print(id(var1), id(var2), id(var1) == id(var2))

# Case 2
print(id(dir(hello)), id(hello.__dir__()), id(dir(hello)) == id(hello.__dir__()))
print(dir(hello) == hello.__dir__())

输出

<__main__.Hello object at 0x7f320828c320>
139852862206472 139852862013960 False
139852862014024 139852862014024 True
False

【问题讨论】:

  • 如果您认为您的问题不是重复的,请添加注释来解释原因。如果答案(原始问题或这个问题)没有涵盖您想知道的所有内容,请添加评论。只是反复编辑您的问题,并希望我们会注意到这些更改只有在您对时机非常幸运时才有效。
  • @abarnert,我对 stackoverflow 很陌生。下次我会做的,谢谢你告诉我。
  • 没问题。我什么也没说,只是在我即将关闭页面时碰巧注意到您的一个编辑,并通过编辑我的答案来回答它,我不想给人一种错误的印象,即您可以每天都指望这种时机。

标签: python class


【解决方案1】:

您收到True 只是一个巧合。 (嗯,不是巧合,因为 CPython 的实现很有可能......但这不是语言所需要的。)

在情况 1 中,var1var2 中有两个不同的 dicts。他们都同时活着,所以他们不能拥有相同的id

在情况 2 中,您又拥有两个不同的 dicts——但这一次,您没有将它们存储在任何地方;只要你在一个上调用id,你就会释放它,这意味着它可以在你得到另一个之前收集垃圾***这意味着它可以最终重用相同的id***

注意id 的文档说:

这是一个整数,保证在其生命周期内对于该对象是唯一且恒定的。两个生命周期不重叠的对象可能具有相同的id() 值。

如果你真的想测试两个表达式是否引用同一个对象,使用is,不要比较它们的ids。


您编辑的问题还问:

dir(object) 是否也在内部调用 object._dir__()?

根据dir

如果对象有一个名为__dir__()的方法,这个方法将被调用并且必须返回属性列表。

__dir__ 上的数据模型部分说:

在对象上调用dir() 时调用。必须返回一个序列。 dir() 将返回的序列转换为列表并对其进行排序。

然后你说:

如果是这样,两个调用的返回对象应该是相同的。

嗯,这取决于您所说的“相同”是什么意思。它应该返回 一个相等的 值(因为没有任何变化),但它不会是 相同的 值,这是您要测试的值。 (如果不是很明显为什么dir 每次都会给你一个新列表,那么应该很清楚它必须这样做,因为“dir() 将返回的序列转换为列出并排序”…)


* 因为 CPython 使用引用计数作为其主要的垃圾收集机制,所以“可以收集”通常意味着“将被立即收集”。对于大多数其他 Python 实现而言,情况并非如此。

** 如果您在阅读文档时不清楚评估表达式部分的顺序,您可以尝试dis.dis('id(dir(hello)) == id(hello.__dir__())') 按顺序查看实际的字节码。

*** 在 CPython 中,id 只是表示对象的 PyObject 结构的地址;如果一个PyObject 被释放,另一个相同类型的被立即分配,它通常会得到相同的地址。

【讨论】:

  • dir(object) 和 object._dir__() 具有相同的 id 让我感到困惑,现在很清楚了。谢谢。此外,如果 dir(object) 调用 object.__dir__(),为什么对 __dir__() 的调用没有出现在反汇编代码中? dis.dis('dir(hello)')
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-28
  • 2011-03-14
  • 2016-08-30
  • 1970-01-01
  • 2016-10-31
  • 2015-11-27
  • 1970-01-01
相关资源
最近更新 更多