Python'da bir yöntemin mevcut olup olmadığı nasıl kontrol edilir?


83

Fonksiyonda __getattr__(), referans bir değişken bulunmazsa hata verir. Bir nesnenin parçası olarak bir değişken veya yöntemin var olup olmadığını nasıl kontrol edebilirim?

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

Yanıtlar:


91

Daha dir()önce işlev nasıl getattr()?

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

7
Bu, bir yöntem mi yoksa değişken mi olduğunu kontrol etmez
hek2mgl

1
dir kullanmak harika değil - örneğin adın bir yöntem olduğunu doğrulamıyor
Tony Suffolk 66

109

Af dilemek izin istemekten daha kolaydır.

Bir yöntemin var olup olmadığını kontrol etmeyin. "Kontrol etmek" için tek bir kod satırı bile harcamayın

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
Ama belki de gerçekten onu aramak istemiyor, sadece bu yöntemin olup olmadığını kontrol etmek için (benim durumumda olduğu gibi) ...
Flavius

49
dyn.mymethod()Bir AttributeErrorkendini yükseltirse bunun başarısız olacağını unutmayın .
DK

10
@DK'nın dediği gibi, bu, kontrol edilmekte olan yöntem tarafından ortaya çıkarılan ve istenmeyen olabilecek herhangi bir AttributeError hatasını yakalayacaktır (bu durumda yöntemin yokluğunun yanlış bir şekilde çıkarılacağından bahsetmiyorum bile).
ShreevatsaR

3
Prensipte iyidir ve Python diğer dillerin aksine "kontrol akışı olarak istisnalar" kültürüne sahiptir. Bununla birlikte, Sentry / Raven veya New Relic gibi istisna kayıt araçları kullanıyorsanız, bu tür istisnaların ayrı ayrı filtrelenmesi (eğer mümkünse) veya gürültü üretmesi gerekir. Yöntemin çağırmak yerine var olup olmadığını kontrol etmeyi tercih ederim.
RichVel

2
Bu pek çok düzeyde yanlıştır. Yöntemin kendisi AttributeError'ı artırabilir ve bu, yöntem olmadığı için algılanabilir! Ayrıca, istisnaları kırmak için hata ayıklayıcı desteğini de bozar. Ayrıca, bir şey döngüde olsaydı, bunun muhtemelen performansı etkileyeceğinden eminim. Son fakat liste değil, yöntemi yürütmek istemeyebilirim, sadece var olup olmadığını doğrulayın. Bu yanıtı kaldırmayı düşünmelisiniz veya en azından tüm bu uyarıları, saf insanların yanıltmaması için koymalısınız.
Shital Shah

107

Sınıfın böyle bir yöntemi olup olmadığını kontrol edin?

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

veya

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

Sen kullanabilirsiniz self.__class__yerineDynamo


23
Noneçağrılabilir değil, bu yüzden yapabilirsin callable(getattr(Dynamo, 'mymethod', None)). Bu yanıtı kullandım çünkü super (). Mymethod () atabilirAttributeError
sbutler

@sbutler İşe yarayan ilginç. PyCharm'a göre getattr'ın imzası def getattr(object, name, default=None):bunun doğru olmadığından şüpheleniyorum çünkü eğer öyleyse, işlevin davranışını değiştirmemesini üçüncü parametre olarak Hiçbiri olarak geçirmeyi beklerdim.
bszom

@bszom: Bir python kabuğunda, help(getattr)"Varsayılan bir bağımsız değişken verildiğinde, öznitelik olmadığında döndürülür; onsuz, bu durumda bir istisna ortaya çıkar." - (ve aslında getattr'ın öznitelik eksikse bir istisna oluşturup oluşturmadığını kontrol edebilirsiniz), PyCharm her ne ise, bu yanlış.
ShreevatsaR

@ShreevatsaR Şüphelerimi onayladığınız için teşekkürler. PyCharm bir IDE'dir.
bszom

4
SIMPLER VERSİYONU: Geçerli sınıf INSTANCE bir özeliği varsa kontrol etmek istiyorum ve onu çağrılabilir ise, sadece bunu: if hasattr(self, "work") and callable(self.work). Bu, örneğin bir iş özniteliğine sahip olup olmadığını (bir değişken veya bir işlev olabilir) ve ardından çağrılabilir olup olmadığını kontrol eder (yani bir işlevdir).
Mitch McMabers

14

'İncele' modülünü kullanmayı deneyebilirsiniz:

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

is_method(dyn, 'mymethod')

12

Aşağıdaki yardımcı program işlevini kullanıyorum. Lambda, sınıf yöntemleri ve örnek yöntemler üzerinde çalışır.

Fayda Yöntemi

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

Örnek Kullanım

Test sınıfını tanımlayalım

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

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

Şimdi deneyebilirsin

>>> 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
Bu cevap (en azından benim görüşüme göre) diğer cevaplardan daha uygundur çünkü genel bir yaklaşım (ifade kullanarak try) kullanmaz ve üye gerçek bir işlev olduğunda kontrol eder. harika paylaşım!
ymz

4

İçeri bakmaya ne dersin dyn.__dict__?

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

kuralın altında çubuk önekli yöntemler 'özel' anlamına gelir.
xtofl

çift ​​alt çubuk öneki artı çift alt çubuk soneki 'bu normalde Python yorumlayıcısının kendisi tarafından kullanılır' anlamına gelir ve genellikle en yaygın kullanım durumları için bir kullanıcının programından aynı etkiyi elde etmenin bir yolu vardır (bu durumda bir öznitelik için nokta notasyonu kullanmak), ancak kullanım durumunuz gerçekten gerektiriyorsa, onu kullanmak yasak veya yanlış değildir.
deStrangis

Yasak değil. Yanlışlık özneldir: bu, geleneklere uyan programcıları ne kadar karıştırmak istediğinize bağlıdır: başka alternatifiniz yoksa kullanmayın.
xtofl

3

Belki de böyle, tüm yöntemin çağrılabilir olduğunu varsayarsak

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

Metodunuz bir sınıfın dışındaysa ve onu çalıştırmak istemiyorsanız ve yoksa bir istisna oluşturmak istemiyorsanız:

'mymethod' in globals()


1
>>> def myadd (x, y): dönüş x + y >>> 'myadd' (globals) () True
gerowam

-1

Bence inspectpakete bakmalısın . Bazı şeyleri 'sarmamanıza' izin verir. dirYöntemi kullandığınızda, yerleşik yöntemleri, miras alınan yöntemleri ve çarpışmaları mümkün kılan diğer tüm öznitelikleri de listeler, örneğin:

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)

Aldığınız dizi dir(Two)hem f_oneve hem de f_twoçok sayıda yerleşik öğe içerir. İle inspectbunu yapabilirsiniz:

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

Bu örnekler hala iki sınıftaki her iki yöntemi de listelemektedir, ancak incelemeyi yalnızca belirli bir sınıfta çalışmak üzere sınırlamak istiyorsanız biraz daha fazla çalışma gerektirir, ancak kesinlikle mümkündür.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.