代码之家  ›  专栏  ›  技术社区  ›  oHo Denis Tulskiy

Python静态方法并不总是可调用的

  •  12
  • oHo Denis Tulskiy  · 技术社区  · 7 年前

    __dict__ 我的 @staticmethod 不是 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.4 test.py
    Is bar() callable? True
    Is foo() callable? True
    bar      True    <class 'function'>
    foo      False   <class 'staticmethod'>
    
    2 回复  |  直到 7 年前
        1
  •  12
  •   MSeifert    7 年前

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

    简言之 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 __迪克特__

    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'>
    
        2
  •  4
  •   Dimitris Fasarakis Hilliard    7 年前

    你不能检查 staticmethod Issue 20309 -- Not all method descriptors are callable 并以“不是bug”结束。

    简而言之,没有理由实施 __call__ 对于staticmethod对象。内置的 callable 没有办法知道 静力学方法

    尽管你可以实现它(对于 s和 classmethod s) 如前所述,这将是一个维护负担,没有真正的激励用例。


    对于您的情况,您可以使用 getattr(C, name) name ; 这相当于执行 C.<name> . getattr __get__ 它正在管理收回赎回权。然后您可以使用 可赎回 在那上面。

    在文档中可以找到一个很好的描述符入门,请看 Descriptor HOWTO