Sam*_*adi 5 python python-3.x iterable-unpacking
我经常对Python的可迭代解包缺乏灵活性感到沮丧.
请看以下示例:
a, b = range(2)
Run Code Online (Sandbox Code Playgroud)
工作良好.正如预期的那样a包含0和b包含1.现在让我们试试这个:
a, b = range(1)
Run Code Online (Sandbox Code Playgroud)
现在,我们得到一个ValueError:
ValueError: not enough values to unpack (expected 2, got 1)
Run Code Online (Sandbox Code Playgroud)
不理想,当期望的结果是0在a和None中b.
有很多黑客可以解决这个问题.我见过的最优雅的是:
a, *b = function_with_variable_number_of_return_values()
b = b[0] if b else None
Run Code Online (Sandbox Code Playgroud)
不漂亮,可能会让Python新手感到困惑.
那么最恐怖的方式是什么?将返回值存储在变量中并使用if块?该*varname黑客?别的什么?
正如评论中提到的,执行此操作的最佳方法是简单地让函数返回恒定数量的值,如果您的用例实际上更复杂(例如参数解析),请使用库。
但是,您的问题明确要求采用 Pythonic 方式来处理返回可变数量参数的函数,我相信它可以通过装饰器干净地完成。它们并不是很常见,大多数人倾向于使用它们而不是创建它们,因此这里有一个关于创建装饰器的实用教程,以了解更多关于它们的信息。
下面是一个装饰函数,可以满足您的需求。该函数返回一个具有可变数量参数的迭代器,并将其填充到一定长度以更好地适应迭代器解包。
def variable_return(max_values, default=None):
# This decorator is somewhat more complicated because the decorator
# itself needs to take arguments.
def decorator(f):
def wrapper(*args, **kwargs):
actual_values = f(*args, **kwargs)
try:
# This will fail if `actual_values` is a single value.
# Such as a single integer or just `None`.
actual_values = list(actual_values)
except:
actual_values = [actual_values]
extra = [default] * (max_values - len(actual_values))
actual_values.extend(extra)
return actual_values
return wrapper
return decorator
@variable_return(max_values=3)
# This would be a function that actually does something.
# It should not return more values than `max_values`.
def ret_n(n):
return list(range(n))
a, b, c = ret_n(1)
print(a, b, c)
a, b, c = ret_n(2)
print(a, b, c)
a, b, c = ret_n(3)
print(a, b, c)
Run Code Online (Sandbox Code Playgroud)
哪个输出您正在寻找的内容:
0 None None
0 1 None
0 1 2
Run Code Online (Sandbox Code Playgroud)
装饰器基本上采用装饰函数并返回其输出以及足够的额外值来填充max_values。然后,调用者可以假设该函数始终返回确切max_values数量的参数,并且可以像平常一样使用花哨的解包。
| 归档时间: |
|
| 查看次数: |
423 次 |
| 最近记录: |