Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Schrodingers字典:获取间接访问上的动态键的值_Python_Python 3.x_Dictionary - Fatal编程技术网

Python Schrodingers字典:获取间接访问上的动态键的值

Python Schrodingers字典:获取间接访问上的动态键的值,python,python-3.x,dictionary,Python,Python 3.x,Dictionary,我想创建一个有一些动态键的专门词典。子类化dict和重写\uuuu getitems\uuuuu使我大部分时间都在那里,但是您只能从最后一次直接访问中获取key的值 $ cat schrodingers_dict.py cats = [] class SchrodingersDict(dict): def __getitem__(self, key): if key == 'dead' or key == 'alive': self[key] =

我想创建一个有一些动态键的专门词典。子类化
dict
和重写
\uuuu getitems\uuuuu
使我大部分时间都在那里,但是您只能从最后一次直接访问中获取key的值

$ cat schrodingers_dict.py
cats = []

class SchrodingersDict(dict):
    def __getitem__(self, key):
        if key == 'dead' or key == 'alive':
            self[key] = cats.count(key)
        return super().__getitem__(key)

box = SchrodingersDict([('dead', 0), ('alive', 0)])

$ python3 -i schrodinger_dict.py 
>>> box
{'dead': 0, 'alive': 0}
>>> cats.append('alive')
>>> cats.append('dead')
>>> cats.append('dead')
>>> box
{'dead': 0, 'alive': 0}
>>> box['dead']
2
>>> box['alive']
1
>>> box
{'dead': 2, 'alive': 1}

是否可以让间接访问返回动态值,例如
repr(box)
json.dumps(box)

您可能应该扩展
MutableMapping
并实现相关的抽象方法(将非计算键委托给一个具体的底层dict),因为由于性能优化
dict
不能保证在k/v上迭代时调用
\u getitem\uuuuuuu

$ cat schrodingers_dict.py
from collections import MutableMapping
cats = []

class SchrodingersDict(MutableMapping):

    def __init__(self, data):
        self._store = dict(data)

    def __getitem__(self, key):
        if key == 'dead' or key == 'alive':
            self._store[key] = cats.count(key)
        return self._store[key]

    def __setitem__(self, key, value):
        self._store[key] = value

    def __delitem__(self, key):
        del self._store[key]

    def __iter__(self):
        return iter(self._store)

    def __len__(self):
        return len(self._store)

    def __repr__(self):
        return repr(dict(self.items()))


box = SchrodingersDict([('dead', 0), ('alive', 0)])
cats.append('dead')
cats.append('dead')
cats.append('alive')

$ python3 -i schrodinger_dict.py
>>> box
{'dead': 2, 'alive': 1}

您可能还希望计算出的密钥是完全虚拟的,而不是将它们存储在基础dict中,您在每次访问时都要重新计算它们,还可以节省一些指令和空间。

目标是在访问
dict
的值时,以某种方式自动计算
的“死”值和
的“活”值

然而,在
\uuuu getattribute\uuuuu
中实现对某种
值的访问检查是不可能的,因为
dict
是一个(基于C的)python内置属性,没有类似的属性。此外,由于速度优化,特殊方法查找会绕过
\uuuu getattribute\uuuuu

不幸的是,
dict
的方法没有公开的通用方法来访问值(
仅返回视图,所有内容都在内部处理),因此所有这些方法都需要事先显式更新

一种解决方案是以

def accessing_method(self):
    self._update_dead_and_alive()
    return super().accessing_method()
另一个是通过编程实现的

from functools import wraps

cats = []    

def add_state_update(cls):
    # all the methods accessing values of dict
    accmethods_names = [
        '__repr__', '__getitem__', 'get', 'items', 'pop', 'popitem',
        'setdefault', 'values'
    ]

    def state_update(method):
        def update_dead_and_alive(self):
            self['dead'] = cats.count('dead')
            self['alive'] = cats.count('alive')

        @wraps(method)
        def wrapper(*args, **kwargs):
            update_dead_and_alive(*args)
            return method(*args, **kwargs)
        return wrapper

    # put update_dead_and_alive in front of the execution of every
    # accmethod
    for n in accmethods_names:
        method = getattr(cls, n)
        setattr(cls, n, state_update(method))

    return cls

@add_state_update
class SchrodingersDict(dict):
    pass

box = SchrodingersDict([('dead', 0), ('alive', 0)])
根据上述功能进行测试时,得出以下结果

>>> cats.append('alive')
>>> cats.append('dead')
>>> cats.append('dead')
>>>
>>> import pickle
>>> pickle.loads(pickle.dumps(box))
{'dead': 2, 'alive': 1}
>>>
>>> cats.append('alive')
>>> import json
>>> json.loads(json.dumps(box))
{'dead': 2, 'alive': 2}
>>>
>>> cats.append('alive')
>>> eval(repr(box)) == box
True

第一个版本的代码量相似,可能更明确。

我不确定是否理解正确。在本例中,只要cat的内容发生更改,
repr(box)
json.dumps(box)
的输出就应该更改?或者实际存储的
值是否应该更改?@bbastu我希望在间接访问时更改该值,例如
repr
dumps
。当dict发生变化时,我不需要
cat
向它发出信号,我只想在dict被显示或序列化时,该值是正确的。@iiiSeymour如果不是,json.dumps使用的是不会考虑虚拟键的iter/iteritems。由于您必须在映射上实现
\uuuuu iter\uuuuu
,并且每个相关方法都是通过该映射路由的(和/或
\uuuuuu getitem\uuuuuu
),因此您可以正确地将虚拟键添加到该映射中,并在其余部分使用内部dict,对于每个更高级别的方法,情况都会很好,对于
dict
@iiSeymour
dict
来说,如果重写其方法(可以绕过),则基本上不提供任何保证,映射需要实现一组特定的方法,并保证更高级别的调用将通过这些方法。