我如何使Python字典成员访问通过点“。”?
例如,我想写mydict.val而不是mydict['val']。
我还想以这种方式访问嵌套字典。例如
mydict.mydict2.val
会提到
mydict = { 'mydict2': { 'val': ... } }
我如何使Python字典成员访问通过点“。”?
例如,我想写mydict.val而不是mydict['val']。
我还想以这种方式访问嵌套字典。例如
mydict.mydict2.val
会提到
mydict = { 'mydict2': { 'val': ... } }
当前回答
获得点访问(但不是数组访问)的一个简单方法是在Python中使用一个普通对象。是这样的:
class YourObject:
def __init__(self, *args, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
...像这样使用它:
>>> obj = YourObject(key="value")
>>> print(obj.key)
"value"
... 把它转换成字典:
>>> print(obj.__dict__)
{"key": "value"}
其他回答
派生自dict和并实现__getattr__和__setattr__。
或者你也可以用Bunch,非常相似。
我不认为这是可能的monkeypatch内置字典类。
我喜欢Munch,它提供了很多方便的选项在点访问。
进口蒙克 Temp_1 = {'person': {' fname': 'senthil', 'lname': 'ramalingam'}} Dict_munch = munch.munchify(temp_1) dict_munch.person.fname
这是我对@derek73的回答。我用字典。__getitem__作为__getattr__,因此它仍然抛出KeyError,并且im重命名字典公共方法以“”前缀(“”包围导致特殊方法名称冲突,如__get__将被视为一个描述符方法)。无论如何,由于关键的dict基方法,您无法将键作为属性获得完全清晰的命名空间,因此解决方案并不完美,但您可以拥有键属性,如get, pop, items等。
class DotDictMeta(type):
def __new__(
cls,
name,
bases,
attrs,
rename_method=lambda n: f'__{n}__',
**custom_methods,
):
d = dict
attrs.update(
cls.get_hidden_or_renamed_methods(rename_method),
__getattr__=d.__getitem__,
__setattr__=d.__setitem__,
__delattr__=d.__delitem__,
**custom_methods,
)
return super().__new__(cls, name, bases, attrs)
def __init__(self, name, bases, attrs, **_):
super().__init__(name, bases, attrs)
@property
def attribute_error(self):
raise AttributeError
@classmethod
def get_hidden_or_renamed_methods(cls, rename_method=None):
public_methods = tuple(
i for i in dict.__dict__.items() if not i[0].startswith('__')
)
error = cls.attribute_error
hidden_methods = ((k, error) for k, v in public_methods)
yield from hidden_methods
if rename_method:
renamed_methods = ((rename_method(k), v) for k, v in public_methods)
yield from renamed_methods
class DotDict(dict, metaclass=DotDictMeta):
pass
你可以从DotDict命名空间中删除dict方法,并继续使用dict类方法,当你想操作其他dict实例并希望使用相同的方法而不需要额外检查它是否为DotDict时,它也很有用。
dct = dict(a=1)
dot_dct = DotDict(b=2)
foo = {c: i for i, c in enumerate('xyz')}
for d in (dct, dot_dct):
# you would have to use dct.update and dot_dct.__update methods
dict.update(d, foo)
assert dict.get(dot, 'foo', 0) is 0
我不喜欢在(超过)10年前的火灾中添加另一个日志,但我也会检查dotwiz库,它是我最近发布的——实际上就在今年。
它是一个相对较小的库,在基准测试中,它在get(访问)和设置(创建)时间方面也表现得非常好,至少与其他备选方案相比是这样。
通过pip安装dotwiz
pip install dotwiz
它能做你想让它做的所有事情,并继承dict的子类,所以它的操作就像一个普通的字典:
from dotwiz import DotWiz
dw = DotWiz()
dw.hello = 'world'
dw.hello
dw.hello += '!'
# dw.hello and dw['hello'] now both return 'world!'
dw.val = 5
dw.val2 = 'Sam'
最重要的是,你可以将它转换为dict对象:
d = dw.to_dict()
dw = DotWiz(d) # automatic conversion in constructor
这意味着如果你想访问的东西已经是dict形式的,你可以把它变成一个dotwz来方便访问:
import json
json_dict = json.loads(text)
data = DotWiz(json_dict)
print data.location.city
最后,我正在做的一些令人兴奋的事情是一个现有的特性请求,这样它就会自动创建新的子DotWiz实例,这样你就可以做这样的事情:
dw = DotWiz()
dw['people.steve.age'] = 31
dw
# ✫(people=✫(steve=✫(age=31)))
与点图比较
我在下面添加了一个快速而粗略的性能比较。
首先,用pip安装两个库:
pip install dotwiz dotmap
为了进行基准测试,我编写了以下代码:
from timeit import timeit
from dotwiz import DotWiz
from dotmap import DotMap
d = {'hey': {'so': [{'this': {'is': {'pretty': {'cool': True}}}}]}}
dw = DotWiz(d)
# ✫(hey=✫(so=[✫(this=✫(is=✫(pretty={'cool'})))]))
dm = DotMap(d)
# DotMap(hey=DotMap(so=[DotMap(this=DotMap(is=DotMap(pretty={'cool'})))]))
assert dw.hey.so[0].this['is'].pretty.cool == dm.hey.so[0].this['is'].pretty.cool
n = 100_000
print('dotwiz (create): ', round(timeit('DotWiz(d)', number=n, globals=globals()), 3))
print('dotmap (create): ', round(timeit('DotMap(d)', number=n, globals=globals()), 3))
print('dotwiz (get): ', round(timeit("dw.hey.so[0].this['is'].pretty.cool", number=n, globals=globals()), 3))
print('dotmap (get): ', round(timeit("dm.hey.so[0].this['is'].pretty.cool", number=n, globals=globals()), 3))
结果,在我的M1 Mac上运行Python 3.10:
dotwiz (create): 0.189
dotmap (create): 1.085
dotwiz (get): 0.014
dotmap (get): 0.335
使用SimpleNamespace:
>>> from types import SimpleNamespace
>>> d = dict(x=[1, 2], y=['a', 'b'])
>>> ns = SimpleNamespace(**d)
>>> ns.x
[1, 2]
>>> ns
namespace(x=[1, 2], y=['a', 'b'])