簡體   English   中英

訪問OrderedDict鍵,如Python中的屬性

[英]Accessing OrderedDict keys like attributes in Python

我想寫一個容器類

  1. 允許索引(在字典樣式中),例如data['a']和類似屬性的訪問,例如data.a ; 這是在這里解決的
  2. 保留添加條目的順序,例如通過子類化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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM