Tha*_*wda 10 python lambda programming-languages keyword
Python是关于简单易读的代码.它比版本更好,我是一个巨大的粉丝!但是,l a m b d a每次我必须键入lambda时输入并不好玩(你可能不同意).问题是,l a m b d a当我在maps和filters中嵌入几个lambdas时,这6个字符使我的语句更长(我没有嵌套超过2或3,因为它消除了python的可读性 - 这里没有参数!)
# How to rename/alias a keyword to a nicer one?
lines = map(lmbd x: x.strip(), sys.stdin)
# OR, better yet, how to define my own operator like -> in python?
lines = map(x -> x.strip(), sys.stdin)
# Or may be :: operator is pythonic
lines = map(x :: x.strip(), sys.stdin)
# INSTEAD of this ugly one. Taking out this is my goal!
lines = map(lambda x: x.strip(), sys.stdin)
Run Code Online (Sandbox Code Playgroud)
我很乐意添加这样的导入:
from myfuture import lamb_as_lambda
# OR
from myfuture import lambda_operator
Run Code Online (Sandbox Code Playgroud)
MSe*_*ert 12
好消息是:你不需要使用map或根本不需要filter使用生成器表达式(懒惰)或列表推导(渴望),从而lambda完全避免使用.
所以代替:
lines = map(lambda x: x.strip(), sys.stdin)
Run Code Online (Sandbox Code Playgroud)
只需使用:
# You can use either of those in Python 2 and 3, but map has changed between
# Python 2 and Python 3 so I'll present both equivalents:
lines = (x.strip() for x in sys.stdin) # generator expression (Python 3 map equivalent)
lines = [x.strip() for x in sys.stdin] # list comprehension (Python 2 map equivalent)
Run Code Online (Sandbox Code Playgroud)
如果你使用理解,它可能也会更快.在使用map或filter使用时,很少有功能实际上更快,并且使用lambda更多的反模式(和慢速).
这个问题只包含一个例子map,但您也可以替换filter.例如,如果你想filter输出奇数:
filter(lambda x: x%2==0, whatever)
Run Code Online (Sandbox Code Playgroud)
您可以使用条件理解:
(x for x in whatever if x%2==0)
[x for x in whatever if x%2==0]
Run Code Online (Sandbox Code Playgroud)
你甚至可以结合一个map和filter一个理解:
(x*2 for x in whatever if x%2==0)
Run Code Online (Sandbox Code Playgroud)
只要考虑一下它的外观map和filter:
map(lambda x: x*2, filter(lambda x: x%2==0, whatever))
Run Code Online (Sandbox Code Playgroud)
注意:这并不意味着lambda没用!有很多地方的lambdas非常方便.考虑key的参数sorted(并且对于min和max)或functools.reduce(但是从功能更好地保持距离,大部分的时间正常for-loop更易读)或者itertools需要谓词函数:itertools.accumulate,itertools.dropwhile,itertools.groupby和itertools.takewhile.仅举一些lambda可能有用的例子,可能还有很多其他地方.
为了回答您的特定问题,该operator模块提供了几个旨在替换lambda表达式的特定用途的函数。在这里,您可以使用该methodcaller函数创建一个函数,该函数调用对象上的给定方法。
from operator import methodcaller as mc
lines = map(mc('strip'), sys.stdin)
Run Code Online (Sandbox Code Playgroud)
然而,列表推导式往往比map.
lines = [x.strip() for x in sys.stdin]
Run Code Online (Sandbox Code Playgroud)
作为一个除了调试目的从不在他的代码中使用 lambda 表达式的人,我可以建议几种替代方法。
我不会谈论在编辑器中定义你自己的语法(你不能在纯 Python 中定义运算符:Python:定义我自己的运算符?),而只是关于内置的东西。
words = ['cat', 'dog', 'shark']
result_1 = map(lambda x: x.upper(), words)
result_2 = (x.upper() for x in words)
result_3 = map(str.upper, words)
# ['CAT', 'DOG', 'SHARK']
Run Code Online (Sandbox Code Playgroud)
使用mapwithstr.upper比另一个答案中提出的mapwithlambda和生成器表达式都短。
你可以找到很多的其他方法的文档不同的类型,例如,,,和其他人,你可以以同样的方式使用。例如,检查数字是否为整数:
intfloatstrbytesnumbers = [1.0, 1.5, 2.0, 2.5]
result_1 = map(lambda x: x.is_integer(), numbers)
result_2 = (x.is_integer() for x in numbers)
result_3 = map(float.is_integer, numbers)
# [True, False, True, False]
Run Code Online (Sandbox Code Playgroud)类方法:
以类似的方式,您可以使用map类方法:
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
circles = [Circle(2), Circle(10)]
result_1 = map(lambda x: x.area(), circles)
result_2 = (x.area() for x in circles)
result_3 = map(Circle.area, circles)
# [12.56, 314.0]
Run Code Online (Sandbox Code Playgroud)operator 模块:
itemgetter:
当您想通过索引选择元素时使用此方法:
from operator import itemgetter
numbers = [[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 0, 1]]
result_1 = map(lambda x: x[0], numbers)
result_2 = (x[0] for x in numbers)
result_3 = map(itemgetter(0), numbers)
# [0, 4, 8]
Run Code Online (Sandbox Code Playgroud)
虽然在给定示例中它比生成器表达式长,但当您想要一次选择多个元素时,它实际上会更短:
result_1 = map(lambda x: (x[0], x[2], x[3]), numbers)
result_2 = ((x[0], x[2], x[3]) for x in numbers)
result_3 = map(itemgetter(0, 2, 3), numbers)
# [(0, 2, 3), (4, 6, 7), (8, 0, 1)]
Run Code Online (Sandbox Code Playgroud)
您还可以使用itemgetter字典:
data = [{'time': 0, 'temperature': 290, 'pressure': 1.01},
{'time': 10, 'temperature': 295, 'pressure': 1.04},
{'time': 20, 'temperature': 300, 'pressure': 1.07}]
result_1 = map(lambda x: (x['time'], x['pressure']), data)
result_2 = ((x['time'], x['pressure']) for x in data)
result_3 = map(itemgetter('time', 'pressure'), data)
# [(0, 1.01), (10, 1.04), (20, 1.07)]
Run Code Online (Sandbox Code Playgroud)attrgetter
这个用于获取对象的属性:
from collections import namedtuple
from operator import attrgetter
Person = namedtuple('Person', ['name', 'surname', 'age', 'car'])
people = [Person(name='John', surname='Smith', age=40, car='Tesla'),
Person(name='Mike', surname='Smith', age=50, car=None)]
result_1 = map(lambda x: (x.name, x.age, x.car), people)
result_2 = ((x.name, x.age, x.car) for x in people)
result_3 = map(attrgetter('name', 'age', 'car'), people)
# [('John', 40, 'Tesla'), ('Mike', 50, None)]
Run Code Online (Sandbox Code Playgroud)
它比生成器表达式版本长,所以我将它留在这里只是为了完整性。当然,您可以导入attrgetterasget并且它会更短,但没有人真正这样做。attrgetter但是,Using有一个优势,您可以将其作为单独的可调用对象取出,可以多次使用(与 相同lambda):
get_features = attrgetter('name', 'age', 'car')
group_1_features = map(get_features, people)
group_2_features = map(get_features, other_people)
...
Run Code Online (Sandbox Code Playgroud)
另一个值得一提的替代fget方法是使用属性方法:
result = map(Person.age.fget, people)
Run Code Online (Sandbox Code Playgroud)
不过,我从未见过有人使用它,所以准备好向那些会阅读你的代码的人解释一下,如果你使用它。
contains:
用于检查元素是否存在于另一个对象/容器中:
from functools import partial
from operator import contains
fruits = {'apple', 'peach', 'orange'}
objects = ['apple', 'table', 'orange']
result_1 = map(lambda x: x in fruits, objects)
result_2 = (x in fruits for x in objects)
is_fruit = partial(contains, fruits)
result_3 = map(is_fruit, objects)
# [True, False, True]
Run Code Online (Sandbox Code Playgroud)
但是,这具有创建附加partial对象的缺点。另一种写法是使用__contains__方法:
result = map(fruits.__contains__, objects)
Run Code Online (Sandbox Code Playgroud)
但是有些人认为使用 dunder 方法是一种不好的做法,因为这些方法仅供私人使用。
数学运算:
例如,如果您想对成对的数字求和,您可以使用operator.add:
from itertools import starmap
from operator import add
pairs = [(1, 2), (4, 3), (1, 10), (2, 5)]
result_1 = map(lambda x: x[0] + x[1], pairs)
result_2 = (x + y for x, y in pairs)
result_3 = starmap(add, pairs)
# [3, 7, 11, 7]
Run Code Online (Sandbox Code Playgroud)
如果您对两个额外的导入没问题,那么这是最短的选择。请注意,我们itertools.starmap在这里使用是因为我们需要在将数字元组提供给add(a, b)函数之前对其进行解包。
我想我涵盖了我经常遇到的大多数情况,这些情况可以在没有lambda. 如果您知道更多,请写在评论中,我会将其添加到我的答案中。