今天我定义了一个专门用于测试下一步的课程:
class B(object):
def p(self):
print("p")
后来我这样做了:
>>> type(B.__dict__['p'])
<type 'function'>
>>> type(B.p)
<type 'instancemethod'>
那么,为什么? B.p
和B.__dict__['p']
不是同一个对象吗?
当我尝试这个时,我的惊讶就增加了:
>>> B.__dict__['p']
<function p at 0x3d2bc80>
>>> type(B.__dict__['p'])
<type 'function'>
好的,到目前为止一直很好,类型是两个结果function
,但是当我尝试时:
>>> B.p
<unbound method B.p>
>>> type(B.p)
<type 'instancemethod'>
什么?!,为什么? unbound method
和instancemethod
?那些是一样的吗?为什么有两个不同的名字?
这就是我正在使用的python:
Python 2.7.4 (default, Sep 26 2013, 03:20:26)
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
答案 0 :(得分:23)
这是一个非常好的问题。
要清除一些事情:
B.p
)访问方法名称时,它表示未绑定。B().p
)访问该方法时,称其为绑定。 绑定和未绑定之间的主要区别在于,如果绑定,第一个参数将隐式地是调用的实例类。这就是我们在定义它时为每个方法添加self
作为第一个参数的原因。当 unbound 时,您必须显式传递要应用该方法逻辑的类的实例。
例如:
class B(object):
def foo(self):
print 'ok'
>>>B().foo()
ok
>>>B.foo()
Exception, missing an argument.
>>>B.foo(B())
ok
这是绑定和未绑定的基本解释。现在关于__dict__
古怪。 Python中的任何对象都可以定义__get__
和__set__
方法,当它们是类中的属性时,它控制对它们的访问。这些被称为描述符。
简单来说,当您通过其实例或类访问类的属性(属性)时,Python不会直接返回该对象,而是调用__get__
或__set__
方法反过来返回一个方便的对象来使用。
Python中的函数会覆盖此__get__
方法。因此,当您发出B.foo
或B().foo
时,它会返回instancemethod
类型,这是function
类型的包装器(一个包装器,它隐含地传递self
作为第一个参数)。当您通过原始类字典访问该函数时,不会调用__get__
,因为您没有将它们作为类的属性访问,因此返回值为 raw 功能
关于这个话题有很多话要说,我试着给这样一个聪明的主题提供一个非常简单的答案。您可以在Guido的博客文章The Inside Story on New-Style Classes上找到权威性信息,非常值得推荐。
更新:关于您的上一个例子:
>>> B.p
<unbound method B.p>
>>> type(B.p)
<type 'instancemethod'>
请注意,在Python的解释器中>>>B.p
实际上并不打印对象的类型,而是打印对象的__repr__
方法。您可以通过执行>>>print B.p.__repr__()
并查看其结果相同来检查:)
Python充满了间接和委托,这就是它如此灵活的原因。
希望这能澄清一点。
答案 1 :(得分:4)
那么,为什么?
B.p
和B.__dict__['p']
不是同一个对象吗?
没有。属性访问是神奇的;当按属性名访问用户定义的方法时,会返回绑定方法或未绑定方法(这在Python 3中更改;根本不再有未绑定方法;如果通过访问实例方法,则会获得常规函数class object);通过字典直接访问可以绕过这种魔力。
什么?!,为什么? unbound方法和instancemethod?,那些是一样的吗?为什么有两个不同的名字?
用户定义的方法属于instancemethod
类型,除非它是使用@classmethod
或@staticmethod
装饰器定义的。它可以是绑定的实例方法(当作为实例的属性访问时)或未绑定的方法(当作为类的属性访问时)。
(有关说明,请参阅http://docs.python.org/2/reference/datamodel.html的“用户定义的方法”部分。)
答案 2 :(得分:2)
显然他们不是。请阅读此文:https://wiki.python.org/moin/FromFunctionToMethod以获得更深入的解释。那么,为什么?不是B.p和B. dict ['p']是同一个对象吗?