如何检查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

Answers:


91

dir()之前的功能怎么样getattr()

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

7
这不会检查它是方法还是变量
hek2mgl

1
使用dir并不是很好-它不能确认名称是否是例如方法
Tony Suffolk 66年

108

寻求宽恕比寻求许可要容易。

不要检查是否存在方法。不要在“检查”上浪费一行代码

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

56
但是也许他真的不想调用它,只是检查是否存在该方法(就我而言)……
Flavius 2012年

48
请注意,如果本身dyn.mymethod()加注,则此操作将失败AttributeError
2013年

10
如@DK所说,这将捕获所检查的方法可能引发的任何AttributeError,这可能是不希望的(更不用说在这种情况下会错误地推断出该方法的缺失)。
2014年

3
原则上讲很好,Python与其他语言不同,确实具有“例外作为控制流”的文化。但是,如果您正在使用Sentry / Raven或New Relic等异常日志记录工具,则必须单独过滤掉此类异常(如果可能的话),否则会产生噪音。我宁愿检查该方法是否存在,而不是调用它。
RichVel

2
在很多层面上这都是错误的。方法本身会引发AttributeError,这将被检测到,因为方法不存在!它还破坏了调试器的支持以打破异常。我还确定如果事情在循环中,这可能会影响性能。最后但没有列出我可能不想执行方法,只需验证它是否存在。您应该考虑删除此答案,或者至少放所有这些警告,以免天真的人们不会误导。
Shital Shah,

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,def getattr(object, name, default=None):我怀疑getattr的签名是不准确的,因为如果这样,我希望将None作为第三个参数传递不会改变函数的行为。
bszom 2013年

@bszom:在python shell中,help(getattr)说“给定默认参数时,如果属性不存在,则返回该参数;如果没有默认参数,则将引发异常。” -(实际上,如果缺少属性,您可以检查getattr确实引发了异常)很明显,无论PyCharm是什么,都是错误的。
ShreevatsaR 2014年

@ShreevatsaR感谢您证实我的怀疑。PyCharm是一个IDE。
bszom 2014年

4
SIMPLER VERSION:如果要检查当前类INSTANCE是否具有属性并且可以调用,请执行以下操作:if hasattr(self, "work") and callable(self.work)。这将检查实例是否具有工作属性(可以是变量或函数),然后检查其是否可调用(意味着它是一个函数)。
米奇·麦克马伯斯

14

您可以尝试使用“检查”模块:

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

is_method(dyn, 'mymethod')

12

我使用下面的实用程序功能。它适用于lambda,类方法以及实例方法。

效用方法

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

4

在里面查找怎么样dyn.__dict__

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

约定下带有下划线前缀的方法表示“私有”。
xtofl

double-underbar前缀加上double-underbar后缀表示“这通常由Python解释器本身使用”,通常对于某些最常见的用例,有某种方法可以从用户程序中获得相同的效果(在这种情况下,使用点表示法表示属性),但是如果您的用例确实需要它,那么使用它既不被禁止也不错误。
deStrangis

这是不被禁止的。错误是主观的:它取决于您要使遵循约定的程序员困惑多少:除非别无选择,否则不要使用它。
xtofl '17

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):返回x + y >>> globals()中的'myadd'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_onef_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')

这个示例仍然在两个类中列出了这两种方法,但是如果您希望将检查限制为仅在特定类中起作用,则需要做更多的工作,但这是绝对可能的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.