在 lambda 中自动元组解包的好的 python3 等价物是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21892989/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the good python3 equivalent for auto tuple unpacking in lambda?
提问by balki
Consider the following python2 code
考虑以下python2代码
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
This is not supported in python3 and I have to do the following:
这在 python3 中不受支持,我必须执行以下操作:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
This is very ugly. If the lambda was a function, I could do
这是非常丑陋的。如果 lambda 是一个函数,我可以做
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
Removing this feature in python3 forces the code to either do the ugly way(with magic indexes) or create unnecessary functions(The most bothering part is to think of good names for these unnecessary functions)
在 python3 中删除这个特性会迫使代码要么做丑陋的方式(使用魔术索引)要么创建不必要的函数(最麻烦的部分是为这些不必要的函数想好名字)
I think the feature should be added back at least to lambdas alone. Is there a good alternative?
我认为该功能至少应该单独添加到 lambdas 中。有没有好的替代方案?
Update:I am using the following helper extending the idea in the answer
更新:我正在使用以下助手扩展答案中的想法
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Update2:A cleaner version for star
更新 2:一个更干净的版本star
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
采纳答案by jsbueno
No, there is no other way. You covered it all. The way to go would be to raise this issue on the Python ideas mailing list, but be prepared to argue a lot over there to gain some traction.
不,没有其他办法。你涵盖了这一切。要走的路是在Python 想法邮件列表上提出这个问题,但准备好在那里争论很多以获得一些牵引力。
Actually, just not to say "there is no way out", a third way could be to implement one more level of lambda calling just to unfold the parameters - but that would be at once more inefficient and harder to read than your two suggestions:
实际上,并不是说“没有出路”,第三种方法可能是实现更高级别的 lambda 调用以展开参数 - 但这会比您的两个建议更低效且更难阅读:
min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))
update Python 3.8
更新 Python 3.8
As of now, Python 3.8 alpha1 is available, and PEP 572- assignment expressions are implemented.
截至目前,Python 3.8 alpha1 可用,并实现了 PEP 572-赋值表达式。
So, if one uses a trick to execute multiple expressions inside a lambda - I usually do that by creating a tuple and just returning the last component of it, it is possible to do:
因此,如果有人使用技巧在 lambda 中执行多个表达式 - 我通常通过创建一个元组并只返回它的最后一个组件来做到这一点,可以这样做:
>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
>>> a((3,4))
25
One should keep in mind that this kind of code will seldom be more readable or practical than having a full function. Still, there are possible uses - if there are various one-liners that would operate on this point, it could be worth to have a namedtuple, and use the assignment expression to effectively "cast" the incoming sequence to the namedtuple:
应该记住,这种代码很少会比拥有完整功能更具可读性或实用性。尽管如此,还是有可能的用途——如果有各种单行器可以对 this 进行操作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]
回答by njzk2
According to http://www.python.org/dev/peps/pep-3113/tuple unpacking are gone, and 2to3will translate them like so:
根据http://www.python.org/dev/peps/pep-3113/元组解包消失了,2to3并将像这样翻译它们:
As tuple parameters are used by lambdas because of the single expression limitation, they must also be supported. This is done by having the expected sequence argument bound to a single parameter and then indexing on that parameter:
lambda (x, y): x + ywill be translated into:
lambda x_y: x_y[0] + x_y[1]
由于单个表达式的限制,lambda 会使用元组参数,因此也必须支持它们。这是通过将预期的序列参数绑定到单个参数然后在该参数上建立索引来完成的:
lambda (x, y): x + y将被翻译成:
lambda x_y: x_y[0] + x_y[1]
Which is quite similar to your implementation.
这与您的实现非常相似。
回答by jfs
I don't know any good general alternatives to the Python 2 arguments unpacking behaviour. Here's a couple of suggestion that might be useful in some cases:
我不知道 Python 2 参数解包行为有什么好的通用替代方法。以下是一些在某些情况下可能有用的建议:
if you can't think of a name; use the name of the keyword parameter:
def key(p): # more specific name would be better x, y = p return x**2 + y**3 result = min(points, key=key)you could see if a
namedtuplemakes your code more readable if the list is used in multiple places: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)
如果你想不出名字;使用关键字参数的名称:
def key(p): # more specific name would be better x, y = p return x**2 + y**3 result = min(points, key=key)namedtuple如果列表在多个地方使用,您可以查看 a 是否使您的代码更具可读性: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)
回答by njzk2
Based on Cuadue suggestion and your comment on unpacking still being present in comprehensions, you can use, using numpy.argmin:
根据 Cuadue 的建议和您对解包的评论仍然存在于理解中,您可以使用,使用numpy.argmin:
result = points[numpy.argmin(x*x + y*y for x, y in points)]
回答by rahul
While the destructuring arguments was removed in Python3, it was not removed from comprehensions. It is possible to abuse it to obtain similar behavior in Python 3. In essence, we take advantage of the fact that co-routines allow us to turn functions inside out, and yield is not a statement, and hence is allowed within lambdas.
虽然在 Python3 中删除了解构参数,但它并没有从理解中删除。在 Python 3 中可以滥用它来获得类似的行为。本质上,我们利用了这样一个事实,即协程允许我们将函数内外翻转,而 yield 不是语句,因此在 lambda 中是允许的。
For example:
例如:
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))))
In comparison with the accepted answer of using a wrapper, this solution is able to completely destructure the arguments while the wrapper only destructures the first level. That is,
与使用包装器的公认答案相比,该解决方案能够完全解构参数,而包装器仅解构第一级。那是,
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))))
In comparison to
相比
values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda p: (lambda a,b: (lambda x,y: (y))(*a))(*p)))
Alternatively one can also do
或者一个也可以做
values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda y: next(b for (a,b),c in [y])))
Or slightly better
或者稍微好一点
print(min(values, key=lambda y: next(b for ((a,b),c) in (y,))))
This is just to suggest that it can be done, and should not be taken as a recommendation.
这只是建议可以做到,不应作为建议。
回答by daz
Another option is to write it into a generator producing a tuple where the key is the first element. Tuples are compared starting from beginning to end so the tuple with the smallest first element is returned. You can then index into the result to get the value.
另一种选择是将其写入生成器,生成一个元组,其中键是第一个元素。元组从头到尾进行比较,因此返回第一个元素最小的元组。然后,您可以对结果进行索引以获取值。
min((x * x + y * y, (x, y)) for x, y in points)[1]
回答by chepner
Consider whether you need to unpack the tuple in the first place:
首先考虑是否需要解包元组:
min(points, key=lambda p: sum(x**2 for x in p))
or whether you need to supply explicit names when unpacking:
或者在解包时是否需要提供显式名称:
min(points, key=lambda p: abs(complex(*p))
回答by anthony.hl
I think the better syntax is x * x + y * y let x, y = point, letkeyword should be more carefully chosen.
我认为更好的语法是x * x + y * y let x, y = point,let应该更仔细地选择关键字。
The double lambda is the closest version.
lambda point: (lambda x, y: x * x + y * y)(*point)
双 lambda 是最接近的版本。
lambda point: (lambda x, y: x * x + y * y)(*point)
High order function helper would be useful in case we give it a proper name.
如果我们给它一个合适的名字,高阶函数助手会很有用。
def destruct_tuple(f):
return lambda args: f(*args)
destruct_tuple(lambda x, y: x * x + y * y)

