如何在扩展 dict 时正确覆盖方法 keys()(在 python3 中)

How to properly override method keys() while extending dict (in python3)

编辑:我添加了 class 和一些信息,请参阅新的 post。

我创建了一个扩展 dictset 的 class(更准确地说,我扩展了 collections.abc.MutableMappingMutableSet)。现在我想正确地覆盖方法 keys().

这个class表示一组其他对象,称为Measurand:

class Measurands(MutableSet, MutableMapping):
    @property
    def measurands(self):
        return self._measurands
    
    
    @measurands.setter
    def measurands(self, val):
        self._measurands = []
        
        for el in val:
            self.add(el)
    
    
    def __init__(self, arg=None):
        if arg is None:
            self.measurands = []
        else:
            try:
                measurands = arg.measurands
            except AttributeError:
                if isinstance(arg, Iterable):
                    measurands = list(arg)
                else:
                    measurands = [arg]
            
            self.measurands = measurands
            
    
    def __iter__(self):
        return iter(self.measurands)
    
    
    def __getitem__(self, key):
        for m in self:
            if m.id == key:
                return m
    
        raise KeyError(key)
    
    
    def __contains__(self, el_x):
        is_in = False
        
        for el in self:
            if el_x.id == el.id:
                is_in = True
                break
        
        return is_in
    
    
    def add(self, el):
        try:
            self[el.id].session_ids |= el.session_ids
        except KeyError:
            self[el.id] = Measurand(el)
    
    
    def _discard(self, key):
        res = False
        
        for i, m in enumerate(self):
            if m.id == key:
                del self.measurands[i]
                res = True
                break
        
        return res
    
    
    def __delitem__(self, key):
        res = self._discard(self, key)
        
        if not res:
            raise KeyError(key)
    
    def discard(self, key):
        self._discard(self, key)
    
    
    def remove(self, key):
        self.__delitem__(self, key)
    
    
    def __len__(self):
        return len(self.measurands)
    
    
    def __setitem__(self, key, value):
        res = False
        value_true = Measurand(value)
        
        for i, m in enumerate(self):
            if m.id == key:
                res = True
                
                if value.id == key:
                    self.measurands[i] = value_true
                else:
                    raise KeyError(key)
                
                break
        
        if not res:
            self.measurands.append(value_true)
    
    
    def __str__(self):
        string = "Measurands({"
        
        for m in self:
            string += str(m)
            string += ", "
        
        if string:
            string = string[:-2]
        
        string += "})"
        
        return string

问题是默认方法 keys return 是 Measurand 对象的“列表”。这不是我想要的。键应该是 Measurand 个对象的 属性 id

目前我正在 return 创建一个简单的 list,但我会 return dict_keyscollection.abc.KeysView 对象。不幸的是,dict_keys 不是全局名称。

  1. dict_keys在哪里?
  2. 这是correct/pythonic的方法吗?

我还没有找到任何方法将某些东西转换为 dict_keys 类型,但是在阅读了介绍访问键和值的新方法的 PEP (PEP 3106) 之后, dict_keys 似乎被介绍给了

return a set-like or unordered container object whose contents are derived from the underlying dictionary rather than a list which is a copy of the keys, etc.

考虑到这一点,看起来您可以使用 keys() 方法而不是列表返回生成器对象。

这是来自 PEP 的伪代码:

class dict:

    # Omitting all other dict methods for brevity.

    def keys(self):
        return d_keys(self)

class d_keys:

    def __init__(self, d):
        self.__d = d

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

    def __contains__(self, key):
        return key in self.__d

    def __iter__(self):
        for key in self.__d:
            yield key

Python3 文档说 dict.keys() return 值类型(即视图)是 "set-like",因此您的 return 值应该是 "set-like" 还有。

The objects returned by dict.keys(), dict.values() and dict.items() are view objects. They provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes.

Dictionary views can be iterated over to yield their respective data, and support membership tests:

....

Keys views are set-like since their entries are unique and hashable. If all values are hashable, so that (key, value) pairs are unique and hashable, then the items view is also set-like. (Values views are not treated as set-like since the entries are generally not unique.) For set-like views, all of the operations defined for the abstract base class collections.abc.Set are available (for example, ==, <, or ^).

全文在这里: https://docs.python.org/3/library/stdtypes.html#dict-views

这已经为您处理好了! collections.abc.MutableMapping 包含 keys 的合理默认实现,它提供与 dict.keys.

相同的接口

只需删除您的 keys 方法,您将使用继承的实现。