2010-03-11 26 views
22

Tôi đang tìm kiếm bản thân mình làm như sau một chút quá thường xuyên:cách ngắn gọn để getattr() và sử dụng nó nếu không muốn nói Không bằng Python

attr = getattr(obj, 'attr', None) 
if attr is not None: 
    attr() 
    # Do something, either attr(), or func(attr), or whatever 
else: 
    # Do something else 

Có cách nào pythonic hơn về văn bản đó? Tốt hơn chưa? (Ít nhất là không trong hoạt động, IMO.)

try: 
    obj.attr() # or whatever 
except AttributeError: 
    # Do something else 
+0

"Ít nhất không trong hoạt động, IMO". Có lẽ bạn nên đo nó. Bạn sẽ thấy rằng các ngoại lệ Python rất nhanh. –

+1

Nếu nó thực sự là một nút cổ chai (có thể không), hiệu suất cũng phụ thuộc vào trường hợp phổ biến - thuộc tính thường tồn tại, hay nó thường không tồn tại? – orip

Trả lời

26

Vì bạn đang gọi số attr, bạn sẽ d chỉ làm:

def default_action(): 
    # do something else 

action = getattr(obj, 'attr', default_action) 

action() 
+0

Tôi chưa bao giờ nghĩ về điều này, nhưng điều này chắc chắn hoạt động hoàn hảo cho một số trường hợp sử dụng của tôi! –

5

Có một thành ngữ đẹp:

if hasattr(obj, 'attr'): 
    ...something... 
else: 
    ...something else... 

Từ hai tùy chọn bạn đăng Tôi thích là người đầu tiên. Khái niệm về ném ngoại lệ khi truy cập các thành viên dường như không phải là điều mà các ngoại lệ được dùng để sử dụng.

+0

-1 vì AttributeError là một ngoại lệ rất rõ ràng được sử dụng "khi truy cập các thành viên". –

+2

Đây là loại câu hỏi mở. Tôi không tìm thấy bằng cách sử dụng 'AttributeError' như là một thực hành tốt trong tình huống này, bạn làm. Nó có nghĩa là bạn đúng và tôi không? Tôi không nghĩ như vậy – pajton

1

Sử dụng thử/ngoại trừ thường được coi là có nhiều pythonic hơn. Nó cũng hiệu quả hơn nếu obj không có thuộc tính, vì nó loại bỏ các khối thử nghiệm - thử không có phí nếu không có ngoại lệ. Mặt khác, nó ít hiệu quả hơn nếu obj không có thuộc tính vì nó sẽ có chi phí ném và bắt ngoại lệ.

+2

Có lẽ nó là pythonic, nhưng nó là xấu xí và tôi tin rằng trường hợp ngoại lệ không có nghĩa là cho mục đích đó. Trong python bạn thậm chí có thể nắm bắt 'IndentationError', đây cũng là pythonic để bao quanh một số mã bạn không chắc chắn là thụt vào đúng? – pajton

+0

Tại sao phải không? Giả sử bạn đang nhập mô-đun plugin và mô-đun không thể nhập. Các ngoại lệ ném nói lý do tại sao. Nếu bạn có động lực để làm như vậy, bạn có thể bắt lỗi và báo cho người dùng biết chính xác cách sửa lỗi ("Xóa vấn đề thụt lề trên dòng X của tệp Y"). Tôi đánh giá cao tính linh hoạt này. –

+0

Và tôi thách thức bạn "bao quanh một số mã" không được thụt lề đúng cách với khối thử .... Bạn phải gián tiếp hơn vì trình phân tích cú pháp sẽ bắt gặp vấn đề trước khi cấu trúc 'try:' được hoàn thành. –

6

Thay thế try/except, khi bạn mã hóa, có thể vô tình gây ra sự cố AttributeError gây ra bởi các sự cố trong bất kỳ điều gì mà attr() đang gọi, bị phát hiện. Nếu bạn muốn mã hóa với try/except, đó là hợp lý và khá thực hiện tốt nếu nó là hiếm cho thuộc tính là mất tích, sử dụng:

try: 
    attr = obj.attr 
except AttributeError: 
    dosome(thingelse) 
else: 
    attr() 

này sẽ không nguyên nhân "tình cờ bắt" như trên. Vì cách tiếp cận nào thích hợp hơn, tôi thường đi theo cách tiếp cận ngoại lệ - "EAFP", "dễ dàng hơn để hỏi sự tha thứ hơn phép" (một phương châm thường được gán cho Đô đốc Grace Hopper, động lực đằng sau COBOL và CODASYL) tốt cho Python ;-).

0

Ah, nó phụ thuộc vào mã chính xác. Hai công cụ của bạn:

  • hasattr (obj, 'attr') trả về Đúng nếu và chỉ khi obj.attr tồn tại.
  • getattr (obj, 'attr', other_value) trả về obj.attr nếu nó tồn tại, else else_value
  • try a = obj.attr/trừ thất bại()/else do_something (a) khi hiệu suất có thể đọc được.

Dưới đây là những trường hợp phổ biến nhất:

the_name = getattr(user, 'name', '<Unknown User>') 
user.name = getattr(user, 'name', '<Unknown User>') 
if not hasattr(name, 'user'): 
    try_asking_again() 
name = user.name if hasattr(user, 'name') else do_expensive_name_lookup(user) 

Để hiểu rõ hơn về toàn bộ quá trình, nhìn vào đoạn mã này:

class Thing(): 
    def __init__(self): 
     self.a = 'A' 

    def __getattr__(self, attr): 
     if attr == "b": 
      return "B" 
     else: 
      raise AttributeError("Thing instance has no attribute '" + attr + "'") 

item = Thing() 
print "hasattr(a) is " + str(hasattr(item, "a")) 
print "a is " + item.a 
print "hasattr(b) is " + str(hasattr(item, "b")) 
print "b is " + item.b 
out = "c is " + item.c if hasattr(item, "c") else "No C" 
print out 
print "and c is also " + getattr(item, "c", "Not Assigned") 
print "c throws an Attribute exception " + item.c 

trong đó có sản lượng này:

hasattr(a) is True 
a is A 
hasattr(b) is True 
b is B 
No C 
and c is also Not Assigned 
Traceback (most recent call last): 
    File "attr_snippet.py", line 23, in <module> 
    print "c throws an Attribute exception " + item.c 
    File "attr_snippet.py", line 9, in __getattr__ 
    raise AttributeError("Thing instance has no attribute '" + attr + "'") 
AttributeError: Thing instance has no attribute 'c' 
5

Tương tự như câu trả lời của Joe, nhưng ngắn hơn:

getattr(obj, 'attr', lambda: None)() 
+0

Có, tính năng này hoạt động. Tôi vẫn sẽ sử dụng try/except phương pháp tiếp cận trong hầu hết các trường hợp mặc dù gây ra nó dễ dàng hơn để đọc cho người khác. – chhantyal

Các vấn đề liên quan