2009-03-16 45 views
66

Rất nhiều lần trong Perl, tôi sẽ làm một cái gì đó như thế này:Cách tốt nhất để khởi tạo một dict của dicts bằng Python là gì?

$myhash{foo}{bar}{baz} = 1 

Làm thế nào tôi sẽ dịch này để Python? Cho đến nay tôi có:

if not 'foo' in myhash: 
    myhash['foo'] = {} 
if not 'bar' in myhash['foo']: 
    myhash['foo']['bar'] = {} 
myhash['foo']['bar']['baz'] = 1 

Có cách nào tốt hơn không?

+0

ahem, quả thực khác đã được hỏi 5 ngày trước và cả hai đều là 4 tuổi ... –

Trả lời

83
class AutoVivification(dict): 
    """Implementation of perl's autovivification feature.""" 
    def __getitem__(self, item): 
     try: 
      return dict.__getitem__(self, item) 
     except KeyError: 
      value = self[item] = type(self)() 
      return value 

Thử nghiệm:

a = AutoVivification() 

a[1][2][3] = 4 
a[1][3][3] = 5 
a[1][2]['test'] = 6 

print a 

Output:

{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}} 
+3

Có thể mở rộng nó để nó hỗ trợ các hành vi sau đây: a [1] [2] [3] + = some_value. Vì vậy, nếu khóa không tồn tại trước, thì a [1] [2] [3] sẽ được khởi tạo với giá trị mặc định của loại (some_value)? –

+4

Chức năng này có tác dụng phụ mà bất kỳ nỗ lực nào để lấy khóa không tồn tại cũng tạo khóa. Thông thường, bạn chỉ muốn tự động tạo khóa nếu bạn đồng thời đặt khóa hoặc khóa con. –

+0

Có cách nào để tạo biến gán không? Vì vậy, với 'var = [1,2,3]', tôi có thể làm như 'a [var] = 1', nó sẽ mở rộng thành' a [1] [2] [3] = 1'? – PascalVKooten

2

Tôi đoán dịch sát nghĩa sẽ là:

mydict = {'foo' : { 'bar' : { 'baz':1}}} 

Calling:

>>> mydict['foo']['bar']['baz'] 

mang đến cho bạn 1.

Điều đó có vẻ một chút thô với tôi, mặc dù.

(Tôi không có anh chàng perl, mặc dù, vì vậy tôi đoán vào những gì perl của bạn không)

+1

Điều đó chỉ hoạt động ở thời gian khởi tạo, mặc dù, phải không? – mike

+0

Tôi không chắc chắn ý của bạn là gì. – Dana

+0

@Dana, trái với việc thêm giá trị mới vào mydict trong thời gian chạy. –

2

điển lồng nhau như thế được (thường) được gọi là một mans nghèo đối tượng. Có, có một hàm ý và nó có thể tương quan với thiên nhiên hướng đối tượng pythons.

12

Có một lý do nó cần phải được một dict của dicts? Nếu không có lý do thuyết phục cho rằng cấu trúc cụ thể, bạn có thể chỉ đơn giản là chỉ số dict với một tuple:

mydict = {('foo', 'bar', 'baz'):1} # Initializes dict with a key/value pair 
mydict[('foo', 'bar', 'baz')]  # Returns 1 

mydict[('foo', 'unbar')] = 2  # Sets a value for a new key 

Các dấu ngoặc đơn được yêu cầu nếu bạn khởi tạo dict với một chìa khóa tuple, nhưng bạn có thể bỏ qua chúng khi thiết/nhận các giá trị sử dụng []:

mydict = {}      # Initialized the dict 
mydict['foo', 'bar', 'baz'] = 1 # Sets a value 
mydict['foo', 'bar', 'baz']  # Returns 1 
+0

Bạn có thể rõ ràng khi nào bạn có thể bỏ qua các dấu ngoặc đơn? Có phải vì dấu phẩy là toán tử tuple và chỉ cần dấu ngoặc đơn nếu chúng ta có nhóm không rõ ràng? – Kiv

+0

Đã thêm làm rõ, thx. – zweiterlinde

+0

Điều này thực sự có thể nhanh hơn từ điển lồng nhau vì có một tra cứu thay vì ba. – ChaimG

86

Nếu số lượng tổ bạn cần cố định, collections.defaultdict thật tuyệt vời.

ví dụ: làm tổ hai sâu:

myhash = collections.defaultdict(dict) 
myhash[1][2] = 3 
myhash[1][3] = 13 
myhash[2][4] = 9 

Nếu bạn muốn đi một mức độ làm tổ, bạn sẽ cần phải làm một cái gì đó như:

myhash = collections.defaultdict(lambda : collections.defaultdict(dict)) 
myhash[1][2][3] = 4 
myhash[1][3][3] = 5 
myhash[1][2]['test'] = 6 

chỉnh sửa: MizardX chỉ ra rằng chúng ta có thể có được genericity đầy đủ với một chức năng đơn giản:

import collections 
def makehash(): 
    return collections.defaultdict(makehash) 

Bây giờ chúng ta có thể làm:

myhash = makehash() 
myhash[1][2] = 4 
myhash[1][3] = 8 
myhash[2][5][8] = 17 
# etc 
+4

hoặc def makehash(): return collections.defaultdict (makehash); myhash = makehash() –

+0

Tôi không có vấn đề với các hàm đệ quy "truyền thống", nhưng có một điều gì đó mà tôi thấy không trực quan. Odd. Dù sao cũng cảm ơn! –

+1

Cảm ơn vì điều này. Đó lambda: defaultdict() là những gì tôi cần. – wheaties

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