Python: как работает inspect.ismethod? - PullRequest
8 голосов
/ 12 июля 2010

Я пытаюсь получить название всех методов в моем классе. При тестировании работы модуля проверки я извлек один из моих методов на obj = MyClass.__dict__['mymethodname'].

Но теперь inspect.ismethod(obj) возвращает False, а inspect.isfunction(obj) возвращает True, и я не понимаю, почему. Есть какой-то странный способ маркировки методов как методов, о которых я не знаю? Я думал, что это просто, что он определен в классе и принимает self в качестве первого аргумента.

Ответы [ 5 ]

7 голосов
/ 12 июля 2010

Вы видите некоторые эффекты скрытого механизма Python.

Когда вы пишете f = MyClass.__dict__['mymethodname'], вы получаете необработанную реализацию «mymethodname», которая является простой функцией. Чтобы вызвать его, вам нужно передать дополнительный параметр, экземпляр класса.

Когда вы пишете f = MyClass.mymethodname (обратите внимание на отсутствие скобок после mymethodname), вы получаете несвязанный метод класса MyClass, который является экземпляром MethodType, который оборачивает необработанную функцию, которую вы получили выше. Чтобы вызвать его, вам нужно передать дополнительный параметр, экземпляр класса.

Когда вы пишете f = MyClass().mymethodname (обратите внимание, что я создал объект класса MyClass, прежде чем использовать его метод), вы получаете связанный метод экземпляра класса MyClass. Вам не нужно передавать ему дополнительный экземпляр класса, поскольку он уже хранится внутри него.

Чтобы получить упакованный метод (связанный или несвязанный) по его имени, указанному в виде строки, используйте getattr, как отмечено gnibbler . Например:

unbound_mth = getattr(MyClass, "mymethodname")

или

bound_mth = getattr(an_instance_of_MyClass, "mymethodname")
2 голосов
/ 12 июля 2010

Использовать источник

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
        im_class        class object in which this method belongs
        im_func         function object containing implementation of method
        im_self         instance to which this method is bound, or None"""
    return isinstance(object, types.MethodType)

Первый аргумент self - просто по соглашению.Получая доступ к методу по имени из условия класса, вы обходите привязку, поэтому она представляется функцией, а не методом

Если вы хотите получить доступ к методу по имени, используйте

getattr(MyClass, 'mymethodname') 
1 голос
/ 12 июля 2010

Из комментария, сделанного к ответу @ THC4k, похоже, что ОП хочет различать встроенные методы и методы, определенные в чистом коде Python. Пользовательские методы имеют значение types.MethodType, а встроенные методы - нет.

Вы можете получить различные типы, такие как:

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

который печатает:

['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
1 голос
/ 12 июля 2010

Ну, вы имеете в виду, что obj.mymethod - это метод (с неявно переданным self), в то время как Klass.__dict__['mymethod'] - это функция?

В основном Klass.__dict__['mymethod'] - это «сырая» функция, которую можно превратить в метод с помощью чего-то, называемого descriptors .Это означает, что каждая функция в классе может быть как нормальной функцией, так и методом, в зависимости от того, как вы к ним обращаетесь.Это то, как система классов работает в Python и вполне нормально.

Если вам нужны методы, вы не можете использовать __dict__ (что вам никогда не следует).Чтобы получить все методы, вы должны сделать inspect.getmembers(Klass_or_Instance, inspect.ismethod)

Вы можете прочитать подробности здесь , объяснение этого в разделе "Пользовательские методы".

0 голосов
/ 12 июля 2010

Вы можете использовать dir , чтобы получить имя доступных методов / атрибутов / и т. Д., Затем просмотреть их, чтобы узнать, какие из них являются методами.Вот так:

[ mthd for mthd in dir(FooClass) if inspect.ismethod(myFooInstance.__getattribute__(mthd)) ]

Я ожидаю, что будет более чистое решение, но это может быть то, что вы могли бы использовать, если никто другой не придумал.Я бы хотел, чтобы мне не пришлось использовать экземпляр класса для использования getattribute.

...