2012-04-18 21 views
8

Tôi cảm thấy như tôi đã thấy cách để thực hiện việc này gần đây. Nói rằng tôi đã có một dict trống và tôi muốn đặt một giá trị trong một dict lồng nhau bên trong dict trống, nhưng rõ ràng là dict lồng nhau chưa được tạo ra. Có cách nào để tạo khóa trung gian không? Đây là những gì tôi muốn làm:Đặt giá trị dict lồng nhau và tạo các phím trung gian

mydict = {} 
mydict['foo']['bar']['foobar'] = 25 

Nếu bạn thực thi mã này, bạn sẽ nhận được ngoại lệ KeyError cho 'foo'. Có chức năng tạo khóa trung gian không?

Cảm ơn.

+0

bản sao có thể có của [Tạo khóa dict python khi đang di chuyển] (http://stackoverflow.com/questions/3405073/generating-python-dict-keys-on-the-fly) – unutbu

Trả lời

14
from collections import defaultdict 
recursivedict = lambda: defaultdict(recursivedict) 
mydict = recursivedict() 

Khi bạn truy cập mydict['foo'], nó đặt mydict['foo'] để recursivedict khác. Nó sẽ thực sự xây dựng một recursivedict cho mydict['foo']['bar']['foobar'] là tốt, nhưng sau đó nó sẽ được ném ra bằng cách gán cho 25.

+0

Đây chính xác là những gì tôi đã nhớ đọc về-- cảm ơn. – skandocious

+0

Điều này có thể vi phạm 'mydict [' foo '] = 15⏎ mydict [' foo '] [' bar '] [' foobar '] = 25'. Trên một codebase lớn, OP không thể nhớ giá trị mà anh ta đã gán trước đó. – nehemiah

+0

@itsneo Đúng vậy. Tôi không nghĩ rằng có một cách tốt đẹp xung quanh đó; bạn phải tạo các hàm bao trả về '__getitem__' xung quanh phần tử được lưu trữ đè đè' __getitem__' của phần tử đó, điều này sẽ làm cho việc đặt một danh sách hoặc bất kỳ thứ gì vào dict là khó khăn. – Dougal

0

Không chắc lý do tại sao bạn muốn, nhưng:

>>> from collections import defaultdict as dd 
>>> mydict = dd(lambda: dd(lambda: {})) 
>>> mydict['foo']['bar']['foobar'] = 25 
>>> mydict 
defaultdict(<function <lambda> at 0x021B8978>, {'foo': defaultdict(<function <lambda> at 0x021B8618>, {'bar': {'foobar': 25}})}) 
+0

Điều này chỉ cho phép bạn lồng xuống ba lớp; bạn muốn hàm đệ quy, như trong [câu trả lời của tôi] (http://stackoverflow.com/a/10218517/344821), để có thể tiếp tục. – Dougal

+0

@Dougal: Câu trả lời của bạn không nói rằng khi tôi viết bài này. – MattH

+0

@Dougal: Nếu ba cấp độ sâu là tất cả các nhu cầu OP, nó là đủ. –

3

Một lựa chọn thay thế - tùy thuộc vào mục đích sử dụng của bạn, là sử dụng các bộ như phím thay vì các từ điển lồng nhau:

mydict = {} 
mydict['foo', 'bar', 'foobar'] = 25 

này sẽ hoạt động hoàn toàn tốt trừ khi bạn muốn lấy cành cây tại bất kỳ điểm nào (bạn không thể nhận được mydict ['foo'] trong trường hợp này).

Nếu bạn biết có bao nhiêu lớp làm tổ mà bạn muốn, bạn cũng có thể sử dụng functools.partial thay vì lambda.

from functools import partial 
from collections import defaultdict 

tripledict = partial(defaultdict, partial(defaultdict, dict)) 
mydict = tripledict() 
mydict['foo']['bar']['foobar'] = 25 

nào một số người thấy dễ đọc hơn, và nhanh hơn để tạo ra các trường hợp so với giải pháp lambda dựa trên tương đương:

python -m timeit -s "from functools import partial" -s "from collections import defaultdict" -s "tripledefaultdict = partial(defaultdict, partial(defaultdict, dict))" "tripledefaultdict()" 
1000000 loops, best of 3: 0.281 usec per loop 

python -m timeit -s "from collections import defaultdict" -s "recursivedict = lambda: defaultdict(recursivedict)" "recursivedict()" 
1000000 loops, best of 3: 0.446 usec per loop 

Mặc dù, như mọi khi, không có điểm tối ưu hóa cho đến khi bạn biết có là một nút cổ chai, vì vậy hãy chọn những gì hữu ích nhất và có thể đọc được trước những gì là nhanh nhất.

+0

Thú vị. Tôi không bao giờ nghĩ rằng sử dụng một tuple như là một khóa chính tả. Mặc dù điều này không giúp ích gì trong trường hợp của tôi, điều đó chắc chắn hữu ích-- cảm ơn! – skandocious

+0

Tất nhiên, có thể lấy các nhánh cây bằng giải pháp dựa trên tuple thông qua một cái gì đó như 'prefix = ('foo', 'bar'); l = len (tiền tố); branch = {k [l:]: v cho k, v trong mydict.items() nếu k [: l] == prefix} '- mặc dù cần lặp lại tất cả các phím. – Dougal

+0

@Dougal Vâng, tại thời điểm đó, bạn nên sử dụng '' dict''s lồng nhau. –

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