为什么这是假的?`SomeClass.method是SomeClass.method`

Chr*_*son 2 python python-2.7 python-descriptors

以此代码为例:

class SomeClass():
    def a_method(self):
        pass

print(SomeClass.a_method is SomeClass.a_method)     # Example 1: False
print(SomeClass.a_method == SomeClass.a_method)     # Example 2: True
print(SomeClass().a_method is SomeClass().a_method) # Example 3: False
print(SomeClass().a_method == SomeClass().a_method) # Example 4: False
Run Code Online (Sandbox Code Playgroud)
  • 例1:我猜他们是同一个对象.Python每次引用时都会复制该方法吗?
  • 例2:预期.
  • 示例3:预期,因为它们是不同的对象.
  • 示例4:为什么此输出不匹配示例2?

wim*_*wim 7

例1:

Someclass.a_method是一种未绑定的方法.现在这些在Python中都不存在,所以请考虑这是一个无用的历史课.

Python每次引用时都会复制该方法吗?

是的,或多或少.这是通过描述符协议完成的.

>>> SomeClass.a_method  # unbound method via attribute access
<unbound method SomeClass.a_method>
>>> SomeClass.__dict__['a_method']  # just stored as a function in the class dict
<function __main__.a_method>
>>> SomeClass.__dict__['a_method'].__get__(None, SomeClass)
<unbound method SomeClass.a_method>
Run Code Online (Sandbox Code Playgroud)

最后一行显示了描述符为类上的属性访问调用但是手动写出的"绑定"操作.在纯Python中,它就是这样的

class Function(object):
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj, objtype):
Run Code Online (Sandbox Code Playgroud)

您还可以通过以下方式创建绑定方法:

>>> some_instance = SomeClass()
>>> SomeClass.__dict__['a_method'].__get__(some_instance, SomeClass)
<bound method SomeClass.a_method of <__main__.SomeClass instance at 0xcafef00d>>
Run Code Online (Sandbox Code Playgroud)

例2:

方法比较通过方法的属性__func____self__属性完成.在这种情况下,它们都是相同的:__func__你可以从类字典中挖出相同的普通旧函数,而且__self__None.因此,尽管这些方法是不同的对象,但它们相等.

例3:

正确.它们是不同的对象,因此不相同.

例4:

如前所述,比较是使用__func____self__属性.结果与示例2不匹配,因为在这种情况下,__self__属性引用不同的实例.那些不同的实例不比较相等,因为SomeClass实例按身份进行比较,因此方法也不比较相等.

关于当前Python版本的最后说明

除了示例1之外,上面提到的所有内容也适用于该语言的当前版本.在Python中,不再存在未绑定方法,删除了对象模型中的这种不必要的复杂性.

>>> SomeClass.a_method
<function __main__.SomeClass.a_method(self)>
>>> SomeClass.a_method is SomeClass.__dict__['a_method']
True
Run Code Online (Sandbox Code Playgroud)

Python 2中的"未绑定方法"现在只是一个普通的旧函数,通过属性访问检索的实例与类dict中的对象相同.的实施例1从结果变化FalseTrue> Python 3的升级-在Python 2.