do_something(...)
方法期望接收任意数量的参数。每个参数都应以一种或另一种方式包含有关以下信息:
name
(类型:str
;包含与Python语法不兼容的符号,例如@
,#
,.
等)]data
(类型:bytes
)为了防止意外行为do_something(...)
asserts每个参数的name
和data
的类型:
...
assert isinstance(name, str), ...
assert isinstance(data, bytes), ...
...
每个论点应该(并且应该)仅带来这两条信息。
将参数作为namedtuple
实例(*args
)的列表传递:
from collections import namedtuple
SomeRepresentation = namedtuple('SomeRepresentation', ['name', 'data'])
foo_bar = [SomeRepresentation('name_of_item_@1', b'...'), SomeRepresentation('name_of_item_@2', b'...'), ...]
do_something(*foo_bar)
假设do_something(*args)
将被相应实现:
def do_something(*args):
for item in args:
assert isinstance(item, SomeRepresentation), ...
...
将参数作为字典传递[**kwargs
)
foo_bar = {
'name_of_item_@1': b'...',
'name_of_item_@2': b'...',
...
}
do_something(**foo_bar)
假设do_something(*args)
将被相应实现:
def do_something(**kwargs):
for name, data in kwargs.items():
...
不使用可变参数,而是使用一对可迭代的对。
from typing import Iterable
def do_something(pairs: Iterable): # take an iterable...
for name, data in pairs: # ...of multiple pairs
assert isinstance(name, str) and isinstance(data, bytes)
...
除非延迟创建对元素,否则可能需要更具体的注释pairs: Iterable[Tuple[str, bytes]]
。
这既与dict
项目和list
兼容,也与许多其他类型兼容。
foo_bar_list = [
SomeRepresentation('name_of_item_@1', b'...'),
SomeRepresentation('name_of_item_@2', b'...'),
]
do_something(foo_bar_list)
foo_bar_dict = {
'name_of_item_@1': b'...',
'name_of_item_@2': b'...',
}
foo_bar_dict(foo_bar_dict.items())
foo_bar_gen = (
(f'name_of_item_@{n}', b'...')
for n in range(1, 1000)
)
do_something(foo_bar_gen)
在这种情况下,使用可变参数是无效的并且具有误导性。
如果呼叫站点和接收方使用*
/ **
,则意味着无需重复包装可迭代对象,然后重新包装。由于也构造了完整的tuple
/ dict
,因此这也防止了使用懒惰的可迭代项/映射。
使用可变参数表示该函数旨在与各个参数一起使用。这里不是这种情况:
# not intended: manual construction of arguments
do_something(SomeRepresentation('name_of_item_@1', b'...'), SomeRepresentation('name_of_item_@2', b'...'))
# not valid: manual passing of keywords
do_something(name_of_item_@1=b'...', name_of_item_@2=b'...')