【问题标题】:Very strange behavior of operator 'is' with methods操作员“是”的非常奇怪的行为与方法
【发布时间】:2014-08-13 14:40:51
【问题描述】:

为什么第一个结果是False,不应该是True吗?

>>> from collections import OrderedDict
>>> OrderedDict.__repr__ is OrderedDict.__repr__
False
>>> dict.__repr__ is dict.__repr__
True

【问题讨论】:

  • Python 3.3 返回 True
  • @JustinEngel:那是因为 Python 3 取消了未绑定的方法,所有方法都是绑定的。在 Python 3 中尝试OrderedDict().__repr__ is OrderedDict().__repr__,您会看到相同的行为。
  • 我很好奇在实际代码中怎么会涉及到这样的事情
  • @NickT:验证猴子补丁方法需要了解方法是如何绑定的。将一个类的方法添加到另一个类还需要您提取函数对象,而不是方法等。

标签: python python-2.7 methods python-internals


【解决方案1】:

对于用户定义的函数,在 Python 2 中,unboundbound 方法是通过 descriptor protocol 按需创建的; OrderedDict.__repr__ 就是这样一个方法对象,因为被包装的函数被实现为 pure-Python function

描述符协议将在支持它的对象上调用__get__ method,因此每当您尝试访问OrderedDict.__repr__ 时都会调用__repr__.__get__();对于类None(无实例)和类对象本身被传入。因为每次调用函数__get__ 方法时都会获得一个new 方法对象,所以is 失败。不是同一个方法对象。

dict.__repr__ 不是自定义 Python 函数,而是 C 函数,它的 __get__ 描述符方法 essentially just returns self when accessed on the class。每次访问该属性都会为您提供相同的对象,因此 is 有效:

>>> dict.__repr__.__get__(None, dict) is dict.__repr__  # None means no instance
True

方法具有引用包装函数的__func__ 属性,使用它来测试身份:

>>> OrderedDict.__repr__
<unbound method OrderedDict.__repr__>
>>> OrderedDict.__repr__.__func__
<function __repr__ at 0x102c2f1b8>
>>> OrderedDict.__repr__.__func__.__get__(None, OrderedDict)
<unbound method OrderedDict.__repr__>
>>> OrderedDict.__repr__.__func__ is OrderedDict.__repr__.__func__
True

Python 3 取消了 unbound 方法,function.__get__(None, classobj) 返回函数对象本身(因此它的行为类似于 dict.__repr__ 所做的)。但是您会看到与 bound 方法相同的行为,即从实例中检索的方法。

【讨论】:

  • 作为一个简单的测试来证明这一点,创建一个类,其__repr__ 方法为__repr__ = lambda :xis 测试将失败。实际上,覆盖__repr__ 通常会导致is 失败。
  • 而且,在一般情况下,没有类的纯 python 未绑定方法与 Trueis 相比。
  • @aruisdante:好吧,您可以创建(多个)对方法对象的引用,然后您仍然可以使用is。但是从类中检索方法会给您一个新对象,因为函数__get__ 方法会生成一个新对象。
  • 啊,是的,当然,我的意思是像 OP 那样通过直接比较。显然你的回答实际上是这样说的,只是不是很明显。也许提供一个简单的示例,您可以证明对于任何具有任何纯 python 方法的类都会发生这种情况,这将对未来的这个问题的查看者有所帮助。
  • @aruisdante:我更关注这里与dict.__repr__ 的区别;实际上,只是谈论方法对象是重复的。
【解决方案2】:

这两个OrderedDict.__repr__ 没有绑定到同一个对象。如果你尝试:

 OrderedDict.__repr__ == OrderedDict.__repr__

您会看到它们具有相同的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-13
    • 2011-03-01
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 2020-02-09
    相关资源
    最近更新 更多