python-3.x 类的自定义星星运算符?

lx0bsm1f  于 2023-04-22  发布在  Python
关注(0)|答案(2)|浏览(122)

如何实现自定义的星星运算符(**)来解包,类似于__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>
}
ix0qys7i

ix0qys7i1#

就像@ShadowRanger说的,实现Mapping。下面是一个例子:

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}
huwehgph

huwehgph2#

实现Mapping ABC。从技术上讲,语言文档没有指定使用哪些Mapping方法,因此假设您只需要当前实现使用的某个子集是一个坏主意。它所说的全部内容是:
如果语法**expression出现在函数调用中,则expression必须计算为Map,其内容被视为附加的关键字参数。如果关键字同时出现在expression和显式关键字参数中,则会引发TypeError异常。
因此,如果您实现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会做一些涉及迭代和查找的半邪恶的事情,其中直接访问器可能会更快,这取决于内部结构),所以如果你将其用于其他目的,我建议用优化版本覆盖它们。

相关问题