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 2016

1
dirを使用するのは良くありません
Tony Suffolk 66

108

許可を求めるよりも許しを求める方が簡単です。

メソッドが存在するかどうかを確認しないでください。「チェック」に1行のコードを無駄にしないでください

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

48
それ自体をdyn.mymethod()上げると、これは失敗することに注意してくださいAttributeError
DK 2013年

10
@DKが言うように、これはチェックされているメソッドによって発生する可能性のあるAttributeErrorをトラップしますが、これは望ましくない場合があります(その場合、メソッドが存在しないと誤って推測することは言うまでもありません)。
ShreevatsaR 2014年

3
原則としては良好であり、Pythonには他の言語とは異なり「制御フローとしての例外」の文化があります。ただし、Sentry / RavenやNewRelicなどの例外ログツールを使用している場合は、そのような例外を個別に除外するか(可能な場合)、ノイズを生成する必要があります。メソッドを呼び出すよりも、メソッドが存在するかどうかを確認したいと思います。
RichVel 2016

2
これは非常に多くのレベルで間違っています。メソッド自体がAttributeErrorを発生させる可能性があり、メソッドが存在しないため、これが検出されます。また、例外を破るためにデバッガーのサポートを台無しにします。また、物事がループしている場合、これはおそらくパフォーマンスに影響を与えると確信しています。最後にリストではありませんが、メソッドを実行したくない場合があります。メソッドが存在するかどうかを検証するだけです。ナイーブな人々が誤解を招かないように、この回答を削除するか、少なくともこれらすべての警告を出すことを検討する必要があります。
ShitalShah19年

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 2013

@sbutlerそれがうまくいくのは興味深い。PyCharmによると、getattrのシグネチャdef getattr(object, name, default=None):は、正確ではないと思われます。正確な場合は、関数の動作を変更しない3番目のパラメーターとしてNoneを渡すと予想されるためです。
bszom 2013年

@bszom:Pythonシェルで、help(getattr)「デフォルトの引数が指定されている場合、属性が存在しない場合に返されます。それがないと、例外が発生します。」-(そして実際、属性が欠落している場合、getattrが例外を発生させることを確認できます)非常に明確に、PyCharmが何であれ、それは間違っています。
ShreevatsaR 2014年

@ShreevatsaR私の疑いを確認していただきありがとうございます。PyCharmはIDEです。
bszom 2014年

4
単純なバージョン:現在のクラスINSTANCEに属性があり、それが呼び出し可能かどうかを確認する場合は、次のようにしますif hasattr(self, "work") and callable(self.work)。これは、インスタンスに作業属性(変数または関数のいずれか)があるかどうかを確認してから、呼び出し可能かどうか(つまり、関数であるかどうか)を確認します。
MitchMcMabers19年

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

4

調べてみdyn.__dict__ませんか?

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

慣例によりアンダーバープレフィックス付きのメソッドは「プライベート」を意味します。
xtofl 2017年

double-underbarプレフィックスとdouble-underbarサフィックスは、「これは通常、Pythonインタープリター自体によって使用されます」を意味し、通常、最も一般的なユースケースでユーザーのプログラムから同じ効果を達成する方法があります(この場合は属性にドット表記を使用する)が、ユースケースで実際に必要な場合に使用することは禁止されておらず、間違っていません。
deStrangis 2017年

禁止されていません。間違いは主観的なものです。それは、慣習に従うプログラマーをどれだけ混乱させたいかによって異なります。代替手段がない限り、それを使用しないでください。
xtofl 2017年

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 >>> 'myadd'グローバルに()真
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')

この例でも、2つのクラスの両方のメソッドがリストされていますが、検査を特定のクラスでのみ機能するように制限する場合は、もう少し作業が必要ですが、絶対に可能です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.