Python是关于简单易读的代码。它比版本更好,我是一个巨大的粉丝!但是,每次我必须定义lambda时输入l
a
m
b
d
a
并不好玩(您可能不同意)。
问题是,这些6个字符l
a
m
b
d
a
使我的声明更长,因为我在{{}}内嵌了几个lambdas { {1}} s和map
s(我没有嵌套超过2或3,因为它消除了python的可读性 - 这里没有参数!)
filter
我很乐意添加这样的导入:
# 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)
答案 0 :(得分:11)
好消息是:您根本不需要使用map
或filter
,您可以使用generator expressions(懒惰)或list comprehensions(渴望) )而是完全避免lambda
。
所以而不是:
lines = map(lambda x: x.strip(), sys.stdin)
只需使用:
# 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)
如果你使用理解,它可能也会更快。在map
或filter
中使用时,很少有函数实际上更快 - 并且使用lambda
有更多的反模式(和慢速)。
该问题仅包含map
的示例,但您也可以替换filter
。例如,如果您想要filter
输出奇数:
filter(lambda x: x%2==0, whatever)
您可以改为使用条件理解:
(x for x in whatever if x%2==0)
[x for x in whatever if x%2==0]
您甚至可以在一个理解中合并map
和filter
:
(x*2 for x in whatever if x%2==0)
考虑使用map
和filter
:
map(lambda x: x*2, filter(lambda x: x%2==0, whatever))
注意:这并不意味着lambda
并不有用!有很多地方lambda
非常方便。考虑key
argument for sorted
(同样适用于min
和max
)或functools.reduce
(但最好远离该功能,大部分时间都是正常for
- 循环更具可读性)或itertools
需要谓词函数:itertools.accumulate
,itertools.dropwhile
,itertools.groupby
和itertools.takewhile
。仅举一些lambda
可能有用的例子,可能还有很多其他地方。
答案 1 :(得分:4)
为了回答您的具体问题,operator
模块提供了一些功能,旨在取代lambda
表达式的特定用途。在这里,您可以使用methodcaller
函数创建一个调用对象上给定方法的函数。
from operator import methodcaller as mc
lines = map(mc('strip'), sys.stdin)
但是,对于map
的许多(如果不是大多数)使用,列表推导往往更受欢迎。
lines = [x.strip() for x in sys.stdin]
答案 2 :(得分:1)
作为一个除了调试目的外,从不在其代码中使用lambda的人,我可以提出几种替代方案。
我不会谈论defining your own syntax in an editor(尽管您不能在纯Python中定义运算符:Python: defining my own operators?),但是只涉及内置内容。
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']
将map
与str.upper
一起使用要比map
与lambda
和another answer中建议的生成器表达式短。int
,float
,str
,bytes
等。同样的方式。例如,检查数字是否为整数:
numbers = [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]
Class methods:
您可以通过类似的方式将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]
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]
虽然它比给定示例中的生成器表达式长,但是当您要一次选择多个元素时,它实际上会更短:
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)]
您还可以将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)]
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)]
它比生成器表达式版本长,因此为了完整起见,我将其保留在此处。当然,您可以将attrgetter
导入为get
,它会更短一些,但没有人真正这样做。不过,使用attrgetter
有一个优势,您可以将它作为一个单独的可调用对象取出,并可以多次使用(与lambda
相同):
get_features = attrgetter('name', 'age', 'car')
group_1_features = map(get_features, people)
group_2_features = map(get_features, other_people)
...
另一个值得一提的替代方法是使用属性fget
:
result = map(Person.age.fget, people)
虽然我从未见过有人在使用它,所以请准备对将使用您的代码的人进行解释。
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]
但这有一个缺点,那就是创建一个额外的partial
对象。编写此内容的另一种方法是使用__contains__
方法:
result = map(fruits.__contains__, objects)
但是有些人认为使用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]
如果您可以再添加两个导入,则这是最短的选择。请注意,我们在这里使用itertools.starmap
是因为我们需要先将数字元组解包,然后再将其提供给add(a, b)
函数。
我认为我涵盖了我经常遇到的大多数情况,这些情况可以不用lambda
来重写。如果您了解更多信息,请在评论中写下它,我会将其添加到我的答案中。