如何实现自定义双星运算符(**
)进行解包,类似于__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>
}
答案 0 :(得分:14)
正如@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}
答案 1 :(得分:9)
实施Mapping
ABC。从技术上讲,语言文档没有指定使用哪些Mapping
方法,因此假设您只需要当前实现使用的某个子集是一个坏主意。 All it says is:
如果语法**表达式出现在函数调用中,则表达式必须求值为映射,其内容被视为附加关键字参数。如果关键字出现在表达式和显式关键字参数中,则会引发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):
...
在某些情况下,您继承的默认实现可能不是最理想的(例如items
和values
会涉及迭代和查找的半邪恶内容,其中直接访问器可能会更快,具体取决于内部结构),因此,如果您将其用于其他目的,我建议优先使用优化版本。