Python 类方法和类方法中定义的变量
有关以下代码:Python 类方法和类方法中定义的变量,python,class,Python,Class,有关以下代码: import os.path class Test: @classmethod def foo(cls): cls.exist = os.path.exists print type(cls.exist) print type(os.path.exists) def main(): Test.foo() 我得到的输出为: <type 'instancemethod'> <type 'functi
import os.path
class Test:
@classmethod
def foo(cls):
cls.exist = os.path.exists
print type(cls.exist)
print type(os.path.exists)
def main():
Test.foo()
我得到的输出为:
<type 'instancemethod'>
<type 'function'>
我只是将函数os.path.exist分配给类变量cls.exist。
但是当我打印这两个变量时,我得到一个作为实例方法,另一个作为函数。
为什么? 您可以将其指定为类变量,但它绑定到类:
Traceback (most recent call last):
File "<stdin>", line 12, in <module>
TypeError: unbound method exists() must be called with Test instance as first argument (got str instance instead)
cls.exist = staticmethod(os.path.exists)
现在,两者都属于同一类型:
<type 'function'>
<type 'function'>
首先,直观的解释: 将函数分配给类时,它将转换为未绑定的方法 未绑定方法是一种神奇的东西,它为类的每个实例创建绑定方法 绑定方法是一种神奇的东西,它绑定了特殊的
self
参数
(这在3.x中略有不同,因为没有未绑定的方法;函数本身是神奇的东西,可以为类的每个实例创建一个绑定方法。但您显然是在问2.x。)
因此:
现在您可以调用c.foo()
,并且self
参数将自动填入c
。但是没有参数就不能调用C.foo()
,就像没有参数就不能调用foo()
>>> c.foo()
<__main__.C object at 0x108df7e50>
>>> C.foo()
TypeError: unbound method foo() must be called with C instance as first argument (got nothing instead)
>>> foo()
TypeError: foo() takes exactly 1 argument (0 given)
如果查看函数、未绑定方法和绑定方法,它们很容易区分:
>>> foo, C.foo, c.foo
(<function __main__.foo>, <unbound method C.foo>, <bound method C.foo of <__main__.C object at 0x108df7e50>>)
>>> type(foo), type(C.foo), type(c.foo)
(function, instancemethod, instancemethod)
现在,您可以将其作为常规函数在类或实例上调用,而无需使用magicself
方法:
>>> C.bar(1)
1
>>> c.bar(1)
1
>>> bar(1)
TypeError: 'staticmethod' object is not callable
但这种直观的解释并不是真的。它总会引导你找到正确的答案,但这不是事情真正的运作方式 要真正理解这一点,您需要了解如何工作 当您将一个函数作为属性分配给一个类时,不会发生任何神奇的事情。存储在类字典中的只是普通的旧函数:
>>> C.__dict__['foo']
<function __main__.foo>
真正的神奇发生在查找时。无论何时查找任何属性(方法或其他),解释器不仅从字典中返回对象,还调用该对象的\uuuu get\uuuu
方法,传递实例(或None
,如果对类对象调用)和类
普通函数有一个\uuuuu get\uuuu
方法,该方法根据需要生成绑定或未绑定的方法:
>>> C.__dict__['foo'].__get__(None, C)
<unbound method C.foo>
>>> C.__dict__['foo'].__get__(None, C) == C.foo
True
>>> C.__dict__['foo'].__get__(c, C)
<bound method C.foo of <__main__.C object at 0x108df7e50>>
>>> C.__dict__['foo'].__get__(c, C) == c.foo
True
现在,您可能可以猜出staticmethod
是什么样子:它有一个\uu get\uu
方法,它只返回原始函数,不管您传递它什么
处理可设置的数据属性等要复杂一点,但实际上,这几乎就是全部,如果您非常了解这一点,那么您就非常了解Python中的所有魔力。您可以自己构建staticmethod
、classmethod
和property
,从头开始构建类等等。这是对我答案中“直观但不真实”部分的更好(而且更短!)解释。而且,即使这不是真的,您也可以编写代码,就好像它是真的一样,并且可以正常工作。
>>> bar = staticmethod(foo)
>>> C.bar = staticmethod(foo)
>>> c = C()
>>> bar, C.bar, c.bar
(<staticmethod at 0x109e990f8>, <function __main__.foo>, <function __main__.foo>)
>>> C.bar(1)
1
>>> c.bar(1)
1
>>> bar(1)
TypeError: 'staticmethod' object is not callable
>>> C.__dict__['foo']
<function __main__.foo>
>>> c.__dict__['foo']
KeyError: 'foo'
>>> C.__dict__['foo'].__get__(None, C)
<unbound method C.foo>
>>> C.__dict__['foo'].__get__(None, C) == C.foo
True
>>> C.__dict__['foo'].__get__(c, C)
<bound method C.foo of <__main__.C object at 0x108df7e50>>
>>> C.__dict__['foo'].__get__(c, C) == c.foo
True
>>> types.MethodType(foo, None, C) == C.foo
True
>>> types.MethodType(foo, c, C) == c.foo
True