Python: check if method is static
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'>
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.
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.