Python中的类方法差异:绑定、未绑定和静态
以下类方法之间有什么区别 一个是静态的,另一个不是Python中的类方法差异:绑定、未绑定和静态,python,static-methods,Python,Static Methods,以下类方法之间有什么区别 一个是静态的,另一个不是 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() 调用类成员时,Python会自动使用对对象的引用作为第一个参数。变量self实际上
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()
调用类成员时,Python会自动使用对对象的引用作为第一个参数。变量
self
实际上没有任何意义,它只是一种编码约定。如果你想的话,你可以叫它gargaloo
。也就是说,调用method\u two
会引发TypeError
,因为Python会自动尝试将参数(对其父对象的引用)传递给定义为没有参数的方法
要使其真正起作用,可以将其附加到类定义中:
method_two = staticmethod(method_two)
或者您可以使用
@staticmethod
方法,因为您正在定义一个成员函数,但没有告诉它该函数的成员是什么,所以方法2不起作用。如果执行最后一行,您将得到:
>>> a_test.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
>>一个测试方法二()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:method_two()不接受任何参数(给定1个)
如果要为类定义成员函数,则第一个参数必须始终为“self”。对方法2的调用将抛出一个不接受self参数的异常,Python运行时将自动传递该参数 如果要在Python类中创建静态方法,请使用
staticmethoddecorator
对其进行修饰
Class Test(Object):
@staticmethod
def method_two():
print "Called method_two"
Test.method_two()
在Python中,绑定方法和未绑定方法之间存在区别 基本上,对成员函数(如
method\u one
)的调用是一个绑定函数
a_test.method_one()
翻译成
Test.method_one(a_test)
i、 e.对未绑定方法的调用。因此,调用您的method\u 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)
装饰器告诉内置默认元类类型
(类的类,cf.)不要为方法二创建绑定方法
现在,您可以在实例或类上直接调用静态方法:
>>> a_test = Test()
>>> a_test.method_one()
Called method_one
>>> a_test.method_two()
Called method_two
>>> Test.method_two()
Called method_two
这是一个错误
首先,第一行应该是这样的(注意大写字母)
无论何时调用一个类的方法,它都会将自身作为第一个参数(因此命名为self),而方法_two会给出此错误
>>> a.method_two()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method_two() takes no arguments (1 given)
>a.方法二()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:method_two()不接受任何参数(给定1个)
第二个参数不起作用,因为当您像python内部那样调用它时,会尝试使用a_测试实例作为第一个参数来调用它,但您的方法2不接受任何参数,因此它不起作用,您将得到一个运行时错误。
如果您想要与静态方法等效,可以使用类方法。
与Java或C#等语言中的静态方法相比,Python中对类方法的需求要少得多。大多数情况下,最好的解决方案是在模块中使用类定义之外的方法,这些方法比类方法更有效。一旦您了解了描述符系统的基本知识,Python中的方法就非常简单了。想象一下下面的类:
class C(object):
def foo(self):
pass
现在让我们看看shell中的类:
>>> C.foo
<unbound method C.foo>
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
这是因为函数有一个\uuuuu get\uuuu
方法,使它们成为描述符。如果您有一个类的实例,它几乎是相同的,只是None
是类实例:
>>> c = C()
>>> C.__dict__['foo'].__get__(c, C)
<bound method C.foo of <__main__.C object at 0x17bd4d0>>
staticmethod
装饰器包装您的类并实现一个虚拟的\uuuu get\uuuu
,它将包装的函数作为函数而不是方法返回:
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
>>C.uuu dict_uuuuuu['foo'].uuuu get_uuuu(无,C)
希望能解释清楚。>>类(对象):
>>> 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
... 定义初始化(自):
... self.i=0
... def实例_方法(自身):
... self.i+=1
... 打印自我
... c=0
... @类方法
... def分级方法(cls):
... cls.c+=1
... 打印cls.c
... @静力学方法
... def静态_方法:
... s+=1
... 印刷品
...
>>>a=类()
>>>a.类_方法()
1.
>>>Class.Class_method()#该类在实例之间共享此值
2.
>>>a.实例_方法()
1.
>>>Class.instance_method()#该类不能使用实例方法
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:必须以类实例作为第一个参数调用未绑定的方法实例\u method()(但没有得到任何结果)
>>>Class.instance_方法(a)
2.
>>>b=0
>>>a.静态法(b)
1.
>>>a.static_方法(a.c)#static方法无法直接访问
>>>#类或实例属性。
3.
>>>上面的Class.c#a.c是通过值传递的,而不是通过引用传递的。
2.
>>>交流
2.
>>>a.c=5#实例之间的连接
>>>Class.c#和它的类是弱的,如图所示。
2.
>>>Class.Class_方法()
3.
>>>交流
5.
请阅读Guido的这些文档,清楚地解释了未绑定、绑定方法是如何产生的。上面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
class对象的\uuuu dict\uuuu
dictionary属性包含对class对象的所有属性和方法的引用,因此
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
例如
>>> C.__dict__['foo'].__get__(c, C)
在哪里
self
是CPO(可以是list、str、function等的实例),由运行时提供
instance
是定义此CPO的类的实例(上面的对象“c”),需要由我们明确提供
owner
是定义此CPO的类(上面的类对象“C”),并且
>>> 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
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
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
def __get__(self, instance, owner)
def __set__(self, instance, value)
def __delete__(self, instance)
>>> C.__dict__['foo'].__get__(c, C)
>>> 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__'
class C(object):
@staticmethod
def foo():
pass
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
class MyClass:
def some_method(self):
return self # For the sake of the example
>>> MyClass().some_method()
<__main__.MyClass object at 0x10e8e43a0># This can also be written as:>>> obj = MyClass()
>>> obj.some_method()
<__main__.MyClass object at 0x10ea12bb0>
# Bound method call:
>>> obj.some_method(10)
TypeError: some_method() takes 1 positional argument but 2 were given
# WHY IT DIDN'T WORK?
# obj.some_method(10) bound call translated as
# MyClass.some_method(obj, 10) unbound method and it takes 2
# arguments now instead of 1
# ----- USING THE UNBOUND METHOD ------
>>> MyClass.some_method(10)
10
class MyClass:
def some_method(self):
return self
@staticmethod
def some_static_method(number):
return number
>>> MyClass.some_static_method(10) # without an instance
10
>>> MyClass().some_static_method(10) # Calling through an instance
10