Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 类方法和类方法中定义的变量_Python_Class - Fatal编程技术网

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)
现在,您可以将其作为常规函数在类或实例上调用,而无需使用magic
self
方法:

>>> 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