Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.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_Static Methods - Fatal编程技术网

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