Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.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 自定义Dict在施放时放置键_Python_Python 3.x_Class_Dictionary - Fatal编程技术网

Python 自定义Dict在施放时放置键

Python 自定义Dict在施放时放置键,python,python-3.x,class,dictionary,Python,Python 3.x,Class,Dictionary,我有一个从dict继承的自定义类(如下所示),当我将对象强制转换为dict时,它会删除名为“type”的键。发生这种情况有什么原因吗 我预期会有以下结果: dm=参数() 打印(dict(dm)) {'tags':'bar','type':'Item','title':'foo'} 我最终得到的是: {'tags':'bar','title':'foo'} self.\u映射包含“type”键/值对,因此我不知道可能是什么问题。有人有什么建议吗 class ItemParameter(dict)

我有一个从dict继承的自定义类(如下所示),当我将对象强制转换为dict时,它会删除名为“type”的键。发生这种情况有什么原因吗

我预期会有以下结果:

dm=参数()

打印(dict(dm))

{'tags':'bar','type':'Item','title':'foo'}

我最终得到的是:

{'tags':'bar','title':'foo'}

self.\u映射包含“type”键/值对,因此我不知道可能是什么问题。有人有什么建议吗

class ItemParameter(dict):
    """
    """
    def __init__(self,
                 title,
                 tags):
        super(ItemParameter, self).__init__(title=title, tags=tags)
        self._map = {}
        self._allowed_keys = {'type':'type',
                              'title': 'title',
                              'tags':'tags',
                              'thumbnail': 'thumbnail',
                              'thumbnailurl': 'thumbnailurl',
                              'metadata': 'metadata',
                              'type_keywords' : 'typeKeywords',
                              'description': 'description',
                              'snippet' : 'snippet'}
        self['type'] = "Item"
        self['title'] = title
        self['tags'] = tags

    def __iter__(self):
        for k, v in self.items():
            yield k, v

    def __setitem__(self, k, v):
        if k in self._allowed_keys:
            self._map[self._allowed_keys[k]] = v

    def __getitem__(self, k):
        if k in self._map:
            return self._map[k]
        elif k in self._allowed_keys and \
             self._allowed_keys[k] in self._map:
            return self._map[self._allowed_keys[k]]

    def __setattr__(self, k, v):
        if k in {'_map','_dynamic', '_allowed_keys',
                 '_ipython_canary_method_should_not_exist_'}:
            super(ItemParameter, self).__setattr__(k,v)
        else:
            if k in self._allowed_keys.keys():
                self._map[self._allowed_keys[k]] = v

    def __getattr__(self, k):
        if k == {'_map','_dynamic', '_allowed_keys',
                 '_ipython_canary_method_should_not_exist_'}:
            super(ItemParameter, self).__getattr__(k)
        else:
            if k in self._allowed_keys.keys() and \
               self._allowed_keys[k] in self._map:
                return self._map[self._allowed_keys[k]]
    def __delattr__(self, key):
        return self._map.__delitem__(key)
    def __contains__(self, k):
        return self._map.__contains__(k)
    def __repr__(self):
        return str(self._map)
    def __str__(self):
        return self.__repr__()
    def items(self):
        return self._map.items()

这里有两个完全不同的
dict
s;隐式地属于您自己对象结构的一部分(因为您继承自
dict
)和
\u map
。您看到的两个键是通过调用超类
\uuuu init\uuuu
(初始值设定项中的第一行)来设置的,该超类委托给
update
(您也没有覆盖它),而用于
打印
dict
构造函数忽略它们

一般来说,在更改有意义的行为时尝试从
dict
本身继承是一个坏主意,因为很容易错过重要的代码路径而无法获得预期的结果。例如,在本例中,我认为处理代码正在调用类的
keys
方法,您没有覆盖它,因此它从超类实现中获取
keys
,而超类实现绕过了自定义代码

