【问题标题】:How to check whether a method exists in Python?如何检查Python中是否存在方法?
【发布时间】:2011-11-26 16:32:01
【问题描述】:

在函数__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

【问题讨论】:

    标签: python methods


    【解决方案1】:

    检查类是否有这样的方法?

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

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

    您可以使用self.__class__ 代替Dynamo

    【讨论】:

    • None 是不可调用的,所以你可以只做callable(getattr(Dynamo, 'mymethod', None))。我使用这个答案是因为我的 super().mymethod() 可能会抛出 AttributeError
    • @sbutler 有趣的是,它有效。根据 PyCharm,getattr 的签名是 def getattr(object, name, default=None): 我怀疑这是不准确的,因为如果是这样,我希望传递 None 作为第三个参数不会改变函数的行为。
    • @bszom:在 python shell 中,help(getattr) 说“当给出默认参数时,当属性不存在时返回它;没有它,在这种情况下会引发异常。 " -- (事实上,如果缺少属性,您可以检查 getattr 是否会引发异常)非常清楚,无论 PyCharm 是什么,它都是错误的。
    • @ShreevatsaR 感谢您确认我的怀疑。 PyCharm 是一个 IDE。
    • SIMPLER VERSION: 如果你想检查当前类 INSTANCE 是否有一个属性并且它是可调用的,只需这样做:if hasattr(self, "work") and callable(self.work)。这将检查实例是否具有工作属性(可以是变量或函数),然后检查它是否可调用(意味着它是一个函数)。
    【解决方案2】:

    请求宽恕比请求许可更容易。

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

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

    【讨论】:

    • 但也许他真的不想调用它,只是为了检查是否有那个方法(就像我的情况一样)......
    • 请注意,如果dyn.mymethod() 自己引发AttributeError,这将失败。
    • 正如@DK 所说,这将捕获任何可能由正在检查的方法引发的 AttributeError ,这可能是不可取的(更不用说在这种情况下它会错误地推断出该方法的缺失) )。
    • 原则上很好,而且 Python 确实有一种与其他语言不同的“作为控制流的异常”文化。但是,如果您使用的是 Sentry/Raven 或 New Relic 等异常记录工具,则必须单独过滤此类异常(如果可能)或产生噪音。我宁愿检查该方法是否存在而不是调用它。
    • 这在很多层面上都是错误的。方法本身可以引发 AttributeError 并且这将被检测为方法不存在!它还破坏了调试器对中断异常的支持。我也确信如果事情处于循环状态,这可能会影响性能。最后但不是列出我可能不想执行方法,只需验证它是否存在。你应该考虑删除这个答案,或者至少把所有这些警告都写下来,这样天真的人就不会被误导。
    【解决方案3】:

    dir() 之前的getattr() 函数怎么样?

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

    【讨论】:

    • 这里不检查是方法还是变量
    • 使用 dir 不是很好 - 它不能确认名称是一个方法,例如
    【解决方案4】:

    我使用以下实用功能。它适用于 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                                                          
    

    【讨论】:

    • 这个答案比其他答案更合适(至少在我看来),因为它不使用通用方法(使用try 语句)并且它会检查成员是否是实际函数。很棒的分享!
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      dyn.__dict__ 中查找如何?

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

      【讨论】:

      • 按照惯例,带有下划线前缀的方法表示“私有”。
      • 双下划线前缀加上双下划线后缀表示“这通常由 Python 解释器本身使用”,通常有一些方法可以从用户的程序中获得相同的效果,以用于最常见的用途情况(在这种情况下,它将对属性使用点表示法),但如果您的用例确实需要它,则使用它既不是禁止也不是错误的。
      • 不禁止。错误是主观的:这取决于你想在多大程度上混淆遵守约定的程序员:除非你别无选择,否则不要使用它。
      【解决方案7】:

      可能是这样,假设所有方法都是可调用的

      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
      

      【讨论】:

        【解决方案8】:

        如果您的方法在一个类之外,并且您不想运行它并在它不存在时引发异常:

        'mymethod' in globals()

        【讨论】:

        • >>> def myadd(x,y): return x+y >>> 'myadd' in globals() True
        【解决方案9】:

        适合喜欢简单的人。

        
        class ClassName:
            def function_name(self):
                return
        
        class_name = ClassName()
        print(dir(class_name))
        # ['__init__', .... ,'function_name']
        
        answer = 'function_name' in dir(class_name)
        print("is'function_name' in class ? >> {answer}")
        # is 'function_name' in class ? >> True
        

        【讨论】:

          【解决方案10】:

          我认为你应该看看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')
          

          这个例子仍然列出了两个类中的两个方法,但是如果你想限制检查只在一个特定的类中起作用,它需要更多的工作,但这是绝对可能的。

          【讨论】:

            猜你喜欢
            • 2014-04-11
            • 2014-12-01
            • 1970-01-01
            • 2017-05-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-22
            相关资源
            最近更新 更多