[英]Accessing OrderedDict keys like attributes in Python
我想寫一個容器類
data['a']
和類似屬性的訪問,例如data.a
; 這是在這里解決的 collections.OrderedDict
; 這是在這里解決的 我修改了1.的子collections.OrderedDict
類的解決方案。 dict
而不是dict
但是它不起作用; 見下文。
from collections import OrderedDict
class mydict(OrderedDict):
def __init__(self, *args, **kwargs):
super(mydict, self).__init__(*args, **kwargs)
self.__dict__ = self
D = mydict(a=1, b=2)
#D['c'] = 3 # fails
D.d = 4
#print D # fails
帶有失敗注釋的兩行會導致以下錯誤:
print D
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 176, in __repr__
return '%s(%r)' % (self.__class__.__name__, self.items())
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 113, in items
return [(key, self[key]) for key in self]
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 76, in __iter__
root = self.__root
AttributeError: 'struct' object has no attribute '_OrderedDict__root'
和
D['c'] = 3
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 58, in __setitem__
root = self.__root
AttributeError: 'mydict' object has no attribute '_OrderedDict__root'
這個問題有方法解決嗎 ? 可以修補__init__
函數嗎?
首先,如果你只想讓這個工作,不明白你的嘗試有什么問題,在PyPI,ActiveState等上有多個“AttrDict”實現。搜索一個並查看它的代碼 - 或者只是安裝它並使用它。
那個self.__dict__ = self
不是你想要的。 我意識到人們推薦它,但它有一些基本的主要問題。 其中一個問題正是你所看到的問題。
特別是,它意味着您現在已經丟失了所有現有屬性,包括OrderedDict
本身使用的內部屬性(比如您收到錯誤的__root
)和附加到所有對象的特殊屬性(如__class__
)。
當你剛剛使用dict
你沒有注意到這個問題 - 至少在CPython中 - 因為dict
是用C實現的,它需要操作的特殊成員存儲在C結構中,而不是__dict__
,所以你不能失去他們。 但是對於在Python中實現的任何需要任何特殊成員的類,問題變得明顯。
Python有自定義屬性訪問的特殊方法。 你想要做的是實現這些方法:
class AttrDict(OrderedDict):
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
self[name] = value
def __delattr__(self, name):
del self[name]
但是,在這種情況下,即使這樣也不適用於所有內容,因為當OrderedDict
的代碼嘗試使用__root
時,您仍然會調用覆蓋! 要解決這個問題,你只需要將這些方法中的一些調用轉發到你的dict,而不是全部 。
而“某些”很復雜,很難做到。 一個更簡單的解決方案是封裝和委托給OrderedDict
而不是繼承:
class AttrDict(object):
def __init__(self, *args, **kwargs):
self._od = OrderedDict(*args, **kwargs)
def __getattr__(self, name):
return self._od[name]
def __setattr__(self, name, value):
if name == '_od':
self.__dict__['_od'] = value
else:
self._od[name] = value
def __delattr__(self, name):
del self._od[name]
或者,更簡單地說,只需使用OrderedDict作為__dict__
- 這是元類的范例,但如果你想快速和骯臟,你可以在__init__
或__new__
。
后一種解決方案只會使您成為普通對象,其中的屬性恰好是有序的,而不是映射。 但是轉發映射方法也很容易。 實現__getitem__
, __setitem__
, __delitem__
, __iter__
,和__len__
轉發給self._od
,並繼承collections.MutableMapping
填補了API的其余部分。
現在,如果你回過頭來查看PyPI上的“AttrDict”並點擊實現,你會發現這正是他們所做的:他們將__getattr__
和__getitem__
轉發給OrderedDict的__getitem__
,依此類推。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.