Python 静态方法并不总是可调用的 [英] Python static method is not always callable

查看:79
本文介绍了Python 静态方法并不总是可调用的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 __dict__,我的@staticmethod 不是 callable.

Python 2.7.5(默认,2016 年 8 月 29 日,10:12:21)[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] 在 linux2输入帮助"、版权"、信用"或许可"以获取更多信息.>>>从 __future__ 导入(absolute_import、除法、print_function)>>>C类(对象):... @staticmethod...定义 foo():...对于名称,C.__dict__.items() 中的 val:...如果名称[:2] != '__':...打印(名称,可调用(val),类型(val))...>>>C.foo()foo False 

  • 这怎么可能?
  • 如何检查静态方法是否可调用?
<小时>

我在下面提供了一个更详细的例子:

脚本 test.py

from __future__ import (absolute_import, Division, print_function)C类(对象):@静态方法定义 foo():返回 42定义栏(自我):print('bar() 是否可以调用?', callable(C.bar))打印('foo()是否可调用?',可调用(C.foo))对于属性,C.__dict__.items() 中的值:如果属性 [:2] != '__':打印(属性,'\t',可调用(值),'\t',类型(值))c = C()c.bar()

python2 的结果

>python2.7 test.pybar() 可以调用吗?真的foo() 是可调用的吗?真的bar True <type 'function'>foo False 

python3 的结果相同

>python3.4 test.pybar() 可以调用吗?真的foo() 是可调用的吗?真的bar True foo False 

解决方案

这种行为的原因是描述符协议.C.foo 不会返回 staticmethod 而是一个普通函数,而 __dict__ 中的 'foo' 是一个 staticmethod(和 staticmethod 是一个描述符).

简而言之 C.foo 在这种情况下与 C.__dict__['foo'] 不同 - 而是 C.__dict__['foo'].__get__(C)(另请参阅 描述符上的数据模型):

<预><代码>>>>callable(C.__dict__['foo'].__get__(C))真的>>>类型(C.__dict__['foo'].__get__(C))功能>>>可调用(C.foo)真的>>>类型(C.foo)功能>>>C.foo 是 C.__dict__['foo'].__get__(C)真的

<小时>

在您的情况下,我会使用 getattr 检查可调用对象(知道描述符以及如何访问它们)而不是存储在 __dict__ 类中的值:

def bar(self):print('bar() 是否可以调用?', callable(C.bar))打印('foo()是否可调用?',可调用(C.foo))对于 C.__dict__.keys() 中的属性:如果属性 [:2] != '__':value = getattr(C, 属性)打印(属性,'\t',可调用(值),'\t',类型(值))

打印(在 python-3.x 上):

 bar() 是否可以调用?真的foo() 是可调用的吗?真的bar True foo True 

python-2.x 的类型不同,但是 callable 的结果是一样的:

 bar() 是否可以调用?真的foo() 是可调用的吗?真的bar True <type 'instancemethod'>foo True <type 'function'>

While parsing attributes using __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'>

  • How is this possible?
  • How to check if a static method is callable?

I provide below a more detailed example:

Script 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()

Result for python2

> python2.7 test.py
Is bar() callable? True
Is foo() callable? True
bar      True    <type 'function'>
foo      False   <type 'staticmethod'>

Same result for python3

> python3.4 test.py
Is bar() callable? True
Is foo() callable? True
bar      True    <class 'function'>
foo      False   <class 'staticmethod'>

解决方案

The reason for this behavior is the descriptor protocol. The C.foo won't return a staticmethod but a normal function while the 'foo' in __dict__ is a staticmethod (and staticmethod is a descriptor).

In short C.foo isn't the same as C.__dict__['foo'] in this case - but rather C.__dict__['foo'].__get__(C) (see also the section in the documentation of the 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


In your case I would check for callables using getattr (which knows about descriptors and how to access them) instead of what is stored as value in the 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))

Which prints (on python-3.x):

Is bar() callable? True
Is foo() callable? True
bar      True    <class 'function'>
foo      True    <class 'function'>

The types are different on python-2.x but the result of callable is the same:

Is bar() callable? True
Is foo() callable? True
bar      True    <type 'instancemethod'>
foo      True    <type 'function'>

这篇关于Python 静态方法并不总是可调用的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