Python dict 使用点符号和链接

标签 python dictionary syntax

理想情况下,我要完成的是一个扩展(或非常类似于)Python 中的 dict 并具有附加功能的类:

  • 能够设置和获取值的 Dot-Notation
  • 键值功能,如 dict(即 setitem、getitem)
  • 可以链接点标记的操作

目标是如果我有类似 example = DotDict() 的东西,我可以针对它执行以下操作 example.configuration.first= 'first' 并且它会实例化example 下适当的 DotDict 实例,真正痛苦的警告是,如果操作不是赋值,它应该像 dict 一样简单地引发 KeyError

这是我天真地组装的

class DotDict(dict):
    def __getattr__(self, key):
        """ Make attempts to lookup by nonexistent attributes also attempt key lookups. """
        import traceback
        import re
        s= ''.join(traceback.format_stack(sys._getframe(1),1))
        if re.match(r'  File.*\n.*[a-zA-Z]+\w*\.[a-zA-Z]+[a-zA-Z0-9_. ]*\s*=\s*[a-zA-Z0-9_.\'"]+',s):
            self[key] = DotDict()
            return self[key]

        return self[key]

    def __setattr__(self, key, value):
        if isinstance(value,dict):
            self[key] = DotDict(value)
        self[key] = value

除了一些常见的边缘情况外它都有效,我必须说我绝对讨厌这种方法并且必须有更好的方法。查看堆栈并在最后一行运行正则表达式并不是完成此任务的好方法。

问题的核心是 Python 从左到右解释代码行,所以当它到达像 a.b.c = 3 这样的语句时,它的第一个操作是 getattr(a,b) 而不是 setattr 所以我无法轻易确定操作堆栈中的最后一个操作是否是赋值。

我想知道的是,是否有一种好方法可以确定操作堆栈中的最后一个操作,或者至少它是否是 setattr

编辑:

这是我在 user1320237 的推荐下得出的解决方案。

class DotDict(dict):
    def __getattr__(self, key):
        """ Make attempts to lookup by nonexistent attributes also attempt key lookups. """
        if self.has_key(key):
            return self[key]
        import sys
        import dis
        frame = sys._getframe(1)
        if '\x00%c' % dis.opmap['STORE_ATTR'] in frame.f_code.co_code:
            self[key] = DotDict()
            return self[key]

        raise AttributeError('Problem here')

    def __setattr__(self, key, value):
        if isinstance(value,dict):
            self[key] = DotDict(value)
        self[key] = value

实际实现中还有一些内容,但效果非常好。它的工作方式是检查堆栈中的最后一帧并检查 STORE_ATTR 操作的字节码,这意味着正在执行的操作属于 a.b.this.doesnt.exist.yet = 'something'说服。我很好奇这是否可以在 CPython 之外的其他解释器上完成。

最佳答案

您可能需要为这些边缘情况覆盖 getattribute,然后使用

object.__getattribute__

查看模块 dis . 不过你写的比反汇编好看。

>>> import dis
>>> def g():
    a.b.c = 4


>>> dis.dis(g)
  2           0 LOAD_CONST               1 (4)
              3 LOAD_GLOBAL              0 (a)
              6 LOAD_ATTR                1 (b)
              9 STORE_ATTR               2 (c)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE        

关于Python dict 使用点符号和链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10438990/

相关文章:

python - 使用 cx_Oracle 的 LIKE 中字符串的正确语法是什么?

python - 转义正则表达式字符串

python - Python中的过滤操作

python - 提高包含 3000 多个条目的字典的性能

scala - 将 "_"分配给 Scala 中的字段是什么意思?

python - 使用列(键)中的信息更改 Pandas 中的索引名称

python - 更改 scikit learn 中的数字格式

python - 更改 python dict 中的键并仅打印带有值的键值

syntax - Jenkins - 每月或每周构建工作

mysql - 当没有 "having"子句时, "where"和 "group by"是否完全等价?