The Python Oracle

getattr on class objects

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Magic Ocean Looping

--

Chapters
00:00 Getattr On Class Objects
00:58 Accepted Answer Score 5
01:39 Answer 2 Score 3
02:32 Answer 3 Score 0
02:57 Thank you

--

Full question
https://stackoverflow.com/questions/1849...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #classmethod #getattr

#avk47



ACCEPTED ANSWER

Score 5


Is this good enough?

import types
class Test(object):
    @staticmethod
    def foo():
        print 'foo'

    def bar(self):
        print 'bar'

In combination with:

>>>(isinstance(getattr(Test, 'foo'), types.FunctionType),
    isinstance(getattr(Test, 'bar'), types.FunctionType))
True, False

You can also use the inspect module:

>>> inspect.isfunction(Test.foo)
True
>>> inspect.isfunction(Test.bar)
False

With a little additional work you can even distinguish class methods from instance methods and static methods:

import inspect

def get_type(cls, attr):
    try:
        return [a.kind for a in inspect.classify_class_attrs(cls) if a.name == attr][0]
    except IndexError:
        return None

class Test(object):
    @classmethod
    def foo(cls):
        print 'foo'

    def bar(self):
        print 'bar'

    @staticmethod
    def baz():
        print 'baz'

You can use it as:

>>> get_type(Test, 'foo')
'class method'
>>> get_type(Test, 'bar')
'method'
>>> get_type(Test, 'baz')
'static method'
>>> get_type(Test, 'nonexistant')
None



ANSWER 2

Score 3


Your results from an incorrect definition of foo, not any underlying semantics of class attributes. By default, a function declared inside a class is an instance method, which must take at least one argument, an instance of the class. Conventionally, it is referred to as self:

class A:
    def foo(self):
        print "foo()"

Normally, you would call such a method like this:

a = A()
a.foo()    # passes the object 'a' implicitly as the value of the parameter 'self'

but this is legal as well

a = A()
A.foo(a)   # pass the object 'a' explicitly as the value of the parameter 'self'

In order to define a function inside a class that doesn't take any such implicit arguments, you need to decorate it with the @staticmethod decorator:

class A:
    @staticmethod
    def foo():
        print "foo()"

Now, you can call foo the way you tried to previously:

>>> A.foo()
foo()



ANSWER 3

Score 0


You want something like this:

from inspect import ismethod
from collections import Callable
def can_i_call(func):
    if not isinstance(func, Callable):
        # not a callable at all
        return False

    if not ismethod(func):
        # regular function or class or whatever
        return True

    # func is a method
    return func.im_self is not None

Note: this will only test whether or not an attempt to call will error out because you're calling an unbound method without a self. It doesn't guarantee that func() will succeed, i.e. not fail for any other reason.