以下类方法有什么区别?
是一个是静态而另一个不是?
class Test(object): def method_one(self): print "Called method_one" def method_two(): print "Called method_two" a_test = Test() a_test.method_one() a_test.method_two()
Torsten Mare.. 407
在Python中,绑定和未绑定方法之间存在区别.
基本上,调用成员函数(如method_one
),绑定函数
a_test.method_one()
被翻译成
Test.method_one(a_test)
即对未绑定方法的调用.因此,对您的版本的调用method_two
将失败TypeError
>>> a_test = Test() >>> a_test.method_two() Traceback (most recent call last): File "", line 1, in TypeError: method_two() takes no arguments (1 given)
您可以使用装饰器更改方法的行为
class Test(object): def method_one(self): print "Called method_one" @staticmethod def method_two(): print "Called method two"
装饰器告诉内置的默认元类type
(类的类,参见这个问题)不创建绑定方法method_two
.
现在,您可以直接在实例或类上调用静态方法:
>>> a_test = Test() >>> a_test.method_one() Called method_one >>> a_test.method_two() Called method_two >>> Test.method_two() Called method_two
在python 3中,不推荐使用未绑定的方法.相反,只有一个功能. (23认同)
我支持这个答案,它优于我的.干得好Torsten :) (17认同)
Armin Ronach.. 189
一旦理解了描述符系统的基础知识,Python中的方法就变得非常非常简单.想象一下以下课程:
class C(object): def foo(self): pass
现在让我们看一下shell中的那个类:
>>> C.foo>>> C.__dict__['foo']
正如您所看到的,如果您访问foo
该类的属性,则会返回一个未绑定的方法,但是在类存储(dict)中有一个函数.为什么?这样做的原因是你的类的类实现了一个__getattribute__
解析描述符.听起来很复杂,但事实并非如此. C.foo
在这种特殊情况下大致相当于此代码:
>>> C.__dict__['foo'].__get__(None, C)
那是因为函数有一个__get__
使它们成为描述符的方法.如果你有一个类的实例几乎相同,那None
就是类实例:
>>> c = C() >>> C.__dict__['foo'].__get__(c, C)>
现在为什么Python会这样做?因为方法对象将函数的第一个参数绑定到类的实例.这就是自我的来源.现在,有时你不希望你的类将函数作为一个方法,这就是staticmethod
发挥作用的地方:
class C(object): @staticmethod def foo(): pass
该staticmethod
装饰包装类,并实现虚拟__get__
返回的包裹功能功能,而不是作为一种方法:
>>> C.__dict__['foo'].__get__(None, C)
希望能够解释它.
在Python中,绑定和未绑定方法之间存在区别.
基本上,调用成员函数(如method_one
),绑定函数
a_test.method_one()
被翻译成
Test.method_one(a_test)
即对未绑定方法的调用.因此,对您的版本的调用method_two
将失败TypeError
>>> a_test = Test() >>> a_test.method_two() Traceback (most recent call last): File "", line 1, in TypeError: method_two() takes no arguments (1 given)
您可以使用装饰器更改方法的行为
class Test(object): def method_one(self): print "Called method_one" @staticmethod def method_two(): print "Called method two"
装饰器告诉内置的默认元类type
(类的类,参见这个问题)不创建绑定方法method_two
.
现在,您可以直接在实例或类上调用静态方法:
>>> a_test = Test() >>> a_test.method_one() Called method_one >>> a_test.method_two() Called method_two >>> Test.method_two() Called method_two
一旦理解了描述符系统的基础知识,Python中的方法就变得非常非常简单.想象一下以下课程:
class C(object): def foo(self): pass
现在让我们看一下shell中的那个类:
>>> C.foo>>> C.__dict__['foo']
正如您所看到的,如果您访问foo
该类的属性,则会返回一个未绑定的方法,但是在类存储(dict)中有一个函数.为什么?这样做的原因是你的类的类实现了一个__getattribute__
解析描述符.听起来很复杂,但事实并非如此. C.foo
在这种特殊情况下大致相当于此代码:
>>> C.__dict__['foo'].__get__(None, C)
那是因为函数有一个__get__
使它们成为描述符的方法.如果你有一个类的实例几乎相同,那None
就是类实例:
>>> c = C() >>> C.__dict__['foo'].__get__(c, C)>
现在为什么Python会这样做?因为方法对象将函数的第一个参数绑定到类的实例.这就是自我的来源.现在,有时你不希望你的类将函数作为一个方法,这就是staticmethod
发挥作用的地方:
class C(object): @staticmethod def foo(): pass
该staticmethod
装饰包装类,并实现虚拟__get__
返回的包裹功能功能,而不是作为一种方法:
>>> C.__dict__['foo'].__get__(None, C)
希望能够解释它.
当您调用类成员时,Python会自动使用对象的引用作为第一个参数.变量self
实际上没有任何意义,它只是一种编码约定.gargaloo
如果你愿意,你可以打电话给它.也就是说,调用method_two
会引发一个TypeError
,因为Python会自动尝试将参数(对其父对象的引用)传递给定义为没有参数的方法.
要实际使其工作,您可以将其附加到您的类定义:
method_two = staticmethod(method_two)
或者你可以使用@staticmethod
函数装饰器.
>>> class Class(object): ... def __init__(self): ... self.i = 0 ... def instance_method(self): ... self.i += 1 ... print self.i ... c = 0 ... @classmethod ... def class_method(cls): ... cls.c += 1 ... print cls.c ... @staticmethod ... def static_method(s): ... s += 1 ... print s ... >>> a = Class() >>> a.class_method() 1 >>> Class.class_method() # The class shares this value across instances 2 >>> a.instance_method() 1 >>> Class.instance_method() # The class cannot use an instance method Traceback (most recent call last): File "", line 1, in TypeError: unbound method instance_method() must be called with Class instance as first argument (got nothing instead) >>> Class.instance_method(a) 2 >>> b = 0 >>> a.static_method(b) 1 >>> a.static_method(a.c) # Static method does not have direct access to >>> # class or instance properties. 3 >>> Class.c # a.c above was passed by value and not by reference. 2 >>> a.c 2 >>> a.c = 5 # The connection between the instance >>> Class.c # and its class is weak as seen here. 2 >>> Class.class_method() 3 >>> a.c 5