Как проверить, существует ли метод в Python?


83

В функции __getattr__(), если указанная переменная не найдена, выдается ошибка. Как я могу проверить, существует ли переменная или метод как часть объекта?

import string
import logging

class Dynamo:
 def __init__(self,x):
  print "In Init def"
  self.x=x
 def __repr__(self):
  print self.x
 def __str__(self):
  print self.x
 def __int__(self):
  print "In Init def"
 def __getattr__(self, key):
    print "In getattr"
    if key == 'color':
        return 'PapayaWhip'
    else:
        raise AttributeError


dyn = Dynamo('1')
print dyn.color
dyn.color = 'LemonChiffon'
print dyn.color
dyn.__int__()
dyn.mymethod() //How to check whether this exist or not

Ответы:


91

Как насчет dir()функции раньше getattr()?

>>> "mymethod" in dir(dyn)
True

7
Это не проверяет, является ли это методом или переменной
— hek2mgl

1
использование dir не очень хорошо - это не подтверждает, что имя является, например, методом
— Тони Саффолк 66,

109

Проще просить прощения, чем разрешения.

Не проверяйте, существует ли метод. Не тратьте ни единой строчки кода на "проверку"

try:
    dyn.mymethod() # How to check whether this exists or not
    # Method exists and was used.  
except AttributeError:
    # Method does not exist; What now?

57
Но, возможно, он действительно не хочет называть это, просто чтобы проверить, существует ли этот метод (как в моем случае) ...
— Флавий

49
Обратите внимание, что это не удастся, если dyn.mymethod()возникает AttributeErrorсам.
— DK

10
как говорит @DK, это перехватит любую AttributeError, которая может быть вызвана проверяемым методом, что может быть нежелательным (не говоря уже о том, что в этом случае это будет ошибочным выводом об отсутствии метода).
— ShreevatsaR

3
В принципе, это хорошо, и в Python есть культура «исключения как поток управления», в отличие от других языков. Однако, если вы используете инструменты регистрации исключений, такие как Sentry / Raven или New Relic, такие исключения должны быть отфильтрованы индивидуально (если это возможно) или генерировать шум. Я бы предпочел проверить, существует ли метод, а не вызывать его.
— RichVel

2
Это не правильно на многих уровнях. Сам метод может вызвать ошибку AttributeError, и это будет обнаружено, поскольку метод не существует! Это также разрушает поддержку отладчика из-за исключения исключений. Я также уверен, что это, вероятно, повлияет на производительность, если все будет в цикле. Последний, но не список, который я мог бы не захотеть выполнять, просто проверьте, существует ли он. Вам следует подумать об удалении этого ответа или, по крайней мере, о всех этих предупреждениях, чтобы наивные люди не вводили в заблуждение.
— Шитал Шах,

107

Проверить, есть ли у класса такой метод?

hasattr(Dynamo, key) and callable(getattr(Dynamo, key))

или же

hasattr(Dynamo, 'mymethod') and callable(getattr(Dynamo, 'mymethod'))

Вы можете использовать self.__class__вместоDynamo


23
Noneне вызывается, поэтому вы можете просто сделать callable(getattr(Dynamo, 'mymethod', None)). Я использовал этот ответ, потому что мой super (). Mymethod () мог выброситьAttributeError
— sbutler

@sbutler Интересно, что работает. Согласно PyCharm, подпись для getattr, def getattr(object, name, default=None):я подозреваю, не точна, потому что если бы это было так, я бы ожидал, что передача None в качестве третьего параметра не изменит поведение функции.
— bszom

@bszom: в оболочке python help(getattr): «Когда задан аргумент по умолчанию, он возвращается, если атрибут не существует; без него в этом случае возникает исключение». - (и действительно, вы можете проверить, что getattr вызывает исключение, если атрибут отсутствует) так ясно, что что бы ни было PyCharm, это неправильно.
— ShreevatsaR

@ShreevatsaR Спасибо, что подтвердили мои подозрения. PyCharm - это IDE.
— bszom

