Python 静态方法并不总是可调用的
Python static method is not always callable
使用 __dict__
, my @staticmethod
is not callable
.
解析属性时
Python 2.7.5 (default, Aug 29 2016, 10:12:21)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from __future__ import (absolute_import, division, print_function)
>>> class C(object):
... @staticmethod
... def foo():
... for name, val in C.__dict__.items():
... if name[:2] != '__':
... print(name, callable(val), type(val))
...
>>> C.foo()
foo False <type 'staticmethod'>
- 这怎么可能?
- 如何检查静态方法是否可调用?
我在下面提供一个更详细的例子:
脚本test.py
from __future__ import (absolute_import, division, print_function)
class C(object):
@staticmethod
def foo():
return 42
def bar(self):
print('Is bar() callable?', callable(C.bar))
print('Is foo() callable?', callable(C.foo))
for attribute, value in C.__dict__.items():
if attribute[:2] != '__':
print(attribute, '\t', callable(value), '\t', type(value))
c = C()
c.bar()
python2
的结果
> python2.7 test.py
Is bar() callable? True
Is foo() callable? True
bar True <type 'function'>
foo False <type 'staticmethod'>
python3
的结果相同
> python3.4 test.py
Is bar() callable? True
Is foo() callable? True
bar True <class 'function'>
foo False <class 'staticmethod'>
此行为的原因是描述符协议。 C.foo
不会 return 一个 staticmethod
而是一个正常的函数,而 __dict__
中的 'foo'
是一个 staticmethod
(和 staticmethod
是一个描述符)。
简而言之,在这种情况下,C.foo
与 C.__dict__['foo']
不同 - 而是 C.__dict__['foo'].__get__(C)
(另请参阅 Data model on descriptors 文档中的部分) :
>>> callable(C.__dict__['foo'].__get__(C))
True
>>> type(C.__dict__['foo'].__get__(C))
function
>>> callable(C.foo)
True
>>> type(C.foo)
function
>>> C.foo is C.__dict__['foo'].__get__(C)
True
在你的情况下,我会使用 getattr
(它知道描述符以及如何访问它们)而不是 class __dict__
中存储的值来检查可调用项:
def bar(self):
print('Is bar() callable?', callable(C.bar))
print('Is foo() callable?', callable(C.foo))
for attribute in C.__dict__.keys():
if attribute[:2] != '__':
value = getattr(C, attribute)
print(attribute, '\t', callable(value), '\t', type(value))
打印(在 python-3.x):
Is bar() callable? True
Is foo() callable? True
bar True <class 'function'>
foo True <class 'function'>
python-2.x 的类型不同,但 callable
的结果相同:
Is bar() callable? True
Is foo() callable? True
bar True <type 'instancemethod'>
foo True <type 'function'>
您无法检查 staticmethod
对象是否可调用。这在 Issue 20309 -- Not all method descriptors are callable 中的跟踪器上进行了讨论,并在 "not a bug" 中结束。
简而言之,没有理由为 staticmethod 对象实现 __call__
。内置 callable
无法知道 staticmethod
对象本质上是 "holds" 可调用对象。
虽然您可以实施它(对于 staticmethod
s 和 classmethod
s),但如前所述,它没有真正的激励用例,这将是一种维护负担。
对于您的情况,您可以使用 getattr(C, name)
来查找名为 name
的对象;这相当于执行 C.<name>
。 getattr
,在找到 staticmethod 对象后,将调用它的 __get__
来取回它管理的可调用对象。然后你可以在上面使用 callable
。
可以在文档中找到有关描述符的入门读物,请查看 Descriptor HOWTO。
使用 __dict__
, my @staticmethod
is not callable
.
Python 2.7.5 (default, Aug 29 2016, 10:12:21)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from __future__ import (absolute_import, division, print_function)
>>> class C(object):
... @staticmethod
... def foo():
... for name, val in C.__dict__.items():
... if name[:2] != '__':
... print(name, callable(val), type(val))
...
>>> C.foo()
foo False <type 'staticmethod'>
- 这怎么可能?
- 如何检查静态方法是否可调用?
我在下面提供一个更详细的例子:
脚本test.py
from __future__ import (absolute_import, division, print_function)
class C(object):
@staticmethod
def foo():
return 42
def bar(self):
print('Is bar() callable?', callable(C.bar))
print('Is foo() callable?', callable(C.foo))
for attribute, value in C.__dict__.items():
if attribute[:2] != '__':
print(attribute, '\t', callable(value), '\t', type(value))
c = C()
c.bar()
python2
的结果> python2.7 test.py
Is bar() callable? True
Is foo() callable? True
bar True <type 'function'>
foo False <type 'staticmethod'>
python3
的结果相同> python3.4 test.py
Is bar() callable? True
Is foo() callable? True
bar True <class 'function'>
foo False <class 'staticmethod'>
此行为的原因是描述符协议。 C.foo
不会 return 一个 staticmethod
而是一个正常的函数,而 __dict__
中的 'foo'
是一个 staticmethod
(和 staticmethod
是一个描述符)。
简而言之,在这种情况下,C.foo
与 C.__dict__['foo']
不同 - 而是 C.__dict__['foo'].__get__(C)
(另请参阅 Data model on descriptors 文档中的部分) :
>>> callable(C.__dict__['foo'].__get__(C))
True
>>> type(C.__dict__['foo'].__get__(C))
function
>>> callable(C.foo)
True
>>> type(C.foo)
function
>>> C.foo is C.__dict__['foo'].__get__(C)
True
在你的情况下,我会使用 getattr
(它知道描述符以及如何访问它们)而不是 class __dict__
中存储的值来检查可调用项:
def bar(self):
print('Is bar() callable?', callable(C.bar))
print('Is foo() callable?', callable(C.foo))
for attribute in C.__dict__.keys():
if attribute[:2] != '__':
value = getattr(C, attribute)
print(attribute, '\t', callable(value), '\t', type(value))
打印(在 python-3.x):
Is bar() callable? True
Is foo() callable? True
bar True <class 'function'>
foo True <class 'function'>
python-2.x 的类型不同,但 callable
的结果相同:
Is bar() callable? True
Is foo() callable? True
bar True <type 'instancemethod'>
foo True <type 'function'>
您无法检查 staticmethod
对象是否可调用。这在 Issue 20309 -- Not all method descriptors are callable 中的跟踪器上进行了讨论,并在 "not a bug" 中结束。
简而言之,没有理由为 staticmethod 对象实现 __call__
。内置 callable
无法知道 staticmethod
对象本质上是 "holds" 可调用对象。
虽然您可以实施它(对于 staticmethod
s 和 classmethod
s),但如前所述,它没有真正的激励用例,这将是一种维护负担。
对于您的情况,您可以使用 getattr(C, name)
来查找名为 name
的对象;这相当于执行 C.<name>
。 getattr
,在找到 staticmethod 对象后,将调用它的 __get__
来取回它管理的可调用对象。然后你可以在上面使用 callable
。
可以在文档中找到有关描述符的入门读物,请查看 Descriptor HOWTO。