我试图了解静态方法如何在内部工作。我知道如何使用@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
所以我正确地得出结论staticmethod()
函数有一些魔力使得foo()
总是用0参数调用?
如果我在自己的Python代码中定义自己的staticmethod()
,我该怎么做?甚至可以从我们自己的Python代码中定义这样的方法,还是只能将这样的函数定义为内置函数?
答案 0 :(得分:9)
它是以descriptor实现的。例如:
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!
以同样的方式定义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'>
答案 1 :(得分:5)
方法(包括实例,静态和类方法)通过descriptor protocol完成。如果类dict中的对象实现了__get__
特殊方法:
class Descriptor(object):
def __get__(self, instance, klass):
return instance, klass
class HasDescriptor(object):
descriptor = Descriptor()
x = HasDescriptor()
然后访问以下属性:
x.descriptor
HasDescriptor.descriptor
将调用描述符的__get__
方法来计算它们的值,如下所示:
descriptor.__get__(x, HasDescriptor)
descriptor.__get__(None, HasDescriptor)
函数,staticmethod
和classmethod
都实现__get__
以使方法访问起作用。你也可以这样做:
class MyStaticMethod(object):
def __init__(self, f):
self.f = f
def __get__(self, instance, klass):
return self.f
还有__set__
和__delete__
方法,分别允许您控制设置和删除属性。方法不使用这些,但property
会这样做。