staticmethod()做了什么魔术,所以静态方法总是在没有实例参数的情况下被调用?

Lon*_*ner 6 python static-methods python-3.x

我试图了解静态方法如何在内部工作.我知道如何使用@staticmethod装饰器,但我将避免在这篇文章中使用它,以深入了解静态方法的工作原理并提出我的问题.

从我了解的Python,如果有一类A,然后调用A.foo()调用foo()不带任何参数,而调用A().foo()调用foo()一个说法,其中一个说法是实例A()本身.

但是,在静态方法的情况下,似乎总是foo()在没有参数的情况下调用它是否称为A.foo()A().foo().

证明如下:

>>> class A:
...     x = 'hi'
...     def foo():
...         print('hello, world')
...     bar = staticmethod(foo)
...
>>> A.bar()
hello, world
>>> A().bar()
hello, world
>>> A.bar
<function A.foo at 0x00000000005927B8>
>>> A().bar
<function A.foo at 0x00000000005927B8>
>>> A.bar(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes 0 positional arguments but 1 was given
>>> A().bar(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes 0 positional arguments but 1 was given
Run Code Online (Sandbox Code Playgroud)

所以我是否正确地得出结论,该staticmethod()函数具有一些魔力,foo()总是用0参数调用?

如果我staticmethod()在自己的Python代码中定义自己的代码,我该怎么做?甚至可以从我们自己的Python代码中定义这样的方法,还是只能将这样的函数定义为内置函数?

Bak*_*riu 9

它被实现为描述符.例如:

In [1]: class MyStaticMethod(object):
   ...:     def __init__(self, func):
   ...:         self._func = func
   ...:     def __get__(self, inst, cls):
   ...:         return self._func
   ...:     

In [2]: class A(object):
   ...:     @MyStaticMethod
   ...:     def foo():
   ...:         print('Hello, World!')
   ...:         

In [3]: A.foo()
Hello, World!

In [4]: A().foo()
Hello, World!
Run Code Online (Sandbox Code Playgroud)

以同样的方式定义classmethod,只需传递cls给原始函数:

In [5]: from functools import partial
   ...: 
   ...: class MyClassMethod(object):
   ...:     def __init__(self, func):
   ...:         self._func = func
   ...:     def __get__(self, inst, cls):
   ...:         return partial(self._func, cls)

In [6]: class A(object):
   ...:     @MyClassMethod
   ...:     def foo(cls):
   ...:         print('In class: {}'.format(cls))
   ...:         

In [7]: A.foo()
In class: <class '__main__.A'>

In [8]: A().foo()
In class: <class '__main__.A'>
Run Code Online (Sandbox Code Playgroud)


use*_*ica 5

方法(包括实例,静态和类方法)通过描述符协议工作.如果类dict中的对象实现了__get__特殊方法:

class Descriptor(object):
    def __get__(self, instance, klass):
        return instance, klass

class HasDescriptor(object):
    descriptor = Descriptor()

x = HasDescriptor()
Run Code Online (Sandbox Code Playgroud)

然后以下属性访问:

x.descriptor
HasDescriptor.descriptor
Run Code Online (Sandbox Code Playgroud)

将调用描述符的__get__方法来计算它们的值,如下所示:

descriptor.__get__(x, HasDescriptor)
descriptor.__get__(None, HasDescriptor)
Run Code Online (Sandbox Code Playgroud)

函数,staticmethod以及classmethod所有实现__get__方法访问的工具.你也可以做到的:

class MyStaticMethod(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, instance, klass):
        return self.f
Run Code Online (Sandbox Code Playgroud)

也有__set____delete__,使您可以分别控制设置和删除属性,方法.方法不使用这些,但property确实如此.