Làm thế nào để kiểm tra xem một phương thức có tồn tại trong Python hay không?


83

Trong hàm __getattr__(), nếu không tìm thấy biến được tham chiếu thì nó sẽ báo lỗi. Làm cách nào để kiểm tra xem một biến hoặc phương thức có tồn tại như một phần của một đối tượng hay không?

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

Câu trả lời:


91

Làm thế nào về dir()chức năng trước đây getattr()?

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

7
Điều này không kiểm tra xem nó là một phương pháp hay một biến
hek2mgl

1
sử dụng dir là không lớn - nó không xác nhận rằng tên của nó là một phương pháp ví dụ
Tony Suffolk 66

108

Yêu cầu sự tha thứ sẽ dễ dàng hơn là xin phép.

Đừng kiểm tra xem có phương pháp nào không. Đừng lãng phí một dòng mã cho việc "kiểm tra"

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
Nhưng có lẽ anh ấy thực sự không muốn gọi nó, chỉ để kiểm tra xem có phương pháp đó (vì nó là trong trường hợp của tôi) ...
Flavius

48
Lưu ý rằng điều này sẽ không thành công nếu dyn.mymethod()tăng AttributeErrorchính nó.
DK

10
như @DK nói, điều này sẽ bẫy bất kỳ AttributeError nào có thể được đưa ra bởi phương thức đang được kiểm tra, điều này có thể không mong muốn (chưa kể đến việc nó sẽ suy ra sai khi không có phương thức trong trường hợp đó).
ShreevatsaR

3
Tốt về nguyên tắc, và Python có văn hóa "ngoại lệ là luồng điều khiển" không giống như các ngôn ngữ khác. Tuy nhiên, nếu bạn đang sử dụng các công cụ ghi ngoại lệ như Sentry / Raven hoặc New Relic, các ngoại lệ đó phải được lọc ra riêng lẻ (nếu có thể) hoặc tạo ra tiếng ồn. Tôi muốn kiểm tra xem phương thức có tồn tại hay không hơn là gọi nó.
RichVel

2
Điều này là sai trên nhiều cấp độ. Phương thức tự nó có thể tăng AttributeError và điều này sẽ được phát hiện là phương thức không tồn tại! Nó cũng làm hỏng hỗ trợ trình gỡ lỗi để phá vỡ các ngoại lệ. Tôi cũng chắc chắn rằng điều này có thể ảnh hưởng đến hiệu suất nếu mọi thứ xảy ra trong vòng lặp. Cuối cùng nhưng không phải danh sách Tôi có thể không muốn thực thi phương thức, chỉ cần xác thực nếu nó tồn tại. Bạn nên xem xét loại bỏ câu trả lời này hoặc ít nhất đưa tất cả các cảnh báo này để những người ngây thơ không bị hiểu nhầm.
Shital Shah

107

Kiểm tra xem lớp có phương thức như vậy không?

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

hoặc là

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

Bạn có thể sử dụng self.__class__thay vìDynamo


23
Nonekhông thể gọi được, vì vậy bạn chỉ có thể làm callable(getattr(Dynamo, 'mymethod', None)). Tôi đã sử dụng câu trả lời này vì siêu của tôi () MyMethod () có thể ném.AttributeError
sbutler

@sbutler Thật thú vị khi điều đó hoạt động. Theo PyCharm, chữ ký cho getattr là def getattr(object, name, default=None):tôi nghi ngờ điều đó không chính xác bởi vì nếu đúng như vậy, tôi sẽ mong đợi việc truyền Không có làm tham số thứ ba không thay đổi hành vi của hàm.
bszom

@bszom: Trong python shell, có nội dung help(getattr)"Khi một đối số mặc định được đưa ra, nó sẽ được trả về khi thuộc tính không tồn tại; không có nó, một ngoại lệ sẽ được đưa ra trong trường hợp đó." - (và thực sự bạn có thể kiểm tra xem getattr có đưa ra ngoại lệ không nếu thuộc tính bị thiếu) rõ ràng như vậy, dù PyCharm là gì đi nữa, điều đó là sai.
ShreevatsaR

