class 的自定义双星运算符?

Custom double star operator for a class?

如何实现自定义双星运算符 (**) 来解包,类似于 __iter__ 与单星运算符 (*) 的工作方式?

例如:

class PlayerManager(object):

    def __init__(self, players=None):
        self.players = players or []

    # Made up method to support ** operator
    def __dict_iter__(self):
        for player in self.players:
            yield get_steamid(player), player

def print_players(**players):
    print(players)

player_manager = PlayerManager([list, of, players])
print_players(**player_manager)

输出:

{
    'STEAM_0:0:02201': <Player object at 0x0000000000>,
    'STEAM_0:0:10232': <Player object at 0x0000000064>,
    'STEAM_0:0:73602': <Player object at 0x0000000128>
}

实施 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.

所以如果你实现Mapping ABC,你肯定有正确的接口,不管它是否依赖.items(),直接迭代和__getitem__调用等

仅供参考,在检查时,CPython 3.5 中的行为绝对取决于 如何 你实现 Mapping (如果你继承自 dict,它使用直接访问 dict 内部的优化路径,如果你不这样做,它会迭代 .keys() 并查找每个键)。所以,是的,不要偷工减料,实施整个 ABC。多亏了从 Mapping ABC 及其父类继承的默认实现,只需以下代码即可完成此操作:

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

您继承的默认实现在某些情况下可能不是最优的(例如 itemsvalues 会做涉及迭代和查找的半邪恶的事情,其中​​直接访问器可能更快,具体取决于内部结构),所以如果您将它用于其他目的,我建议使用优化版本覆盖那些。

正如@ShadowRanger 所说,实现映射。这是一个例子:

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))

程序输出:

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