2012-05-23 28 views
14

Tôi có một cuốn từ điển mà đôi khi nhận được cuộc gọi cho các phím không tồn tại, vì vậy tôi cố gắng và sử dụng hasattrgetattr để xử lý các trường hợp:hasattr của Python trên danh sách các giá trị của từ điển luôn luôn trả về false?

key_string = 'foo' 
print "current info:", info 
print hasattr(info, key_string) 
print getattr(info, key_string, []) 
if hasattr(info, key_string): 
    array = getattr(info, key_string, []) 
array.append(integer) 
info[key_string] = array 
print "current info:", info 

Lần đầu tiên này chạy với integer = 1:

current info: {} 
False 
[] 
current info: {'foo': [1]} 

Chạy lại mã này bằng integer = 2:

instance.add_to_info("foo", 2) 

current info: {'foo': [1]} 
False 
[] 
current info: {'foo': [2]} 

Lần chạy đầu tiên rõ ràng là thành công ({'foo': [1]}), nhưng hasattr trả về false và getattr sử dụng mảng trống mặc định lần thứ hai xung quanh, mất giá trị 1 trong quá trình! Tại sao điều này?

Trả lời

21

hasattr không kiểm tra cho các thành viên của một cuốn từ điển. Sử dụng các nhà điều hành in thay vào đó, hoặc .has_key phương pháp:

>>> example = dict(foo='bar') 
>>> 'foo' in example 
True 
>>> example.has_key('foo') 
True 
>>> 'baz' in example 
False 

Nhưng lưu ý rằng dict.has_key() đã bị phản đối, được khuyến khích chống lại bằng cách hướng dẫn phong cách PEP 8 và đã bị xóa hoàn toàn bằng Python 3.

Ngẫu nhiên, bạn sẽ chạy vào các vấn đề bằng cách sử dụng một lớp biến có thể thay đổi:

>>> class example(object): 
...  foo = dict() 
... 
>>> A = example() 
>>> B = example() 
>>> A.foo['bar'] = 'baz' 
>>> B.foo 
{'bar': 'baz'} 

khởi tạo nó trong __init__ của bạn thay vì:

class State(object): 
    info = None 

    def __init__(self): 
     self.info = {} 
+0

Tôi sẽ chết tiệt! Tôi nghĩ tôi đã phát điên. Tôi đã luôn sử dụng cấu trúc 'if/in/else' cho các tình huống kiểm tra từ điển này với các giá trị mặc định. Lần này kể từ khi tình hình thực tế thực sự phức tạp hơn nhiều so với ví dụ của tôi, với một vài hasattrs khác bay xung quanh, tôi ủng hộ rằng "cú pháp" thay vào đó ... mà rõ ràng là không hoạt động! Tôi sẽ nhớ điều này từ bây giờ, cảm ơn! –

+0

Ngoài ra, tôi đang xử lý thông tin trong init một cách thích hợp, chỉ muốn hợp lý hóa ví dụ. –

2

Một khóa từ điển là không giống như thuộc tính một đối tượng

thing1 = {'a', 123} 
hasattr(thing1, 'a') # False 
class c: pass 
thing2 = c() 
thing2.a = 123 
hasattr(thing2, 'a') # True 
1

Để kiểm tra các phần tử trong danh sách/từ điển, hãy sử dụng in. Để sử dụng giá trị mặc định, bạn có thể sử dụng dict.get:

def add_to_info(self, key_string, integer): 
    array = self.info.get(key_string, []) 
    array.append(integer) 
    self.info[key_string] = array 

Hoặc sử dụng defaultdict:

from collections import defaultdict 
class State(object): 
    info = defaultdict(list) 

    def add_to_info(self, key_string, integer): 
     self.info[key_string].append(integer) 
2

Hình như tất cả bạn cần là một dòng:

def add_to_info(self, key_string, integer): 
    self.info.setdefault(key_string, []).append(integer) 
0

Đó là tiện dụng đã được xác định một phản xạ getAttr nhận thuộc tính hoặc khóa từ một đối tượng.

def getAttr(obj, attribute, default=''): 

    # like getattr, but also check the keys of obj, and can return a default, if no key or no attribute was found. 
    # note there's a priority to attribute if both attribute and key exist. 

    result = getattr(obj, attribute) if hasattr(obj, attribute) else None 
    if result is None: 
    result = obj.get(attribute, default) if isinstance(obj, dict) else default 
    return result 
Các vấn đề liên quan