Python static method is not always callable

后端 未结 2 845
长情又很酷
长情又很酷 2021-02-08 12:29

While parsing attributes using __dict__, my @staticmethod is not callable.

Python 2.7.5 (default, Aug 29 2016, 10:12:21)         


        
相关标签:
2条回答
  • 2021-02-08 12:45

    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'>
    
    0 讨论(0)
  • 2021-02-08 12:54

    You can't check if a staticmethod object is callable or not. This was discussed on the tracker in Issue 20309 -- Not all method descriptors are callable and closed as "not a bug".

    In short, there's been no rationale for implementing __call__ for staticmethod objects. The built-in callable has no way to know that the staticmethod object is something that essentially "holds" a callable.

    Though you could implement it (for staticmethods and classmethods), it would be a maintenance burden that, as previously mentioned, has no real motivating use-cases.


    For your case, you can use getattr(C, name) to perform a look-up for the object named name; this is equivalent to performing C.<name>. getattr, after finding the staticmethod object, will invoke its __get__ to get back the callable it's managing. You can then use callable on that.

    A nice primer on descriptors can be found in the docs, take a look at Descriptor HOWTO.

    0 讨论(0)
提交回复
热议问题