Custom double star operator for a class?

元气小坏坏 提交于 2019-12-03 12:01:41

As @ShadowRanger says, implement Mapping. Here's an example:

from collections.abc import Mapping

class Foo(Mapping):
    def __iter__(self):
        yield "a"
        yield "b"

    def __len__(self):
        return 2

    def __getitem__(self, item):
        return ord(item)

f = Foo()

print(*f)
print(dict(**f))

The program outputs:

a b
{'a': 97, 'b': 98}

Implement the Mapping ABC. Technically, the language docs don't specify which Mapping methods are used, so assuming you only need some subset used by the current implementation is a bad idea. All it says is:

If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments. In the case of a keyword appearing in both expression and as an explicit keyword argument, a TypeError exception is raised.

So if you implement the Mapping ABC, you definitely have the right interfaces, regardless of whether it relies on .items(), direct iteration and __getitem__ calls, etc.

FYI, on checking, the behavior in CPython 3.5 definitely dependent on how you implement Mapping (if you inherit from dict, it uses an optimized path that directly accesses dict internals, if you don't, it iterates .keys() and looks up each key as it goes). So yeah, don't cut corners, implement the whole ABC. Thanks to default implementations inherited from the Mapping ABC and it's parents, this can be done with as little as:

class MyMapping(Mapping):
    def __getitem__(self, key):
        ...
    def __iter__(self):
        ...
    def __len__(self):
        ...

The default implementations you inherit may be suboptimal in certain cases (e.g. items and values would do semi-evil stuff involving iteration and look up, where direct accessors might be faster depending on internals), so if you're using it for other purposes, I'd suggest overriding those with optimized versions.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!