我发现它更方便访问字典键作为obj。foo而不是obj['foo'],所以我写了这个片段:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
然而,我认为一定有一些原因,Python没有提供开箱即用的功能。以这种方式访问字典键的注意事项和缺陷是什么?
product怎么样,我写了一个小小的Python类来统治它们:)
此外,您还可以获得自动代码完成、递归对象实例化和自动类型转换!
你完全可以做到你所要求的:
p = Prodict()
p.foo = 1
p.bar = "baz"
例1:类型提示
class Country(Prodict):
name: str
population: int
turkey = Country()
turkey.name = 'Turkey'
turkey.population = 79814871
例2:自动类型转换
germany = Country(name='Germany', population='82175700', flag_colors=['black', 'red', 'yellow'])
print(germany.population) # 82175700
print(type(germany.population)) # <class 'int'>
print(germany.flag_colors) # ['black', 'red', 'yellow']
print(type(germany.flag_colors)) # <class 'list'>
为了给答案增加一些变化,sci-kit learn将其实现为一串:
class Bunch(dict):
""" Scikit Learn's container object
Dictionary-like object that exposes its keys as attributes.
>>> b = Bunch(a=1, b=2)
>>> b['b']
2
>>> b.b
2
>>> b.c = 6
>>> b['c']
6
"""
def __init__(self, **kwargs):
super(Bunch, self).__init__(kwargs)
def __setattr__(self, key, value):
self[key] = value
def __dir__(self):
return self.keys()
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __setstate__(self, state):
pass
您所需要的是获取setattr和getattr方法—getattr检查字典键,然后继续检查实际属性。setstaet是针对pickle /unpickling“bunch”的修复-如果感兴趣,请检查https://github.com/scikit-learn/scikit-learn/issues/6196
以这种方式访问字典键的注意事项和缺陷是什么?
正如@Henry所指出的,在dict中不能使用点访问的一个原因是,它将dict键名限制为python有效变量,从而限制了所有可能的名称。
下面是一些例子,说明为什么在给定字典d的情况下,点点访问通常没有帮助:
有效性
以下属性在Python中是无效的:
d.1_foo # enumerated names
d./bar # path names
d.21.7, d.12:30 # decimals, time
d."" # empty strings
d.john doe, d.denny's # spaces, misc punctuation
d.3 * x # expressions
风格
PEP8约定将对属性命名施加软约束:
A.保留关键字(或内置函数)名称:
d.in
d.False, d.True
d.max, d.min
d.sum
d.id
如果函数参数的名称与保留关键字冲突,通常最好在后面添加一个下划线…
B.方法和变量名的大小写规则:
变量名遵循与函数名相同的约定。
d.Firstname
d.Country
使用函数命名规则:小写字母,单词之间用下划线分隔,以提高可读性。
有时,在pandas这样的库中会出现这些问题,这些库允许按名称点访问DataFrame列。解决命名限制的默认机制也是数组表示法——括号中的字符串。
如果这些约束不适用于您的用例,那么在点访问数据结构上有几个选项。
编辑:NeoBunch是废弃的,Munch(上面提到过)可以作为一个替代品。不过,我把这个解决方案留在这里,它可能对某些人有用。
正如Doug所指出的,有一个Bunch包,你可以使用它来实现obj。关键功能。实际上有一个更新的版本叫做
尼奥邦克·蒙克
它有一个伟大的功能,通过neobunchify函数将你的字典转换为NeoBunch对象。我经常使用Mako模板,将数据作为NeoBunch对象传递使它们更具可读性,所以如果你碰巧在你的Python程序中使用了一个普通的字典,但想要在Mako模板中使用点符号,你可以这样使用:
from mako.template import Template
from neobunch import neobunchify
mako_template = Template(filename='mako.tmpl', strict_undefined=True)
data = {'tmpl_data': [{'key1': 'value1', 'key2': 'value2'}]}
with open('out.txt', 'w') as out_file:
out_file.write(mako_template.render(**neobunchify(data)))
Mako模板看起来像这样:
% for d in tmpl_data:
Column1 Column2
${d.key1} ${d.key2}
% endfor