Python: check if method is static

前端 未结 5 1133
梦谈多话
梦谈多话 2020-12-06 16:48

assume following class definition:

class A:
  def f(self):
    return \'this is f\'

  @staticmethod
  def g():
    return \'this is g\'

a = A() 

相关标签:
5条回答
  • 2020-12-06 16:56

    Lets experiment a bit:

    >>> import types
    >>> class A:
    ...   def f(self):
    ...     return 'this is f'
    ...   @staticmethod
    ...   def g():
    ...     return 'this is g'
    ...
    >>> a = A()
    >>> a.f
    <bound method A.f of <__main__.A instance at 0x800f21320>>
    >>> a.g
    <function g at 0x800eb28c0>
    >>> isinstance(a.g, types.FunctionType)
    True
    >>> isinstance(a.f, types.FunctionType)
    False
    

    So it looks like you can use types.FunctionType to distinguish static methods.

    0 讨论(0)
  • 2020-12-06 16:57

    To supplement the answers here, in Python 3 the best way is like so:

    import inspect
    
    class Test:
        @staticmethod
        def test(): pass
    
    isstatic = isinstance(inspect.getattr_static(Test, "test"), staticmethod)
    

    We use getattr_static rather than getattr, since getattr will retrieve the bound method or function, not the staticmethod class object. You can do a similar check for classmethod types and property's (e.g. attributes defined using the @property decorator)

    Note that even though it is a staticmethod, don't assume it was defined inside the class. The method source may have originated from another class. To get the true source, you can look at the underlying function's qualified name and module. For example:

    class A:
        @staticmethod:
        def test(): pass
    
    class B: pass
    B.test = inspect.getattr_static(A, "test")
    
    print("true source: ", B.test.__qualname__)
    
    

    Technically, any method can be used as "static" methods, so long as they are called on the class itself, so just keep that in mind. For example, this will work perfectly fine:

    class Test:
        def test():
            print("works!")
    
    Test.test()
    

    That example will not work with instances of Test, since the method will be bound to the instance and called as Test.test(self) instead.

    Instance and class methods can be used as static methods as well in some cases, so long as the first arg is handled properly.

    class Test:
        def test(self):
            print("works!")
    
    Test.test(None)
    

    Perhaps another rare case is a staticmethod that is also bound to a class or instance. For example:

    class Test:
        @classmethod
        def test(cls): pass
    
    Test.static_test = staticmethod(Test.test)
    

    Though technically it is a staticmethod, it is really behaving like a classmethod. So in your introspection, you may consider checking the __self__ (recursively on __func__) to see if the method is bound to a class or instance.

    0 讨论(0)
  • 2020-12-06 17:07

    Your approach seems a bit flawed to me, but you can check class attributes:

    (in Python 2.7):

    >>> type(A.f)
    <type 'instancemethod'>
    >>> type(A.g)
    <type 'function'>
    

    or instance attributes in Python 3.x

    >>> a = A()
    >>> type(a.f)
    <type 'method'>
    >>> type(a.g)
    <type 'function'>
    
    0 讨论(0)
  • 2020-12-06 17:11

    Why bother? You can just call g like you call f:

    a = A()
    a.f()
    a.g()
    
    0 讨论(0)
  • 2020-12-06 17:19

    I happens to have a module to solve this. And it's Python2/3 compatible solution. And it allows to test with method inherit from parent class.

    Plus, this module can also test:

    1. regular attribute
    2. property style method
    3. regular method
    4. staticmethod
    5. classmethod

    For example:

    class Base(object):
        attribute = "attribute"
    
        @property
        def property_method(self):
            return "property_method"
    
        def regular_method(self):
            return "regular_method"
    
        @staticmethod
        def static_method():
            return "static_method"
    
        @classmethod
        def class_method(cls):
            return "class_method"
    
    class MyClass(Base):
        pass
    

    Here's the solution for staticmethod only. But I recommend to use the module posted here.

    import inspect
    
    def is_static_method(klass, attr, value=None):
        """Test if a value of a class is static method.
    
        example::
    
            class MyClass(object):
                @staticmethod
                def method():
                    ...
    
        :param klass: the class
        :param attr: attribute name
        :param value: attribute value
        """
        if value is None:
            value = getattr(klass, attr)
        assert getattr(klass, attr) == value
    
        for cls in inspect.getmro(klass):
            if inspect.isroutine(value):
                if attr in cls.__dict__:
                    bound_value = cls.__dict__[attr]
                    if isinstance(bound_value, staticmethod):
                        return True
        return False
    
    0 讨论(0)
提交回复
热议问题