26

The following class definition:

class A:
  def f(self):
    return 'this is f'
  
  @staticmethod
  def g():
    return 'this is g'

a = A()

So f is a normal method and g is a static method.

Now, how can I check if the funcion objects a.f and a.g are static or not? Is there a "isstatic" function in Python?

I have to know this because I have lists containing many different function (method) objects, and to call them I have to know if they are expecting self as a parameter or not.

6 Answers 6

24

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you for pointing me to the "types" module, I almost forgot about it.
17

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)

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.

Another final caution for those doing more in depth introspection is that a staticmethod could be defined in a different class. The __qualname__ will reveal whether the static method was defined in the class it is attached to or not.

1 Comment

Thanks a lot @Azmisov for get_attr_static to avoid calling the descriptor protocol ! I learnt something today :) ++
14

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'>

3 Comments

Note that this only works if the object is instantiated(at least in python 3), so if you want to check if a method is static without instantiating the object, then this will not work.
@DuckPuncher Thanks! Youre correct, I have updated the answer.
@DuckPuncher In Python 3 you can check isinstance(A.__dict__['f'], types.FunctionType) and isinstance(A.__dict__['g'], staticmethod)
5

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

2 Comments

This has a bug. It checks if any method with that name in the class's MRO is static. If there's a static method in a base class that's shadowed by a non-static method in a subclass, your function will output True.
I fixed the bug in this package github.com/MacHu-GWU/inspect_mate-project
1

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

a = A()
a.f()
a.g()

5 Comments

wow, indeed, you are right! I thought it would not work because I have the methods in a list, say l = [a.f, a.g], and call them with l[0]() and l[1](). But it works! Strange, I always thought normal methods need a reference to their containing object as first parameter. I mean, if I do A.f(), it is an error, while A.g() works, whereas A.f(a) also works fine.
This is obviously good answer (don't check if method is static!) to the problem, but it does not answer question in the title (check if method is static).
Right you are, Jiri. But I think it's good to have multiple ways of solving a problem, that's why I posted this answer. And it seems OP found it useful, so win/win :)
@DanielJung that works because when you do a.f, python creates bound method instance (it is bound to the object on which is is called). When you do A.f it returns unbound method (you can still call it using A.f(a)), while A.g returns a simple function.
Why bother? Because you are implementing a metaclass, decorator or writing code analysis tools.
1

There is no way in python to check if the method is static or not, only with having the method object. this is my implementation.

def isStaticmethod_withClass(classObj, methodName):
    return isinstance(inspect.getattr_static(classObj, methodName), staticmethod)


def isStaticmethod_onlyByStringDefinition(method):
    if not isinstance(method, types.FunctionType):
        return False

    return inspect.getsource(method).strip().startswith('@staticmethod')


def isStaticmethod(method):
    if isStaticmethod_onlyByStringDefinition(
            method):  # check being static method with it's string definition
        staticmethod_actualClass = getStaticmethod_actualClass(method)  # gets class object
        return isStaticmethod_withClass(staticmethod_actualClass, method.__name__)
    return False


def getStaticmethod_actualClass(method):
    if not isStaticmethod_onlyByStringDefinition(method):
        return None
    className = method.__qualname__.split('.')[0]
    moduleName = method.__module__
    actualClass = getattr(sys.modules[moduleName], className)
    return actualClass


def isClassMethod(method):
    bound_to = getattr(method, '__self__', None)
    if not isinstance(bound_to, type):
        # must be bound to a class
        return False
    name = method.__name__
    for cls in bound_to.__mro__:
        descriptor = vars(cls).get(name)
        if descriptor is not None:
            return isinstance(descriptor, classmethod)
    return False
    ```
    function `isStaticmethod` can get if the object is a static method or not. also you may get the actual class of that method with `getStaticmethod_actualClass`.

the `isStaticmethod_withClass` is from @Azmisov 's code here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.