即使您确实重写了它,代码中偶尔也会出现一些快速路径,这些路径最终会绕过自定义代码以提高性能,直接读取子类的
dict
组件(根本看不到
\u map
或自定义
\ugs]etitem
重写)

我建议您考虑从
collections.abc.MutableMapping
继承,这样您就不是真正的
dict
,但更直观的是,哪些方法需要重写以及必须如何重写

如果您必须是
dict
子类,请直接对自己进行操作,而不是
\u map
成员,因此您首先可以作为
dict
使用。使用
super()
调用父方法,例如替换:

def __setitem__(self, k, v):
    if k in self._allowed_keys:
        self._map[self._allowed_keys[k]] = v
与:


这将改变继承自的
dict
结构,而不是碰巧也是
dict
的不相关属性。

正如ShadowRanger提到的,在
映射
属性中复制
dict
数据是一种糟糕的设计,通常不子类化内置类型会更好

我已经将您的代码减少到复制此“错误”的最低限度,我仍然不完全确定它的行为为何与此完全相同,但我们可以通过确保
\uu setitem\uuuuuuuuuuu
将新项目添加到
self
以及
self.\u map
来修复此错误。例如:

def __setitem__(self, k, v):
    if k in self._allowed_keys:
        k = self._allowed_keys[k]
        self._map[k] = v
        super(ItemParameter, self).__setitem__(k, v)

这是一个新版本的你的类,做什么我认为你想要的。它使用Python3版本的
super()
,它的参数形式为零

class ItemParameter(dict):
    allowed = {
        'type':'type',
        'title': 'title',
        'tags':'tags',
        'thumbnail': 'thumbnail',
        'thumbnailurl': 'thumbnailurl',
        'metadata': 'metadata',
        'type_keywords' : 'typeKeywords',
        'description': 'description',
        'snippet' : 'snippet',
    }

    def __init__(self, title, tags):
        super().__init__(title=title, tags=tags)
        self['type'] = "Item"

    def __setitem__(self, k, v):
        if k in ItemParameter.allowed:
            k = ItemParameter.allowed[k]
            super().__setitem__(k, v)

    def update(self, other):
        for k, v in other.items():
            self[k] = v

# test

p = ItemParameter(title='foo', tags='bar')
for t in p:
    print(t)
print(p)
print(p.copy())
print(dict(p))
p['type_keywords'] = 'some thing'
print(p)
p['bad'] = 'other thing'
print(p)
p.update({'a':1, 'b':2, 'metadata': 3})
print(p)
输出

title
tags
type
{'title': 'foo', 'tags': 'bar', 'type': 'Item'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item', 'typeKeywords': 'some thing'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item', 'typeKeywords': 'some thing'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item', 'typeKeywords': 'some thing', 'metadata': 3}

我同意你所说的
\u map
属性,并使用
集合
而不是子类化
dict
。但是,我不认为“我相信处理代码正在调用类的keys方法,您没有覆盖它,因此它从超类实现中获取密钥,而超类实现绕过了您的自定义代码”是正确的。如果我们添加:
def keys(self):return self.\u map.keys()
,仍然会出现此“错误”。但是,如果我们将
ItemParameter
实例转换为列表或元组(即使没有新的
keys
方法),则不会发生这种情况,因此我不知道实际原因是什么。此外,如果我们打印
\u map
属性,它就具有所有预期的项。但是我刚刚注意到调用
.copy()
会返回简化的字典,如果我添加
def copy(self):返回self,我们仍然会得到原始错误。\u map.copy()
@shadowranger谢谢您提供的信息。我想确保只有某些键被放入字典,而在cast中,我只希望_allowed_键被放入字典,这是我拥有
self的理由。_map
感谢您的回答!
title
tags
type
{'title': 'foo', 'tags': 'bar', 'type': 'Item'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item', 'typeKeywords': 'some thing'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item', 'typeKeywords': 'some thing'}
{'title': 'foo', 'tags': 'bar', 'type': 'Item', 'typeKeywords': 'some thing', 'metadata': 3}