[英]How to use dot notation for dict in python?
我是 python 的新手,我希望我能做到.
訪問dict
值的符號。
可以說我有這樣的test
:
>>> test = dict()
>>> test['name'] = 'value'
>>> print(test['name'])
value
但我希望我可以做test.name
來獲得value
。 事實上,我是通過重寫 class 中的__getattr__
方法來實現的,如下所示:
class JuspayObject:
def __init__(self,response):
self.__dict__['_response'] = response
def __getattr__(self,key):
try:
return self._response[key]
except KeyError,err:
sys.stderr.write('Sorry no key matches')
這有效:當我這樣做時:
test.name // I get value.
但問題是當我單獨打印test
時,我得到的錯誤是:
'Sorry no key matches'
為什么會這樣?
此功能已存在於標准庫中,因此我建議您只使用它們的類。
>>> from types import SimpleNamespace
>>> d = {'key1': 'value1', 'key2': 'value2'}
>>> n = SimpleNamespace(**d)
>>> print(n)
namespace(key1='value1', key2='value2')
>>> n.key2
'value2'
添加、修改和刪除值是通過常規屬性訪問實現的,即您可以使用諸如n.key = val
和del n.key
類的語句。
再次回到字典:
>>> vars(n)
{'key1': 'value1', 'key2': 'value2'}
dict 中的鍵應該是字符串標識符,以便屬性訪問正常工作。
在 Python 3.3 中添加了簡單命名空間。 對於舊版本的語言, argparse.Namespace
具有類似的行為。
我假設您對 Javascript 很熟悉並想借用這種語法……我可以根據個人經驗告訴您,這不是一個好主意。
它確實看起來不那么冗長和整潔; 但從長遠來看,它只是晦澀難懂。 字典就是字典,試圖讓它們表現得像具有屬性的對象可能會導致(壞的)意外。
如果您需要像操作字典一樣操作對象的字段,您可以隨時在需要時使用內部的__dict__
屬性,然后清楚地知道您在做什么。 或者使用getattr(obj, 'key')
來考慮繼承結構和類屬性。
但是通過閱讀您的示例,您似乎正在嘗試不同的東西......因為點運算符已經在__dict__
屬性中查找而無需任何額外代碼。
除了這個答案之外,還可以添加對嵌套字典的支持:
from types import SimpleNamespace
class NestedNamespace(SimpleNamespace):
def __init__(self, dictionary, **kwargs):
super().__init__(**kwargs)
for key, value in dictionary.items():
if isinstance(value, dict):
self.__setattr__(key, NestedNamespace(value))
else:
self.__setattr__(key, value)
nested_namespace = NestedNamespace({
'parent': {
'child': {
'grandchild': 'value'
}
},
'normal_key': 'normal value',
})
print(nested_namespace.parent.child.grandchild) # value
print(nested_namespace.normal_key) # normal value
請注意,這不支持列表中某處的字典的點表示法。
你可以使用命名元組嗎?
from collections import namedtuple
Test = namedtuple('Test', 'name foo bar')
my_test = Test('value', 'foo_val', 'bar_val')
print(my_test)
print(my_test.name)
當所有其他屬性查找規則都失敗時, __getattr__
用作后備。 當你嘗試“打印”你的對象時,Python 會尋找一個__repr__
方法,並且由於你沒有在你的類中實現它,它最終會調用__getattr__
(是的,在 Python 中方法也是屬性)。 您不應該假設將使用哪個鍵getattr來調用,最重要的是,如果__getattr__
無法解析key
,它必須引發 AttributeError 。
作為旁注:不要使用self.__dict__
進行普通屬性訪問,只需使用普通屬性表示法:
class JuspayObject:
def __init__(self,response):
# don't use self.__dict__ here
self._response = response
def __getattr__(self,key):
try:
return self._response[key]
except KeyError,err:
raise AttributeError(key)
現在,如果您的班級沒有其他責任(並且您的 Python 版本 >= 2.6,並且您不需要支持舊版本),您可以只使用命名元組:http: //docs.python.org/2/library/ collections.html#collections.namedtuple
您可以使用內置方法argparse.Namespace()
:
import argparse
args = argparse.Namespace()
args.name = 'value'
print(args.name)
# 'value'
您還可以通過vars(args)
獲取原始字典。
使用__getattr__
時必須小心,因為它用於許多內置的 Python 功能。
嘗試這樣的事情......
class JuspayObject:
def __init__(self,response):
self.__dict__['_response'] = response
def __getattr__(self, key):
# First, try to return from _response
try:
return self.__dict__['_response'][key]
except KeyError:
pass
# If that fails, return default behavior so we don't break Python
try:
return self.__dict__[key]
except KeyError:
raise AttributeError, key
>>> j = JuspayObject({'foo': 'bar'})
>>> j.foo
'bar'
>>> j
<__main__.JuspayObject instance at 0x7fbdd55965f0>
這是一個使用嵌套項的簡單、方便的點表示法幫助器示例:
def dict_get(data:dict, path:str, default = None):
pathList = re.split(r'\.', path, flags=re.IGNORECASE)
result = data
for key in pathList:
try:
key = int(key) if key.isnumeric() else key
result = result[key]
except:
result = default
break
return result
使用示例:
my_dict = {"test1": "str1", "nested_dict": {"test2": "str2"}, "nested_list": ["str3", {"test4": "str4"}]}
print(dict_get(my_dict, "test1"))
# str1
print(dict_get(my_dict, "nested_dict.test2"))
# str2
print(dict_get(my_dict, "nested_list.1.test4"))
# str4
class convert_to_dot_notation(dict):
"""
Access dictionary attributes via dot notation
"""
__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
test = {"name": "value"}
data = convert_to_dot_notation(test)
print(data.name)
對這個答案做一點補充,你也可以支持列表:
class NestedNamespace(SimpleNamespace):
def __init__(self, dictionary, **kwargs):
super().__init__(**kwargs)
for key, value in dictionary.items():
if isinstance(value, dict):
self.__setattr__(key, NestedNamespace(value))
elif isinstance(value, list):
self.__setattr__(key, map(NestedNamespace, value))
else:
self.__setattr__(key, value)
我使用dotted_dict
包:
>>> from dotted_dict import DottedDict
>>> test = DottedDict()
>>> test.name = 'value'
>>> print(test.name)
value
向類添加__repr__()
方法,以便您可以自定義要顯示的文本
print text
在這里了解更多信息: https ://web.archive.org/web/20121022015531/http://diveintopython.net/object_orient_framework/special_class_methods2.html
#!/usr/bin/env python3
import json
from sklearn.utils import Bunch
from collections.abc import MutableMapping
def dotted(inpt: MutableMapping,
*args,
**kwargs
) -> Bunch:
"""
Enables recursive dot notation for ``dict``.
"""
return json.loads(json.dumps(inpt),
object_hook=lambda x:
Bunch(**{**Bunch(), **x}))
2022 回答:我創建了dotwiz
包——這是一個快速、小巧的庫,在大多數情況下似乎表現得非常好。
>>> from dotwiz import DotWiz
>>> test = DotWiz(hello='world')
>>> test.works = True
>>> test
✫(hello='world', works=True)
>>> test.hello
'world'
>>> assert test.works
此功能已嵌入到OmegaConf 中:
from omegaconf import OmegaConf
your_dict = {"k" : "v", "list" : [1, {"a": "1", "b": "2", 3: "c"}]}
adot_dict = OmegaConf.create(your_dict)
print(adot_dict.k)
print(adot_dict.list)
安裝是:
pip install omegaconf
這個庫對於配置很方便,它實際上是為:
from omegaconf import OmegaConf
cfg = OmegaConf.load('config.yml')
print(cfg.data_path)
您可以使向 Dicts 添加點符號的 hacks 大部分工作,但總是存在名稱空間問題。 比如,這是做什么的?
x = DotDict()
x["values"] = 1989
print(x. values)
我使用pydash ,它是 JS 的 lodash 的 Python 端口,當嵌套變得太丑陋時,我會以不同的方式做這些事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.