下面的类方法有什么区别?
是不是一个是静态的,另一个不是?
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()
下面的类方法有什么区别?
是不是一个是静态的,另一个不是?
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()
当前回答
Method_two不能工作,因为你定义了一个成员函数,但没有告诉它这个函数是什么成员。如果你执行最后一行,你会得到:
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
如果你为一个类定义成员函数,第一个参数必须总是'self'。
其他回答
对method_two的调用将抛出一个异常,表示不接受self参数,Python运行时将自动传递给它。
如果你想在Python类中创建一个静态方法,用staticmethod装饰器来装饰它。
Class Test(Object):
@staticmethod
def method_two():
print "Called method_two"
Test.method_two()
在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 "<stdin>", line 1, in <module>
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"
装饰器告诉内置的默认元类类型(类的类,参见这个问题)不要为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
>>> 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 "<stdin>", line 1, in <module>
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
上面Armin Ronacher的准确解释,并对他的答案进行了扩展,以便像我这样的初学者能够很好地理解:
类中定义的方法的区别,无论是静态方法还是实例方法(还有另一种类型-类方法-这里不讨论,所以跳过它),在于它们是否以某种方式绑定到类实例。例如,说明该方法是否在运行时接收到对类实例的引用
class C:
a = []
def foo(self):
pass
C # this is the class object
C.a # is a list object (class property object)
C.foo # is a function object (class property object)
c = C()
c # this is the class instance
类对象的__dict__字典属性保存了对类对象的所有属性和方法的引用,因此
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
foo方法可以像上面那样访问。这里需要注意的一点是,python中的所有东西都是对象,因此上面字典中的引用本身就指向其他对象。让我称它们为类属性对象——或者在我的回答范围内简称为CPO。
如果CPO是一个描述符,则python解释器调用CPO的__get__()方法来访问它包含的值。
为了确定CPO是否是描述符,python解释器检查它是否实现了描述符协议。实现描述符协议需要实现3个方法
def __get__(self, instance, owner)
def __set__(self, instance, value)
def __delete__(self, instance)
如。
>>> C.__dict__['foo'].__get__(c, C)
在哪里
self is the CPO (it could be an instance of list, str, function etc) and is supplied by the runtime instance is the instance of the class where this CPO is defined (the object 'c' above) and needs to be explicity supplied by us owner is the class where this CPO is defined(the class object 'C' above) and needs to be supplied by us. However this is because we are calling it on the CPO. when we call it on the instance, we dont need to supply this since the runtime can supply the instance or its class(polymorphism) value is the intended value for the CPO and needs to be supplied by us
并非所有CPO都是描述符。例如
>>> C.__dict__['foo'].__get__(None, C)
<function C.foo at 0x10a72f510>
>>> C.__dict__['a'].__get__(None, C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__get__'
这是因为列表类没有实现描述符协议。
因此c.foo(self)中的self参数是必需的,因为它的方法签名实际上是这个C.__dict__['foo']。__get__(c, c)(如上所述,c不需要,因为它可以被找到或多态) 这也是为什么如果你不传递所需的实例参数,你会得到一个TypeError。
如果您注意到该方法仍然是通过类对象C引用的,并且与类实例的绑定是通过将实例对象形式的上下文传递给该函数来实现的。
这非常棒,因为如果你选择不保留上下文或不绑定到实例,所需要的只是编写一个类来包装描述符CPO并重写其__get__()方法以不需要上下文。 这个新类就是我们所说的装饰器,它通过关键字@staticmethod应用
class C(object):
@staticmethod
def foo():
pass
在新包装的CPO foo中缺少上下文不会抛出错误,可以通过以下方式验证:
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
静态方法的用例更多的是命名空间和代码可维护性(将其从类中取出并使其在整个模块中可用等)。
如果可能的话,写静态方法比写实例方法更好,当然除非你需要上下文化这些方法(比如访问实例变量,类变量等)。一个原因是通过不保留不必要的对象引用来简化垃圾收集。
The second one won't work because when you call it like that python internally tries to call it with the a_test instance as the first argument, but your method_two doesn't accept any arguments, so it wont work, you'll get a runtime error. If you want the equivalent of a static method you can use a class method. There's much less need for class methods in Python than static methods in languages like Java or C#. Most often the best solution is to use a method in the module, outside a class definition, those work more efficiently than class methods.