bal*_*lki 79 python python-3.x
考虑以下python2代码
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
Run Code Online (Sandbox Code Playgroud)
这在python3中不受支持,我必须执行以下操作:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
Run Code Online (Sandbox Code Playgroud)
这非常难看.如果lambda是一个函数,我可以做
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
Run Code Online (Sandbox Code Playgroud)
在python3中删除此功能会强制代码执行丑陋的方式(使用魔术索引)或创建不必要的函数(最令人烦恼的部分是为这些不必要的函数考虑好名称)
我认为该功能至少应该添加到lambdas中.有没有好的选择?
更新:我正在使用以下助手扩展答案中的想法
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Run Code Online (Sandbox Code Playgroud)
Update2:更清洁版star
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
Run Code Online (Sandbox Code Playgroud)
jsb*_*eno 29
不,没有其他办法.你完全覆盖了它.要走的路是在Python思路邮件列表中提出这个问题,但要准备好在那里争论很多,以获得一些牵引力.
实际上,只是不要说"没有出路",第三种方式可能是实现一个更多级别的lambda调用来展开参数 - 但这会比你的两个建议更低效,更难阅读:
min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))
Run Code Online (Sandbox Code Playgroud)
更新Python 3.8
截至目前,Python 3.8 alpha1可用,并且实现了PEP 572-赋值表达式.
所以,如果一个人使用技巧在lambda中执行多个表达式 - 我通常通过创建一个元组并返回它的最后一个组件来实现,可以这样做:
>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
>>> a((3,4))
25
Run Code Online (Sandbox Code Playgroud)
应该记住,这种代码很少比具有完整功能更具可读性或实用性.尽管如此,仍然有可能的用途 - 如果有各种单行程序可以对此进行操作point,那么可以使用一个namedtuple,并使用赋值表达式将传入的序列有效地"转换"为namedtuple:
>>> from collections import namedtuple
>>> point = namedtuple("point", "x y")
>>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]
Run Code Online (Sandbox Code Playgroud)
njz*_*zk2 23
根据http://www.python.org/dev/peps/pep-3113/元组拆包已经消失了,2to3并将翻译它们如下:
由于单个表达式限制,lambdas使用元组参数,因此还必须支持它们.这是通过将预期的序列参数绑定到单个参数然后对该参数建立索引来完成的:
lambda (x, y): x + y将被翻译成:
lambda x_y: x_y[0] + x_y[1]
这与您的实施非常相似.
jfs*_*jfs 10
我不知道Python 2参数解包行为的任何好的一般替代方案.以下是一些在某些情况下可能有用的建议:
如果你想不出一个名字; 使用关键字参数的名称:
def key(p): # more specific name would be better
x, y = p
return x**2 + y**3
result = min(points, key=key)
Run Code Online (Sandbox Code Playgroud)namedtuple如果列表在多个位置使用,您可以看到是否使代码更具可读性:
from collections import namedtuple
from itertools import starmap
points = [ (1,2), (2,3)]
Point = namedtuple('Point', 'x y')
points = list(starmap(Point, points))
result = min(points, key=lambda p: p.x**2 + p.y**3)
Run Code Online (Sandbox Code Playgroud)虽然解构参数在Python3中已删除,但并未从理解中删除。可能会滥用它以在Python 3中获得类似的行为。实质上,我们利用了以下事实:协例程使我们能够将函数内翻,而yield不是语句,因此在lambda中是允许的。
例如:
points = [(1,2), (2,3)]
print(min(points, key=lambda y: next(x*x + y*y for x,y in (lambda a: (yield a))(y))))
Run Code Online (Sandbox Code Playgroud)
与使用包装器的公认答案相比,此解决方案能够完全解构参数,而包装器仅解构第一级。那是,
values = [(('A',1),'a'), (('B',0),'b')]
print(min(values, key=lambda y: next(b for (a,b),c in (lambda x: (yield x))(y))))
Run Code Online (Sandbox Code Playgroud)
相比
values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda p: (lambda a,b: (lambda x,y: (y))(*a))(*p)))
Run Code Online (Sandbox Code Playgroud)
或者也可以做
values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda y: next(b for (a,b),c in [y])))
Run Code Online (Sandbox Code Playgroud)
还是稍微好一点
print(min(values, key=lambda y: next(b for ((a,b),c) in (y,))))
Run Code Online (Sandbox Code Playgroud)
这只是建议可以做到的,不应作为建议。
| 归档时间: |
|
| 查看次数: |
25267 次 |
| 最近记录: |