Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: how does inspect.ismethod work?

Tags:

python

inspect

I'm trying to get the name of all methods in my class. When testing how the inspect module works, i extraced one of my methods by obj = MyClass.__dict__['mymethodname'].

But now inspect.ismethod(obj) returns False while inspect.isfunction(obj) returns True, and i don't understand why. Is there some strange way of marking methods as methods that i am not aware of? I thought it was just that it is defined in the class and takes self as its first argument.

like image 422
Eskil Avatar asked Jul 12 '10 12:07

Eskil


People also ask

How do you inspect code in Python?

We use the getsource() method of inspect module to get the source code of the function. Returns the text of the source code for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a single string.

What is inspect stack in Python?

inspect. stack() returns a list with frame records. In function whoami() : inspect. stack()[1] is the frame record of the function that calls whoami , like foo() and bar() . The fourth element of the frame record ( inspect.

What is inspect method?

inspect is a String class method in Ruby which is used to return a printable version of the given string, surrounded by quote marks, with special characters escaped. Syntax: str.inspect. Parameters: Returns: Here, str is the given string.


4 Answers

You are seeing some effects of the behind-the-scenes machinery of Python.

When you write f = MyClass.__dict__['mymethodname'], you get the raw implementation of "mymethodname", which is a plain function. To call it, you need to pass in an additional parameter, class instance.

When you write f = MyClass.mymethodname (note the absence of parentheses after mymethodname), you get an unbound method of class MyClass, which is an instance of MethodType that wraps the raw function you obtained above. To call it, you need to pass in an additional parameter, class instance.

When you write f = MyClass().mymethodname (note that i've created an object of class MyClass before taking its method), you get a bound method of an instance of class MyClass. You do not need to pass an additional class instance to it, since it's already stored inside it.

To get wrapped method (bound or unbound) by its name given as a string, use getattr, as noted by gnibbler. For example:

unbound_mth = getattr(MyClass, "mymethodname")

or

bound_mth = getattr(an_instance_of_MyClass, "mymethodname")
like image 185
atzz Avatar answered Oct 04 '22 03:10

atzz


Use the source

def ismethod(object):
    """Return true if the object is an instance method.
    Instance method objects provide these attributes:
        __doc__         documentation string
        __name__        name with which this method was defined
        __func__        function object containing implementation of method
        __self__        instance to which this method is bound"""
    return isinstance(object, types.MethodType)

The first argument being self is just by convention. By accessing the method by name from the class's dict, you are bypassing the binding, so it appears to be a function rather than a method

If you want to access the method by name use

getattr(MyClass, 'mymethodname') 
like image 33
John La Rooy Avatar answered Oct 04 '22 05:10

John La Rooy


Well, do you mean that obj.mymethod is a method (with implicitly passed self) while Klass.__dict__['mymethod'] is a function?

Basically Klass.__dict__['mymethod'] is the "raw" function, which can be turned to a method by something called descriptors. This means that every function on a class can be both a normal function and a method, depending on how you access them. This is how the class system works in Python and quite normal.

If you want methods, you can't go though __dict__ (which you never should anyways). To get all methods you should do inspect.getmembers(Klass_or_Instance, inspect.ismethod)

You can read the details here, the explanation about this is under "User-defined methods".

like image 28
Jochen Ritzel Avatar answered Oct 04 '22 05:10

Jochen Ritzel


From a comment made on @THC4k's answer, it looks like the OP wants to discriminate between built-in methods and methods defined in pure Python code. User defined methods are of types.MethodType, but built-in methods are not.

You can get the various types like so:

import inspect
import types

is_user_defined_method = inspect.ismethod

def is_builtin_method(arg):
    return isinstance(arg, (type(str.find), type('foo'.find)))

def is_user_or_builtin_method(arg):
    MethodType = types.MethodType
    return isinstance(arg, (type(str.find), type('foo'.find), MethodType))

class MyDict(dict):
    def puddle(self): pass

for obj in (MyDict, MyDict()):
    for test_func in (is_user_defined_method, is_builtin_method,
            is_user_or_builtin_method):
        print [attr 
            for attr in dir(obj)
            if test_func(getattr(obj, attr)) and attr.startswith('p')]

which prints:

['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
like image 44
Matt Anderson Avatar answered Oct 04 '22 03:10

Matt Anderson