我已经开始使用这样的结构:
class DictObj(object):
def __init__(self):
self.d = {}
def __getattr__(self, m):
return self.d.get(m, None)
def __setattr__(self, m, v):
super.__setattr__(self, m, v)
更新:基于这个帖子,我已经将DictObj实现修改为:
class dotdict(dict):
def __getattr__(self, attr):
return self.get(attr, None)
__setattr__= dict.__setitem__
__delattr__= dict.__delitem__
class AutoEnum(object):
def __init__(self):
self.counter = 0
self.d = {}
def __getattr__(self, c):
if c not in self.d:
self.d[c] = self.counter
self.counter += 1
return self.d[c]
其中DictObj是一个可以通过点表示法访问的字典:
d = DictObj()
d.something = 'one'
我发现它比d['something']
更美观。请注意,访问未定义的键会返回None而不是引发异常,这也很不错。
更新:Smashery提出了一个很好的观点,mhawke扩展了更简单的解决方案。我想知道使用 dict 而不是定义新字典是否有任何不良副作用;如果没有,我很喜欢mhawke的解决方案。
AutoEnum是一个自动递增的枚举,使用如下:
CMD = AutoEnum()
cmds = {
"peek": CMD.PEEK,
"look": CMD.PEEK,
"help": CMD.HELP,
"poke": CMD.POKE,
"modify": CMD.POKE,
}
两者对我来说都很好,但我对他们感觉不熟悉。
这些实际上是不好的结构吗?
答案 0 :(得分:22)
你的DictObj例子实际上很常见。如果您正在处理“类似于对象的事物”,即对象样式的点符号访问可能是一个胜利。他们有固定的属性名称,只包含Python标识符中有效的字符。像数据库行或表单提交这样的东西可以有效地存储在这种对象中,使代码更具可读性,而不会超出['item access']。
实现有点受限 - 你没有得到dict,len(),comparisons,'in',iteration或nice reprs的漂亮的构造函数语法。你当然可以自己实现这些东西,但是在新式的类世界中你可以通过简单的子类化dict来免费获得它们:
class AttrDict(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
要获得default-to-None行为,只需将Python 2.5的collections.defaultdict类子类化为dict。
答案 1 :(得分:12)
关于DictObj
,以下哪项适合您?空白类允许您随意添加或替换容器对象中的内容。
class Container(object):
pass
>>> myContainer = Container()
>>> myContainer.spam = "in a can"
>>> myContainer.eggs = "in a shell"
如果您不想在没有属性时抛出AttributeError,您对以下内容有何看法?就个人而言,为了清晰起见,我更倾向于使用dict,或者使用try / except子句。
class QuietContainer(object):
def __getattr__(self, attribute):
try:
return object.__getattr__(self,attribute)
except AttributeError:
return None
>>> cont = QuietContainer()
>>> print cont.me
None
右?
答案 2 :(得分:8)
这是DictObj类的简单版本:
class DictObj(object):
def __getattr__(self, attr):
return self.__dict__.get(attr)
>>> d = DictObj()
>>> d.something = 'one'
>>> print d.something
one
>>> print d.somethingelse
None
>>>
答案 3 :(得分:3)
据我所知,Python类使用字典来存储它们的属性(这是程序员隐藏的),因此我认为你在那里所做的就是有效地模拟Python类...使用python类。
答案 4 :(得分:3)
这样做并不是“错误的”,如果你的词典很有可能在某些时候变成对象,那就更好了,但要注意首先拥有括号的原因:
另请注意,如果您决定稍后切换到对象,则可以随时让对象像字典一样访问。
对于这样的情况,我会默认使用“可读性计数”的口头禅:大概是其他Python程序员会阅读你的代码,他们可能不会期望到处都是字典/对象混合。如果这是针对特定情况的良好设计决策,请使用它,但我不会在没有必要的情况下使用它。
答案 5 :(得分:2)
使用像DictObj这样的东西的一个主要缺点是你要么必须限制允许的密钥,要么你的DictObj上没有方法,例如.keys()
,.values()
,.items()
等等。
答案 6 :(得分:2)
class dotdict(dict):
__getattr__= dict.__getitem__
__setattr__= dict.__setitem__
__delattr__= dict.__delitem__
相同的界面,只是以相反的方式实现...
class container(object):
__getitem__ = object.__getattribute__
__setitem__ = object.__setattr__
__delitem__ = object.__delattr__
答案 7 :(得分:1)
我喜欢点符号比字典字段更好。原因是它使自动完成工作更好。
答案 8 :(得分:1)
如果它符合您的目的,那也不错。 “实用性胜过纯洁”。
我在elserwhere看到了这样的方法(例如在Paver中),所以这可以被认为是普遍需要(或欲望)。
答案 9 :(得分:1)
不要忽视Bunch。
它是字典的子节点,可以导入YAML或JSON,或将任何现有字典转换为Bunch,反之亦然。一旦“束缚”'d,字典就会获得点符号,而不会丢失任何其他字典方法。
答案 10 :(得分:0)
因为你要求不良副作用:
缺点是在像eclipse + pyDev这样的可视编辑器中,你会在使用点表示法的行上看到许多未定义的变量错误。 Pydef将无法找到此类运行时“对象”定义。而在普通字典的情况下,它知道您只是在获取字典条目。
你需要1)忽略那些错误,并与红十字会生活在一起; 2)使用#@ UndefinedVariable逐行抑制这些警告或3)完全禁用未定义的变量错误,导致您错过真正的未定义变量定义。
答案 11 :(得分:0)
如果您正在寻找可处理嵌套字典的替代方法:
将字典递归转换为所需类的实例
import json
from collections import namedtuple
class DictTransformer():
@classmethod
def constantize(self, d):
return self.transform(d, klass=namedtuple, klassname='namedtuple')
@classmethod
def transform(self, d, klass, klassname):
return self._from_json(self._to_json(d), klass=klass, klassname=klassname)
@classmethod
def _to_json(self, d, access_method='__dict__'):
return json.dumps(d, default=lambda o: getattr(o, access_method, str(o)))
@classmethod
def _from_json(self, jsonstr, klass, klassname):
return json.loads(jsonstr, object_hook=lambda d: klass(klassname, d.keys())(*d.values()))
例如:
constants = {
'A': {
'B': {
'C': 'D'
}
}
}
CONSTANTS = DictTransformer.transform(d, klass=namedtuple, klassname='namedtuple')
CONSTANTS.A.B.C == 'D'
优点:
缺点:
.keys
和.values
,则它们可能不会做出响应(尽管有时您可以模仿._fields
和list(A.B.C)
)有想法吗?
将h / t发送给@hlzr,以获取原始的课堂想法