有时候能够像对象一样使用字典会很好(所以你不必总是写mydict['blah']
。相反,你可以写mydict.blah
< / p>
在Python 3中,有关于覆盖/包装python字典的新规则。在Python2中,它足以包装__getattr__
和__setattr__
方法。当你包装这些东西时,你会得到一些很好的功能,可以在添加某个属性时添加一些特殊处理(例如,你可以清理/过滤dict中的数据)。
这有用的情况是在Flask模板(HTML模板)中。使用__getattr__
过滤器,您可以在数据离开dict
时格式化数据。这样,在模板中(Python表达式看起来有点复杂),只需编写mymodel.blah
并且知道来自blah
的文本已经是您想要的方式,就可以使事情变得简单它
在Python3中包装dict
有点乱。我现在还不确定如何让它发挥作用。以下是两个不能正常运行的粗略实现:
# messed up Python3 wrapped dictionary (sets work, but gets do not)
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
self.clean_strings()
def clean_strings(self):
for key, value in self.items():
self[key] = string_empty_to_none(value)
def __getattr__(self, name):
#this never gets called in Python 3
return self[name]
这是另一个:
# sets don't work - Always throws: TypeError: 'AttrDict' object does not support item assignment
class AttrDict():
def __init__(self, *args, **kwargs):
self.data = dict()
self.data.__init__(*args, **kwargs)
self.clean_strings()
def clean_strings(self):
for key, value in self.data.items():
self.data[key] = string_empty_to_none(value)
def __getattr__(self, attr):
if attr in self.data:
return self.data[attr]
else:
raise AttributeError("--%r object has no attribute %r" % (type(self).__name__, attr))
def __setattr__(self, name, value):
if name == 'data':
super(AttrDict, self).__setattr__(name, value)
else:
self.data[name] = value
这是我的小实用工具的样子:
def string_empty_to_none(s):
if type(s) == str:
return None if (s.strip() == '') else s
return s
我知道在Python3中,你应该使用__getattribute__
而不是__getattr__
但是当我这样做时,它似乎总是在无限循环中结束。
注意:我正在寻找的最终语法是这样的:
>>> x = AttrDict({'some': 'value'})
>>> x['blah'] = 'hello world'
>>> print(x.blah)
hello world
>>> print(x.some)
value
答案 0 :(得分:1)
实际上,不需要在self.__dict__
继承类的__init__
方法中进行dict
分配 - 只需执行通常的arg传递给super()
,然后你的处理。实际上我甚至不确定self.__dict__ = self
意味着什么 - 我可以想象,如果你压倒他们的__dict__
(即使他们的self
es&#34,它会打破一些内部行为。 #34;。)
最好修改__getattr__
方法,因为如果__getattribute__
找不到任何内容,这将是Python的回退方法。另一方面,如果您知道自己大部分时间都在使用属性样式的访问者,那么您可以切换该逻辑。
请参阅以下示例:
def string_empty_to_none(s):
if type(s) == str:
return None if (s.strip() == '') else s
return s
# This will always have issues, even in IDE's
print('AttrDict')
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
self.clean_strings()
def clean_strings(self):
for key, value in self.items():
self[key] = string_empty_to_none(value)
test = AttrDict({'a': 1})
test['x'] = 2
test.z = ""
print(test.a)
print(test['a'])
print(test.x)
print(test['x'])
print(test.z)
print(test['z'])
print('MostlyPropertiesAccessDict')
class MostlyPropertiesAccessDict(dict):
def __init__(self, *args, **kwargs):
# No need for the self.__dict__ part
super().__init__(*args, **kwargs)
self.clean_strings()
def clean_strings(self):
for key, value in self.items():
self[key] = string_empty_to_none(value)
def __getattr__(self, name):
if not name in self:
raise AttributeError(
"Attribute {} does not exist".format(name))
return self[name]
def __setattr__(self, name, value):
self[name] = string_empty_to_none(value)
def __delattr__(self, name):
if not name in self:
raise AttributeError(
"Attribute {} does not exist".format(name))
del self[name]
test2 = MostlyPropertiesAccessDict({'a': 1})
test2['x'] = 2
test2.z = ""
print(test2.a)
print(test2['a'])
print(test2.x)
print(test2['x'])
print(test2.z)
print(test2['z'])
print("MostlyKeysAccessDict")
class MostlyKeysAccessDict(dict):
def __init__(self, *args, **kwargs):
# No need for the self.__dict__ part
super().__init__(*args, **kwargs)
self.clean_strings()
def clean_strings(self):
for key, value in self.items():
self[key] = string_empty_to_none(value)
def __getattribute__(self, name):
if not name in self:
raise AttributeError(
"Attribute {} does not exist".format(name))
return self[name]
def __getattr__(self, name):
return super().__getattribute__(name)
def __setattr__(self, name, value):
self[name] = string_empty_to_none(value)
def __delattr__(self, name):
if not name in self:
raise AttributeError(
"Attribute {} does not exist".format(name))
del self[name]
test3 = MostlyKeysAccessDict({'a': 1})
test3['x'] = 2
test3.z = ""
print(test3.a)
print(test3['a'])
print(test3.x)
print(test3['x'])
print(test3.z)
print(test3['z'])
答案 1 :(得分:0)
您可以使用__getitem__
内的__getattr__
覆盖来实现此目的。
class AttrDict(dict):
def __getattr__(self, item):
return super().__getitem__(item)
def __setattr__(self, item, value):
return super().__setitem__(item, value)
x = AttrDict({'some': 'value'})
x['blah'] = 'hello world'
print(x.blah) # hello world
print(x.some) # value
# you can also assign value this way
x.foo = 'bar'
print(x['foo']) # bar
答案 2 :(得分:0)
您需要做的就是创建一个包含字典的包装类,然后实现__getitem__
:
class DictionaryWrapper():
_dict = {"key1": "value1", "key2": "value2"}
def __getitem__(self, item):
return self._dict[item]
@attribute
def key1(self):
return self._dict["key1"]
现在,您可以将DictionartWrapper视为字典。 (此受限的实现方式仅允许阅读。)
my_dictionary = DictionaryWrapper()
print(my_dictionary["key1"])
如果字典中的键是已知的,您甚至可以通过包装类上的属性公开它们的值。
print(my_dictionary.key1)
有关类似的讨论,请参见here。