优雅地解包变长元组

6

一个真实但有点傻的问题:

https://github.com/joshmarshall/tornadorpc/blob/master/tornadorpc/base.py

def start_server(handlers, ...):
    ...
    for (route, handler) in handlers:
        ...

通常,“handlers”是一个由2个元素组成的元组列表。但是在这种特殊情况(Tornado)下,您可以向特定处理程序传递第三个参数(kw args)。因此,在“handlers”中的元组有时可能具有2个元素,有时可能具有3个元素。

我需要在循环中解包它。当然,我可以进行长度检查或尝试解包时使用try..except。可惜。

你能想到比这更好/更聪明的方法吗:

In [8]: handlers
Out[8]: [(1, 2), (3, 4, 5), (6, 7)]


In [9]: new_handlers = [x + (None,) for x in handlers]

?

2个回答

9
如果该处理程序需要关键字参数,则使用字典作为第三个元素:
handlers = [(1, 2, {}), (3, 4, {'keyword': 5), (6, 7, {})]

for route, handler, kwargs in handlers:
    some_method(route, handler, **kwargs)

或者您可以使用*args语法来应用参数;在这种情况下,只需在循环中捕获所有值:

for args in handlers:
    some_method(*args)

如果你必须将其解压成至少2个参数,请在单独的步骤中执行:

for handler in handlers:
    route, handler, args = (handler[0], handler[1], handler[2:])

args 是一个由0个或多个元素组成的元组。

在Python 3中,你可以使用解构赋值操作符(splat,*)来处理任意数量的元素:

for route, handlers, *args in handlers:

*args用于捕获解包中的0个或多个额外值。

handlers中的元素缩减到最小长度的另一种方法是:

[(h + (None,) * 3)[:3] for h in handlers]

演示:

>>> handlers = [(1, 2), (3, 4, 5), (6, 7)]
>>> [(h + (None,) * 3)[:3] for h in handlers]
[(1, 2, None), (3, 4, 5), (6, 7, None)]

我知道,但是处理程序不是我的问题,我的问题是在变长元组序列上使用“for”循环。由于tornadorpc不是我的代码/项目,我更感兴趣的是解决这种问题的一般方法,而不是特定于tornado/tornadorpc 的解决方案。 - LetMeSOThat4U
@JohnDoe:但是如果你以不同的方式处理它,问题就会消失。无论如何,我已经添加了通用选项。 - Martijn Pieters

3
自 Python 3 开始,您可以使用PEP 3132 扩展解包:
for route, handler, *kw in handlers:
    ...

如果这不是一个选项,就使用中间人进行解包:
for handler in handlers:
    (route, handler), kw = handler[:2], handler[2:]

你的解包行出现了“ValueError: need more than 2 values to unpack”错误,因为右侧有一个由两个值组成的元组。 - Martijn Pieters
抱歉,那并不完全可行:ValueError: 需要超过2个值来解包。我可以通过执行(r,h),kw = h[:2],h[2:]来解决,但是kw本身也是一个元组(如(5,)或())。 - LetMeSOThat4U

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接