当前位置:  开发笔记 > 编程语言 > 正文

Python中的类方法差异:绑定,未绑定和静态

如何解决《Python中的类方法差异:绑定,未绑定和静态》经验,为你挑选了4个好方法。

以下类方法有什么区别?

是一个是静态而另一个不是?

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)

希望能够解释它.



1> Torsten Mare..:

在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中,不推荐使用未绑定的方法.相反,只有一个功能.
我支持这个答案,它优于我的.干得好Torsten :)

2> Armin Ronach..:

一旦理解了描述符系统的基础知识,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)

希望能够解释它.


*`staticmethod`装饰器包装你的类(...)*这个短语有点误导,因为被包装的类是**方法`foo`的类**而不是`foo`的类被定义为.

3> Justin Polie..:

当您调用类成员时,Python会自动使用对象的引用作为第一个参数.变量self实际上没有任何意义,它只是一种编码约定.gargaloo如果你愿意,你可以打电话给它.也就是说,调用method_two会引发一个TypeError,因为Python会自动尝试将参数(对其父对象的引用)传递给定义为没有参数的方法.

要实际使其工作,您可以将其附加到您的类定义:

method_two = staticmethod(method_two)

或者你可以使用@staticmethod 函数装饰器.


你的意思是"@staticmethod函数装饰器语法".

4> kzh..:
>>> 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


`Class.instance_method()#该类不能使用它可以使用的实例方法.只需手动传递实例:`Class.instance_method(a)`
推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有