4
ПРОЩЕ версия: Если вы хотите , чтобы проверить , если текущий экземпляр класса имеет атрибут , и это отозвано, просто сделать это: if hasattr(self, "work") and callable(self.work). Это проверяет, имеет ли экземпляр рабочий атрибут (может быть либо переменной, либо функцией), а затем проверяет, может ли он быть вызван (что означает, что это функция).
— Митч МакМаберс

14

Вы можете попробовать использовать модуль inspect:

import inspect
def is_method(obj, name):
    return hasattr(obj, name) and inspect.ismethod(getattr(obj, name))

is_method(dyn, 'mymethod')

12

Я использую служебную функцию ниже. Он работает с лямбда-выражениями, методами класса, а также с методами экземпляра.

Полезный метод

def has_method(o, name):
    return callable(getattr(o, name, None))

Пример использования

Определим тестовый класс

class MyTest:
  b = 'hello'
  f = lambda x: x

  @classmethod
  def fs():
    pass
  def fi(self):
    pass

Теперь ты можешь попробовать,

>>> a = MyTest()                                                    
>>> has_method(a, 'b')                                         
False                                                          
>>> has_method(a, 'f')                                         
True                                                           
>>> has_method(a, 'fs')                                        
True                                                           
>>> has_method(a, 'fi')                                        
True                                                           
>>> has_method(a, 'not_exist')                                       
False                                                          

2
Этот ответ более подходит (по крайней мере, на мой взгляд), чем другие ответы, потому что он не использует общий подход (используя tryоператор) и проверяет всякий раз, когда член является фактической функцией. отличная доля!
— ymz 07

4

Как насчет того, чтобы поискать это dyn.__dict__?

try:
    method = dyn.__dict__['mymethod']
except KeyError:
    print "mymethod not in dyn"

Методы с префиксом подчеркивания по соглашению означают «частные».
— xtofl

префикс с двойным подчеркиванием плюс суффикс с двойным подчеркиванием означает, что `` это обычно используется самим интерпретатором Python '', и обычно есть способ добиться того же эффекта от пользовательской программы для наиболее распространенных случаев использования (в этом случае это будет с использованием точечной нотации для атрибута), но использовать его не запрещено и не неправильно, если в вашем случае это действительно требуется.
— deStrangis

Это не запрещено. Ошибочность субъективна: это зависит от того, насколько вы хотите запутать программистов, которые придерживаются соглашений: не используйте это, если у вас нет альтернативы.
— xtofl

3

Может быть, так, если все методы вызываются

app = App(root) # some object call app 
att = dir(app) #get attr of the object att  #['doc', 'init', 'module', 'button', 'hi_there', 'say_hi']

for i in att: 
    if callable(getattr(app, i)): 
        print 'callable:', i 
    else: 
        print 'not callable:', i

1

Если ваш метод находится за пределами класса, и вы не хотите запускать его и вызывать исключение, если оно не существует:

'mymethod' in globals()


1
>>> def myadd (x, y): return x + y >>> 'myadd' в globals () True
— gerowam

-1

Думаю, тебе стоит посмотреть на inspectупаковку. Это позволяет «обернуть» некоторые вещи. Когда вы используете dirметод, он также перечисляет встроенные методы, унаследованные методы и все другие атрибуты, делающие возможными коллизии, например:

class One(object):

    def f_one(self):
        return 'class one'

class Two(One):

    def f_two(self):
        return 'class two'

if __name__ == '__main__':
    print dir(Two)

Массив, который вы получаете, dir(Two)содержит как f_oneи, так f_twoи множество встроенных вещей. С помощью inspectвы можете сделать это:

class One(object):

    def f_one(self):
        return 'class one'

class Two(One):

    def f_two(self):
        return 'class two'

if __name__ == '__main__':
    import inspect

    def testForFunc(func_name):
        ## Only list attributes that are methods
        for name, _ in inspect.getmembers(Two, inspect.ismethod):
            if name == func_name:
                return True
        return False

    print testForFunc('f_two')

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.