我正在用 python 撰寫一個類,它結合了 dict、defaultdict 和 SimpleNamespace 的功能
到目前為止,我有以下代碼:
import warnings
class fluiddict:
"""! A class that emulates a dictionary, while also being able to support attribute assignment and default values.
The default value of `default_factory` is None. This means a KeyError will be raised when non-existent data is requested
To specify a default value of None, use `default_factory=lambda key: None`
"""
def __contains__(self, key):
return key in self.datastore
def __getitem__(self,key):
if self.raise_KeyError and key not in self.datastore:
raise KeyError(f"Key '{key}' was not found in the datastore and no default factory was provided.")
if key not in self.datastore:
try:
return self.default_factory(key)
except Exception as e:
print("An unknown exception occured while trying to provide a default value. Is your default factory valid?")
raise e
return self.datastore[key]
def __setitem__(self,key,value):
self.datastore[key] = value
def __delitem__(self, key):
if key not in self.datastore:
if not self.bypass_del_KeyError:
raise KeyError(f"Key {key} was not found in the datastore.")
else:
warnings.warn(f"Attemping to delete nonexistent key {key} in the datastore. Ignoring del statement...")
else:
del self.datastore[key]
def is_defined(self,key):
return key in self.datastore
def is_set(self,key): #PHP-style `isset` function
return key in self.datastore and key is not None
def __init__(self, default_factory =None, bypass_del_KeyError=False):
self.datastore = {}
self.raise_KeyError = False
if default_factory is None:
self.raise_KeyError = True
self.bypass_del_KeyError = bypass_del_KeyError
代碼有效,但我無法弄清楚如何撰寫一個__getattr__or__setattr__函式來提供類似 SimpleNamespace 的功能而無需無限遞回。
使用以下附加代碼,我得到一個無限遞回錯誤。我認為這是因為self.語法__getattr__在幕后呼叫。我覺得這很奇怪,因為我在其他 SO 帖子中看到__setattr__并且只有在屬性未正常找到__getattr__時才會被呼叫。
如果我添加代碼:
def __getattr__(self,attr_name):
return self.__getitem__(attr_name)
def __setattr__(self,attr_name,value):
self.__setitem__(attr_name,value)
我得到以下追溯:
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 30, in __getattr__
return self.__getitem__(attr_name)Lab
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 14, in __getitem__
if self.raise_KeyError and key not in self.datastore:
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 30, in __getattr__
return self.__getitem__(attr_name)
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 14, in __getitem__
if self.raise_KeyError and key not in self.datastore:
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 30, in __getattr__
return self.__getitem__(attr_name)
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 14, in __getitem__
if self.raise_KeyError and key not in self.datastore:
File "G:\My Drive\Image Processing\Mapping Project\core\types.py", line 30, in __getattr__
return self.__getitem__(attr_name)
RecursionError: maximum recursion depth exceeded
任何幫助表示贊賞。
uj5u.com熱心網友回復:
我認為這實作了你想要的。您可以呼叫基類__setattr__以允許寫入。
class xdict:
def __init__(self):
self.datastore = {}
def __getitem__(self,key):
if key not in self.datastore:
raise KeyError(f'{key} not found')
if key not in self.datastore:
self.datastore[key] = 7
return self.datastore[key]
def __setitem__(self,key,value):
self.datastore[key] = value
def __delitem__(self,key):
if key not in self.datastore:
raise KeyError(f'{key} not found')
del self.datastore[key]
def __getattr__(self,attr):
print("getattr",attr)
if attr == 'datastore':
return getattr(self,attr)
return getattr(self,'datastore')[attr]
def __setattr__(self,attr,val):
print("setattr",attr)
if attr == 'datastore':
object.__setattr__(self,'datastore',val)
else:
getattr(self,'datastore')[attr] = val
x = xdict()
x['one'] = 'one'
x.one = 'seven'
print(x['one'])
print(x.one)
print(x['two'])
uj5u.com熱心網友回復:
好的,感謝@tdelaney 和@Tim Roberts 幫助解決這個問題。我想發布我開始作業的最終代碼,只是為了幫助其他人。
import warnings
class fluiddict:
MEMBER_ATTRIBUTE_LIST = [
"raise_KeyError",
"datastore",
"default_factory",
"bypass_del_KeyError",
"__getstate__" # Comes from pickling
]
"""! A class that emulates a dictionary, while also being able to support attribute assignment and default values.
The default value of `default_factory` is None. This means a KeyError will be raised when non-existent data is requested
To specify a default value of None, use `default_factory=lambda key: None`
"""
def __contains__(self, key):
return self.is_defined(key)
def __getitem__(self,key):
if self.raise_KeyError and key not in self.datastore:
raise KeyError(f"Key '{key}' was not found in the datastore and no default factory was provided.")
if key not in self.datastore:
try:
return self.default_factory(key)
except Exception as e:
print("An unknown exception occured while trying to provide a default value. Is your default factory valid?")
raise e
return self.datastore[key]
def __setitem__(self,key,value):
self.datastore[key] = value
def __getattr__(self, attr_name):
if attr_name in fluiddict.MEMBER_ATTRIBUTE_LIST:
return object.__getattr__(self,attr_name)
return self.__getitem__(attr_name)
def __setattr__(self,attr_name,value):
if attr_name in fluiddict.MEMBER_ATTRIBUTE_LIST:
object.__setattr__(self,attr_name,value)
else:
self.__setitem__(attr_name,value)
def __delitem__(self, key):
if key not in self.datastore:
if not self.bypass_del_KeyError:
raise KeyError(f"Key {key} was not found in the datastore.")
else:
warnings.warn(f"Attemping to delete nonexistent key {key} in the datastore. Ignoring del statement...")
else:
del self.datastore[key]
def is_defined(self,key):
return key in self.datastore
def is_set(self,key): #PHP-style `isset` function
return key in self.datastore and self.datastore[key] is not None
def __init__(self, default_factory =None, bypass_del_KeyError=False):
self.datastore = {}
self.raise_KeyError = False
if default_factory is None:
self.raise_KeyError = True
self.bypass_del_KeyError = bypass_del_KeyError
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/534508.html
標籤:Pythonpython-3.x字典默认指令python-简单命名空间
下一篇:根據另一個字典的鍵名創建新字典
