如何使用点“。”来访问字典的成员?
如何让Python字典成员可以通过点“。”访问?
例如,我不想写mydict['val']
,而是写mydict.val
。
我也想这样访问嵌套的字典。 例如
mydict.mydict2.val
会参考
mydict = { 'mydict2': { 'val': ... } }
你可以用我刚刚做的这个课程来做到这一点。 使用这个类,你可以像使用另一个字典(包括json序列化)或点符号一样使用Map
对象。 我希望能帮助你:
class Map(dict): """ Example: m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer']) """ def __init__(self, *args, **kwargs): super(Map, self).__init__(*args, **kwargs) for arg in args: if isinstance(arg, dict): for k, v in arg.iteritems(): self[k] = v if kwargs: for k, v in kwargs.iteritems(): self[k] = v def __getattr__(self, attr): return self.get(attr) def __setattr__(self, key, value): self.__setitem__(key, value) def __setitem__(self, key, value): super(Map, self).__setitem__(key, value) self.__dict__.update({key: value}) def __delattr__(self, item): self.__delitem__(item) def __delitem__(self, key): super(Map, self).__delitem__(key) del self.__dict__[key]
用法示例:
m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer']) # Add new key m.new_key = 'Hello world!' # Or m['new_key'] = 'Hello world!' print m.new_key print m['new_key'] # Update values m.new_key = 'Yay!' # Or m['new_key'] = 'Yay!' # Delete key del m.new_key # Or del m['new_key']
我一直保存在一个util文件中。 你也可以在自己的课堂上把它作为一个混合使用。
>>> class dotdict(dict): ... """dot.notation access to dictionary attributes""" ... __getattr__ = dict.get ... __setattr__ = dict.__setitem__ ... __delattr__ = dict.__delitem__ ... >>> mydict = {'val':'it works'} >>> nested_dict = {'val':'nested works too'} >>> mydict = dotdict(mydict) >>> mydict.val 'it works' >>> mydict.nested = dotdict(nested_dict) >>> mydict.nested.val 'nested works too'
从字典派生并实现__getattr__
和__setattr__
。
或者你可以使用非常相似的Bunch 。
我不认为有可能monkeypatch内置的字典类。
通过pip
安装dotmap
pip install dotmap
它做你想做的所有事情和子类dict
,所以它像一个正常的字典操作:
from dotmap import DotMap m = DotMap() m.hello = 'world' m.hello m.hello += '!' # m.hello and m['hello'] now both return 'world!' m.val = 5 m.val2 = 'Sam'
最重要的是,你可以将其转换为dict
对象,也可以将其转换为dict
对象:
d = m.toDict() m = DotMap(d) # automatic conversion in constructor
这意味着如果你想访问的东西已经是dict
forms,你可以把它变成一个DotMap
以方便访问:
import json jsonDict = json.loads(text) data = DotMap(jsonDict) print data.location.city
最后,它自动创build新的子DotMap
实例,所以你可以做这样的事情:
m = DotMap() m.people.steve.age = 31
与束的比较
完全披露:我是DotMap的创造者。 我创build它,因为Bunch
缺less这些function
- 记住订单项目是按顺序添加和迭代的
- 自动创build子
DotMap
,这样可以节省时间,并且在有很多层次结构时可以使代码更DotMap
- 从一个
dict
构造并recursion地将所有子dict
实例转换为DotMap
我试过这个:
class dotdict(dict): def __getattr__(self, name): return self[name]
你也可以试试__getattribute__
。
使每个字典都是一个类似的dotdict就足够好了,如果你想从一个多层的字典中初始化这个,试一下也可以实现__init__
。
在库格尔的回答的基础上,迈克·格雷厄姆慎重考虑的话,如果我们做一个包装呢?
class DictWrap(object): """ Wrap an existing dict, or create a new one, and access with either dot notation or key lookup. The attribute _data is reserved and stores the underlying dictionary. When using the += operator with create=True, the empty nested dict is replaced with the operand, effectively creating a default dictionary of mixed types. args: d({}): Existing dict to wrap, an empty dict is created by default create(True): Create an empty, nested dict instead of raising a KeyError example: >>>dw = DictWrap({'pp':3}) >>>dw.ab += 2 >>>dw.ab += 2 >>>dw.a['c'] += 'Hello' >>>dw.a['c'] += ' World' >>>dw.ad >>>print dw._data {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3} """ def __init__(self, d=None, create=True): if d is None: d = {} supr = super(DictWrap, self) supr.__setattr__('_data', d) supr.__setattr__('__create', create) def __getattr__(self, name): try: value = self._data[name] except KeyError: if not super(DictWrap, self).__getattribute__('__create'): raise value = {} self._data[name] = value if hasattr(value, 'items'): create = super(DictWrap, self).__getattribute__('__create') return DictWrap(value, create) return value def __setattr__(self, name, value): self._data[name] = value def __getitem__(self, key): try: value = self._data[key] except KeyError: if not super(DictWrap, self).__getattribute__('__create'): raise value = {} self._data[key] = value if hasattr(value, 'items'): create = super(DictWrap, self).__getattribute__('__create') return DictWrap(value, create) return value def __setitem__(self, key, value): self._data[key] = value def __iadd__(self, other): if self._data: raise TypeError("A Nested dict will only be replaced if it's empty") else: return other
别。 属性访问和索引是Python中独立的东西,你不应该让它们执行相同的操作。 如果你有一些应该有可访问的属性并使用[]
符号来从字典中获得一个项目,那么创build一个类(可能是由一个名为namedtuple
一个类)。
语言本身不支持这一点,但有时这仍然是一个有用的要求。 除了Bunch配方之外,还可以编写一个可以使用虚线string访问字典的小方法:
def get_var(input_dict, accessor_string): """Gets data from a dictionary using a dotted accessor-string""" current_data = input_dict for chunk in accessor_string.split('.'): current_data = current_data.get(chunk, {}) return current_data
这将支持这样的事情:
>> test_dict = {'thing': {'spam': 12, 'foo': {'cheeze': 'bar'}}} >> output = get_var(test_dict, 'thing.spam.foo.cheeze') >> print output 'bar' >>
如果你想腌你修改的字典,你需要添加几个状态方法来回答上面的问题:
class dotdict(dict): """dot.notation access to dictionary attributes""" def __getattr__(self, attr): return self.get(attr) __setattr__= dict.__setitem__ __delattr__= dict.__delitem__ def __getstate__(self): return self def __setstate__(self, state): self.update(state) self.__dict__ = self
面料有一个非常好的,最小的实施 。 扩展它以允许嵌套访问,我们可以使用defaultdict
,结果如下所示:
from collections import defaultdict class AttributeDict(defaultdict): def __init__(self): super(AttributeDict, self).__init__(AttributeDict) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(key) def __setattr__(self, key, value): self[key] = value
利用它如下:
keys = AttributeDict() keys.abc.xyz.x = 123 keys.abc.xyz.abc = 234
Kugel的答案是“从字典中派生出来并实现__getattr__
和__setattr__
”。 现在你知道了!
def dict_to_object(dick): # http://stackoverflow.com/a/1305663/968442 class Struct: def __init__(self, **entries): self.__dict__.update(entries) return Struct(**dick)
如果决定永久性地将该dict
转换为对象,应该这样做。 你可以在访问之前创build一个一次性的对象。
d = dict_to_object(d)
要build立在epool的答案上,这个版本允许你通过点运算符访问任何字典:
foo = { "bar" : { "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ] } }
例如, foo.bar.baz[1].baba
返回"loo"
。
class Map(dict): def __init__(self, *args, **kwargs): super(Map, self).__init__(*args, **kwargs) for arg in args: if isinstance(arg, dict): for k, v in arg.iteritems(): if isinstance(v, dict): v = Map(v) if isinstance(v, list): self.__convert(v) self[k] = v if kwargs: for k, v in kwargs.iteritems(): if isinstance(v, dict): v = Map(v) elif isinstance(v, list): self.__convert(v) self[k] = v def __convert(self, v): for elem in xrange(0, len(v)): if isinstance(v[elem], dict): v[elem] = Map(v[elem]) elif isinstance(v[elem], list): self.__convert(v[elem]) def __getattr__(self, attr): return self.get(attr) def __setattr__(self, key, value): self.__setitem__(key, value) def __setitem__(self, key, value): super(Map, self).__setitem__(key, value) self.__dict__.update({key: value}) def __delattr__(self, item): self.__delitem__(item) def __delitem__(self, key): super(Map, self).__delitem__(key) del self.__dict__[key]
我结束了尝试AttrDict和Bunch图书馆,发现他们的方式来减缓我的用途。 在朋友和我研究过之后,我们发现编写这些库的主要方法是通过一个嵌套的对象积极地recursion库并在整个过程中复制字典对象。 考虑到这一点,我们做了两个关键的改变。 1)我们使属性延迟加载2)而不是创build一个字典对象的副本,我们创build一个轻量级代理对象的副本。 这是最后的实施。 使用此代码的性能提高令人难以置信。 当使用AttrDict或Bunch时,这两个库单独使用我的请求时间的1/2和1/3(什么!?)。 这段代码把时间缩短到几乎没有(在0.5ms的范围内)。 这当然取决于你的需求,但是如果你在你的代码中使用了这个function,肯定要用这样简单的东西。
class DictProxy(object): def __init__(self, obj): self.obj = obj def __getitem__(self, key): return wrap(self.obj[key]) def __getattr__(self, key): try: return wrap(getattr(self.obj, key)) except AttributeError: try: return self[key] except KeyError: raise AttributeError(key) # you probably also want to proxy important list properties along like # items(), iteritems() and __len__ class ListProxy(object): def __init__(self, obj): self.obj = obj def __getitem__(self, key): return wrap(self.obj[key]) # you probably also want to proxy important list properties along like # __iter__ and __len__ def wrap(value): if isinstance(value, dict): return DictProxy(value) if isinstance(value, (tuple, list)): return ListProxy(value) return value
通过https://stackoverflow.com/users/704327/michael-merickel查看原始实施。;
另外要注意的是,这个实现非常简单,并没有实现你可能需要的所有方法。 您需要按照DictProxy或ListProxy对象的要求编写这些代码。
该解决scheme是对epool提供的解决scheme的改进,以满足OP以一致的方式访问嵌套字典的要求。 epool的解决scheme不允许访问嵌套的字典。
class YAMLobj(dict): def __init__(self, args): super(YAMLobj, self).__init__(args) if isinstance(args, dict): for k, v in args.iteritems(): if not isinstance(v, dict): self[k] = v else: self.__setattr__(k, YAMLobj(v)) def __getattr__(self, attr): return self.get(attr) def __setattr__(self, key, value): self.__setitem__(key, value) def __setitem__(self, key, value): super(YAMLobj, self).__setitem__(key, value) self.__dict__.update({key: value}) def __delattr__(self, item): self.__delitem__(item) def __delitem__(self, key): super(YAMLobj, self).__delitem__(key) del self.__dict__[key]
通过这门课,现在可以做一些类似于ABCD
事情。
我想把我自己的解决scheme扔进戒指:
https://github.com/skorokithakis/jsane
它允许你将JSONparsing成你可以访问的东西,主要是因为在开始工作之前我没有看到这个答案。
不直接回答OP的问题,但受到启发,也许对一些有用..我已经创build了一个基于对象的解决scheme,使用内部__dict__
(绝不优化代码)
payload = { "name": "John", "location": { "lat": 53.12312312, "long": 43.21345112 }, "numbers": [ { "role": "home", "number": "070-12345678" }, { "role": "office", "number": "070-12345679" } ] } class Map(object): """ Dot style access to object members, access raw values with an underscore eg class Foo(Map): def foo(self): return self.get('foo') + 'bar' obj = Foo(**{'foo': 'foo'}) obj.foo => 'foobar' obj._foo => 'foo' """ def __init__(self, *args, **kwargs): for arg in args: if isinstance(arg, dict): for k, v in arg.iteritems(): self.__dict__[k] = v self.__dict__['_' + k] = v if kwargs: for k, v in kwargs.iteritems(): self.__dict__[k] = v self.__dict__['_' + k] = v def __getattribute__(self, attr): if hasattr(self, 'get_' + attr): return object.__getattribute__(self, 'get_' + attr)() else: return object.__getattribute__(self, attr) def get(self, key): try: return self.__dict__.get('get_' + key)() except (AttributeError, TypeError): return self.__dict__.get(key) def __repr__(self): return u"<{name} object>".format( name=self.__class__.__name__ ) class Number(Map): def get_role(self): return self.get('role') def get_number(self): return self.get('number') class Location(Map): def get_latitude(self): return self.get('lat') + 1 def get_longitude(self): return self.get('long') + 1 class Item(Map): def get_name(self): return self.get('name') + " Doe" def get_location(self): return Location(**self.get('location')) def get_numbers(self): return [Number(**n) for n in self.get('numbers')] # Tests obj = Item({'foo': 'bar'}, **payload) assert type(obj) == Item assert obj._name == "John" assert obj.name == "John Doe" assert type(obj.location) == Location assert obj.location._lat == 53.12312312 assert obj.location._long == 43.21345112 assert obj.location.latitude == 54.12312312 assert obj.location.longitude == 44.21345112 for n in obj.numbers: assert type(n) == Number if n.role == 'home': assert n.number == "070-12345678" if n.role == 'office': assert n.number == "070-12345679"
我喜欢蒙克 ,它提供了很多方便的选项顶部的点访问。
import蒙克
temp_1 = {'person':{'fname':'senthil','lname':'ramalingam'}}
dict_munch = munch.munchify(temp_1)
dict_munch.person.fname