字典键unpythonic的Javascript样式点表示法?

时间:2008-10-22 00:08:01

标签: python coding-style

我已经开始使用这样的结构:

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,
}

两者对我来说都很好,但我对他们感觉不熟悉。

这些实际上是不好的结构吗?

12 个答案:

答案 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)

这样做并不是“错误的”,如果你的词典很有可能在某些时候变成对象,那就更好了,但要注意首先拥有括号的原因:

  1. 点访问不能使用关键字作为键。
  2. 点访问必须在键中使用Python标识符有效字符。
  3. 字典可以包含任何可清除元素 - 而不仅仅是字符串。
  4. 另请注意,如果您决定稍后切换到对象,则可以随时让对象像字典一样访问。

    对于这样的情况,我会默认使用“可读性计数”的口头禅:大概是其他Python程序员会阅读你的代码,他们可能不会期望到处都是字典/对象混合。如果这是针对特定情况的良好设计决策,请使用它,但我不会在没有必要的情况下使用它。

答案 5 :(得分:2)

使用像DictObj这样的东西的一个主要缺点是你要么必须限制允许的密钥,要么你的DictObj上没有方法,例如.keys().values().items()等等。

答案 6 :(得分:2)

thisthis之间存在对称性:

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,则它们可能不会做出响应(尽管有时您可以模仿._fieldslist(A.B.C)

有想法吗?

将h / t发送给@hlzr,以获取原始的课堂想法