@ShreevatsaR Cảm ơn bạn đã xác nhận sự nghi ngờ của tôi. PyCharm là một IDE.
bszom

4
Phiên bản đơn giản: Nếu bạn muốn kiểm tra xem lớp INSTANCE hiện nay có một thuộc tính và nó có thể được gọi, chỉ cần làm như sau: if hasattr(self, "work") and callable(self.work). Thao tác này kiểm tra xem cá thể có thuộc tính công việc (có thể là một biến hoặc một hàm) hay không và sau đó kiểm tra xem nó có thể gọi được không (nghĩa là nó là một hàm).
Mitch McMabers

14

Bạn có thể thử sử dụng mô-đun 'kiểm tra':

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

is_method(dyn, 'mymethod')

12

Tôi sử dụng chức năng tiện ích dưới đây. Nó hoạt động trên lambda, các phương thức lớp cũng như các phương thức thể hiện.

Phương pháp Tiện ích

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

Ví dụ sử dụng

Hãy xác định lớp thử nghiệm

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

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

Bây giờ bạn có thể thử,

>>> 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
Câu trả lời này phù hợp hơn (ít nhất là theo ý kiến ​​của tôi) so với các câu trả lời khác vì nó không sử dụng cách tiếp cận chung (sử dụng trycâu lệnh) và nó kiểm tra bất cứ khi nào thành viên là một chức năng thực tế. chia sẻ tuyệt vời!
ymz

4

Làm thế nào về việc tìm kiếm nó trong dyn.__dict__?

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

các phương thức có tiền tố dưới thanh theo quy ước có nghĩa là 'riêng tư'.
xtofl

tiền tố gạch dưới kép cộng với hậu tố gạch dưới kép có nghĩa là 'điều này thường được sử dụng bởi chính trình thông dịch Python' và thường có một số cách để thực hiện hiệu ứng tương tự từ chương trình của người dùng cho các trường hợp sử dụng phổ biến nhất (trong trường hợp này là sử dụng ký hiệu dấu chấm cho một thuộc tính), nhưng không bị cấm cũng như không được sử dụng nó nếu trường hợp sử dụng của bạn thực sự yêu cầu nó.
deStrangis

Nó không bị cấm. Sai lầm là chủ quan: nó phụ thuộc vào mức độ bạn muốn gây nhầm lẫn cho các lập trình viên tuân thủ quy ước: không sử dụng nó trừ khi bạn không có giải pháp thay thế.
xtofl

3

Có thể như thế này, giả sử tất cả các phương thức đều có thể gọi được

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

Nếu phương thức của bạn nằm ngoài một lớp và bạn không muốn chạy nó và đưa ra một ngoại lệ nếu nó không tồn tại:

'mymethod' in globals()


1
>>> def myadd (x, y): return x + y >>> 'myadd' trong hình cầu () Đúng
gerowam

-1

Tôi nghĩ bạn nên nhìn vào inspectgói. Nó cho phép bạn 'bọc' một số thứ. Khi bạn sử dụng dirphương thức, nó cũng liệt kê các phương thức được tích hợp sẵn, các phương thức kế thừa và tất cả các thuộc tính khác làm cho xung đột có thể xảy ra, ví dụ:

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)

Mảng bạn nhận được dir(Two)chứa cả f_onef_twovà rất nhiều thứ được tích hợp sẵn. Với inspectbạn có thể làm điều này:

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

Ví dụ này vẫn liệt kê cả hai phương thức trong hai lớp nhưng nếu bạn muốn giới hạn việc kiểm tra chỉ hoạt động trong một lớp cụ thể thì cần phải làm việc nhiều hơn một chút, nhưng hoàn toàn có thể.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.