Trong đó tôi trả lời câu hỏi đã được hỏi
Tại sao Python không cung cấp nó ra khỏi hộp?
Tôi nghi ngờ rằng nó phải liên quan đến Zen của Python : "Nên có một - và tốt nhất là chỉ có một - cách rõ ràng để làm điều đó". Điều này sẽ tạo ra hai cách rõ ràng để truy cập các giá trị từ từ điển: obj['key']
vàobj.key
.
Hãy cẩn thận và cạm bẫy
Chúng bao gồm có thể thiếu rõ ràng và nhầm lẫn trong mã. tức là, những điều sau đây có thể gây nhầm lẫn cho ai đó khác sẽ duy trì mã của bạn vào một ngày sau đó, hoặc thậm chí với bạn, nếu bạn không quay lại trong một thời gian. Một lần nữa, từ Zen : "Tính dễ đọc!"
>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Nếu d
được khởi tạo hoặc KEY
được xác định hoặc d[KEY]
được chỉ định ở xad.spam
đang được sử dụng, nó có thể dễ dàng dẫn đến nhầm lẫn về những gì đang được thực hiện, vì đây không phải là một thành ngữ thường được sử dụng. Tôi biết nó sẽ có khả năng làm tôi bối rối.
Ngoài ra, nếu bạn thay đổi giá trị của KEY
như sau (nhưng bỏ lỡ thay đổi d.spam
), bây giờ bạn sẽ nhận được:
>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'
IMO, không đáng nỗ lực.
Các mặt hàng khác
Như những người khác đã lưu ý, bạn có thể sử dụng bất kỳ đối tượng có thể băm nào (không chỉ là một chuỗi) làm khóa chính tả. Ví dụ,
>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>>
là hợp pháp, nhưng
>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
File "<stdin>", line 1
d.(2, 3)
^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>>
không phải. Điều này cho phép bạn truy cập vào toàn bộ phạm vi các ký tự có thể in hoặc các đối tượng có thể băm khác cho các khóa từ điển mà bạn không có khi truy cập thuộc tính đối tượng. Điều này làm cho phép thuật như một siêu dữ liệu đối tượng được lưu trong bộ nhớ cache, giống như công thức từ Python Cookbook (Ch. 9) .
Trong đó tôi biên tập
Tôi thích tính thẩm mỹ spam.eggs
hơn spam['eggs']
(tôi nghĩ rằng nó trông sạch hơn), và tôi thực sự bắt đầu thèm chức năng này khi tôi gặp namedtuple
. Nhưng sự tiện lợi của việc có thể làm những điều sau đây hơn hẳn.
>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>
Đây là một ví dụ đơn giản, nhưng tôi thường xuyên thấy mình sử dụng dicts trong các tình huống khác nhau hơn là tôi sử dụng obj.key
ký hiệu (nghĩa là khi tôi cần đọc prefs trong từ tệp XML). Trong các trường hợp khác, khi tôi muốn khởi tạo một lớp động và tát một số thuộc tính vào nó vì lý do thẩm mỹ, tôi tiếp tục sử dụng một lệnh cho tính nhất quán để tăng cường khả năng đọc.
Tôi chắc chắn rằng OP từ lâu đã giải quyết điều này với sự hài lòng của anh ấy, nhưng nếu anh ấy vẫn muốn chức năng này, thì tôi khuyên anh ấy nên tải xuống một trong các gói từ pypi cung cấp nó:
Bunch là người tôi quen thuộc hơn. Phân lớp củadict
, vì vậy bạn có tất cả các chức năng đó.
AttrDict cũng có vẻ như nó cũng khá tốt, nhưng tôi không quen thuộc với nó và đã không xem qua nguồn chi tiết nhiều như tôi có Bunch .
- Con nghiện tích cực duy trì và cung cấp quyền truy cập giống như attr và hơn thế nữa.
- Theo ghi nhận trong các bình luận của Rotareti, Bunch đã không được chấp nhận, nhưng có một ngã ba hoạt động được gọi là Munch .
Tuy nhiên, để cải thiện khả năng đọc mã của anh ấy, tôi thực sự khuyên anh ấy không nên trộn lẫn các kiểu ký hiệu của mình. Nếu anh ta thích ký hiệu này thì anh ta chỉ cần khởi tạo một đối tượng động, thêm các thuộc tính mong muốn của mình vào đó và gọi nó là một ngày:
>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}
Trong đó tôi cập nhật, để trả lời câu hỏi tiếp theo trong phần Nhận xét
Trong các bình luận (bên dưới), Elmo hỏi:
Nếu bạn muốn đi sâu hơn thì sao? (tham khảo loại (...))
Mặc dù tôi chưa bao giờ sử dụng trường hợp sử dụng này (một lần nữa, tôi có xu hướng sử dụng lồng nhau dict
, để thống nhất), đoạn mã sau hoạt động:
>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
... setattr(d, x, C())
... i = 1
... for y in 'one two three'.split():
... setattr(getattr(d, x), y, i)
... i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}
collections.namedtuple
là rất hữu ích cho việc này.