关于python:为什么这是假的?

Why is this false? `SomeClass.method is SomeClass.method`

以该代码为例:

1
2
3
4
5
6
7
8
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
  • 例1:我会猜测它们是同一个对象。每次引用该方法时,python是否复制该方法?
  • 例2:应为。
  • 例3:应该是,因为它们是不同的对象。
  • 例4:为什么输出与例2不匹配?


例1:

Someclass.a_method是一种未绑定的方法。这些在当今的Python中甚至都不存在,所以把它当作一个无用的历史课。

Does Python make a copy of the method each time it is referenced?

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

1
2
3
4
5
6
>>> 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>

最后一行显示的是"绑定"操作,描述符调用该操作来访问类的属性,但手工编写。在纯Python中,它就像这样

1
2
3
4
class Function(object):
    def __get__(self, obj, objtype=None):
       "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj, objtype):

您也可以这样创建绑定方法:

1
2
3
>>> some_instance = SomeClass()
>>> SomeClass.__dict__['a_method'].__get__(some_instance, SomeClass)
<bound method SomeClass.a_method of <__main__.SomeClass instance at 0xcafef00d>>

例2:

方法比较是通过方法上的__func____self__属性进行的。在这种情况下,它们都是相同的:__func__是可以从类dict中挖掘出来的同一个普通老函数,__self__None。因此,尽管这些方法是不同的对象,但它们的比较是相等的。

例3:

对的。它们是不同的对象,因此不相同。

例4:

如前所述,比较使用__func____self__属性。结果与示例2不匹配,因为在本例中,__self__属性引用了不同的实例。由于SomeClass实例是按标识比较的,所以这些不同的实例比较不相等,因此这些方法也不相等。

关于当前版本的python的最后一个注释

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

1
2
3
4
>>> SomeClass.a_method
<function __main__.SomeClass.a_method(self)>
>>> SomeClass.a_method is SomeClass.__dict__['a_method']
True

python 2中的"未绑定方法"现在只是一个普通的旧函数,通过属性访问检索到的实例与类dict中的对象相同。在python2->python 3升级中,示例1的结果是从False更改为True