2012-02-16 35 views
13

Tôi đang tìm cách tạo một cơ chế tra cứu đơn giản trong python và muốn đảm bảo rằng chưa có thứ gì đó ẩn trong thư viện rộng lớn trong python chưa thực hiện điều này trước khi tạo ra nó.Truy cập python dict với nhiều chuỗi tìm kiếm chính

Tôi đang tìm kiếm để có một dict được định dạng một cái gì đó như thế này

my_dict = { 
    "root": { 
    "secondary": { 
     "user1": { 
      "name": "jim", 
      "age": 24 
     }, 
     "user2": { 
     "name": "fred", 
     "age": 25 
     } 
    } 
    } 
} 

và tôi đang cố gắng để có một cách để truy cập dữ liệu bằng cách sử dụng một ký hiệu thập phân đó sẽ là một cái gì đó tương tự như

root.secondary.user2 

và trả lại kết quả đó trở lại làm phản hồi. Tôi nghĩ rằng phải có một cái gì đó mà làm điều này và tôi có thể viết một mà không có nhiều khó khăn nhưng tôi muốn chắc chắn rằng tôi không tái tạo một cái gì đó tôi có thể bị thiếu từ tài liệu. Cảm ơn

+0

Bạn đang tìm đường cú pháp ('mydict.root.secondary.user2') hoặc chỉ tra cứu qua chuỗi? –

Trả lời

28

Không có gì trong thư viện chuẩn cho mục đích này là, nhưng nó là khá dễ dàng để mã này tự hỏi:

>>> key = "root.secondary.user2" 
>>> reduce(dict.get, key.split("."), my_dict) 
{'age': 25, 'name': 'fred'} 

này khai thác thực tế là nhìn lên cho phím k trong từ điển d có thể được viết là dict.get(d, k). Áp dụng điều này lặp đi lặp lại bằng cách sử dụng reduce() dẫn đến kết quả mong muốn.

Sửa: Đối với đầy đủ ba chức năng để có được, đặt hoặc xóa các phím từ điển sử dụng phương pháp này:

def get_key(my_dict, key): 
    return reduce(dict.get, key.split("."), my_dict) 

def set_key(my_dict, key, value): 
    key = key.split(".") 
    my_dict = reduce(dict.get, key[:-1], my_dict) 
    my_dict[key[-1]] = value 

def del_key(my_dict, key): 
    key = key.split(".") 
    my_dict = reduce(dict.get, key[:-1], my_dict) 
    del my_dict[key[-1]] 
+0

Điều này làm việc tuyệt vời để truy xuất, nhưng bất kỳ ý tưởng nào về việc thực sự cập nhật một trường trong dict đó bằng cách sử dụng cùng một phương thức – Tanerax

+0

+1 cho câu trả lời 'reduce()'; mặc dù tôi cũng thực sự chỉ đơn giản như câu trả lời, ước gì tôi có thể +2. – SingleNegationElimination

+0

@Tanerax: Để cập nhật, hãy tách thành phần cuối cùng của khóa và truy xuất từ ​​điển có chứa bằng các thành phần hàng đầu. Đã thêm mã ví dụ vào câu trả lời. –

1

Recursion vẫn hoạt động.

def walk_into(dict, key): 
    head, _, tail = key.partition('.') 
    if tail: 
     return walk_into(dict[head], tail) 
    return dict, key 
d, k = walk_into(my_dict, "root.secondary.user2") 

d[k] có thể được sử dụng để nhận hoặc đặt một giá trị mới.

2

Bạn có thể có điều đó. Bạn có thể phân lớp dict, thêm tra cứu khóa (và thậm chí giữ lại tên dict) bằng cách sử dụng mã tương tự như dưới đây. Tuy nhiên, hình thức {...} vẫn sẽ sử dụng lớp dict được xây dựng sẵn (bây giờ được gọi là orig_dict), vì vậy bạn phải đính kèm nó, như vậy: Dict({...}). Việc triển khai đệ quy này chuyển đổi từ điển sang dạng mới, do đó bạn không phải sử dụng phương thức trên cho bất kỳ mục từ điển nào là từ điển đơn giản.

orig_dict = dict 
class Dict(orig_dict): 
    def __init__(self, *args, **kwargs): 
     super(Dict, self).__init__(*args, **kwargs) 
     for k, v in self.iteritems(): 
      if type(v) == orig_dict and not isinstance(v, Dict): 
       super(Dict, self).__setitem__(k, Dict(v)) 
    def __getattribute__(self, k): 
     try: return super(Dict, self).__getattribute__(k) 
     except: return self.__getitem__(k) 
    def __setattr__(self, k, v): 
     if self.has_key(k): self.__setitem__(k, v) 
     else: return super(Dict, self).__setattr__(k, v) 
    def __delattr__(self, k): 
     try: self.__delitem__(k) 
     except: super(Dict, self).__delattr__(k) 
    def __setitem__(self, k, v): 
     toconvert = type(v) == orig_dict and not isinstance(v, Dict) 
     super(Dict, self).__setitem__(k, Dict(v) if toconvert else v) 

# dict = Dict <-- you can even do this but I advise against it 

# testing: 
b = Dict(a=1, b=Dict(c=2, d=3)) 
c = Dict({'a': 1, 'b': {'c': 2, 'd': 3}}) 
d = Dict(a=1, b={'c': 2, 'd': {'e': 3, 'f': {'g': 4}}}) 

b.a = b.b 
b.b = 1 
d.b.d.f.g = 40 
del d.b.d.e 
d.b.c += d.b.d.f.g 
c.b.c += c.a 
del c.a 
print b 
print c 
print d 
Các vấn đề liên quan