📜  在Python中过度使用 lambda 表达式

📅  最后修改于: 2022-05-13 01:55:07.638000             🧑  作者: Mango

在Python中过度使用 lambda 表达式

什么是 lambda 表达式?
lambda 表达式是一种用于创建没有名称的函数的特殊语法。这些函数称为 lambda 函数。这些 lambda 函数可以有任意数量的参数,但只有一个表达式和一个隐式返回语句。 Lambda 表达式返回函数对象。例如,考虑 lambda 表达式:

lambda (arguments) : (expression)

这个 lambda 表达式定义了一个未命名的函数,它接受两个参数并返回两个参数的和。但是我们如何调用一个未命名的函数呢?上面定义的未命名的lambda函数可以调用为:

(lambda x, y: x + y)(1, 2)

代码 1:

Python3
# Python program showing a use
# lambda function
 
# performing a addition of three number
x1 = (lambda x, y, z: (x + y) * z)(1, 2, 3)
print(x1)
 
# function using a lambda function     
x2 = (lambda x, y, z: (x + y) if (z == 0) else (x * y))(1, 2, 3)
print(x2)


Python3
# Python program showing
# variable is storing lambda
# expression
 
# assigned to a variable
sum = lambda x, y: x + y
print(type(sum))
 
x1 = sum(4, 7)
print(x1)


Python3
# Python program showing
# using of normal function
def Key(x):
    return x%2
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sort = sorted(nums, key = Key)
print(sort)


Python3
# Python program showing use
# of lambda function
 
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sort_lambda = sorted(nums, key = lambda x: x%2)
print(sort_lambda)


Python3
# Python program showing a use
# of lambda function
 
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
 
# using map() function
squares = map(lambda x: x * x, nums)
print(list(squares))
 
# using filter() function
evens = filter(lambda x: True if (x % 2 == 0)
                              else False, nums)
print(list(evens))


Python3
# Python program performing
# operation using def()
def fun(x, y, z):
    return x*y+z
a = 1
b = 2
c = 3
 
# logical jump
d = fun(a, b, c)
print(d)


Python3
# Python program performing
# operation using lambda
 
d = (lambda x, y, z: x*y+z)(1, 2, 3)
print(d)


Python3
def func(x):
    if x == 1:
        return "one"
    else if x == 2:
        return "two"
    else if x == 3:
        return "three"
    else:
        return "ten"
num = func(3)
print(num)


Python3
# Python program showing use
# of lambda function
num = (lambda x: "one" if x == 1 else( "two" if x == 2
                       else ("three" if x == 3 else "ten")))(3)
print(num)


Python3
func = lambda x, y, z: x * y + z
print(func)
def func(x, y, z): return x * y + z
print(func)


Python3
details = [{'p':100, 'r':0.01, 'n':2, 't':4},
           {'p':150, 'r':0.04, 'n':1, 't':5},
           {'p':120, 'r':0.05, 'n':5, 't':2}]
sorted_details = sorted(details,
                        key=lambda x: x['p']*((1 + x['r']/
                                x['n'])**(x['n']*x['t'])))
print(sorted_details)


Python3
details = [{'p':100, 'r':0.01, 'n':2, 't':4},
           {'p':150, 'r':0.04, 'n':1, 't':5},
           {'p':120, 'r':0.05, 'n':5, 't':2}]
def CI(det):
    '''sort key: compound interest, P(1 + r/n)^(nt)'''
    return det['p']*((1 + det['r']/det['n'])**(det['n']*det['t']))
sorted_details = sorted(details, key=CI)
print(sorted_details)


Python3
nums = [0, 1, 2, 3, 4, 5]
mapped = map(lambda x: x * x, nums)
filtered = filter(lambda x: x % 2, nums)
print(list(mapped))
print(list(filtered))


Python3
nums = [0, 1, 2, 3, 4, 5]
mapped = (x * x for x in nums)
filtered = (x for x in nums if x % 2 == 1)
print(list(mapped))
print(list(filtered))


输出:

9
2

尽管不鼓励这样做,但可以将 lambda 表达式返回的函数对象分配给变量。请参阅下面的示例,其中为变量 sum 分配了一个由 lambda 表达式返回的函数对象。

Python3

# Python program showing
# variable is storing lambda
# expression
 
# assigned to a variable
sum = lambda x, y: x + y
print(type(sum))
 
x1 = sum(4, 7)
print(x1)

输出:

11

lambda 表达式的常见用途:

  • 由于 lambda 函数是匿名的并且不需要分配名称,因此它们通常用于调用需要函数对象作为参数的函数(或类) 。为此类函数参数定义单独的函数是没有用的,因为函数定义通常很短,并且在代码中只需要一次或两次。例如,内置函数sorted() 的关键参数。

Python3

# Python program showing
# using of normal function
def Key(x):
    return x%2
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sort = sorted(nums, key = Key)
print(sort)
  • 输出:
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9]

Python3

# Python program showing use
# of lambda function
 
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sort_lambda = sorted(nums, key = lambda x: x%2)
print(sort_lambda)
  • 输出:
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
  • Lambda 函数是内联函数,因此在需要重复函数调用以减少执行时间时使用它们。此类场景的一些示例是函数:map()、filter() 和 sorted()。例如,

Python3

# Python program showing a use
# of lambda function
 
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
 
# using map() function
squares = map(lambda x: x * x, nums)
print(list(squares))
 
# using filter() function
evens = filter(lambda x: True if (x % 2 == 0)
                              else False, nums)
print(list(evens))


lambda 函数的优缺点:
lambda 函数的优点:

  • 由于是匿名的,lambda 函数可以很容易地传递而无需分配给变量。
  • Lambda 函数是内联函数,因此执行速度相对较快。
  • 很多时候 lambda 函数通过避免函数调用引起的逻辑跳转来使代码更具可读性。例如,阅读以下代码块。

Python3

# Python program performing
# operation using def()
def fun(x, y, z):
    return x*y+z
a = 1
b = 2
c = 3
 
# logical jump
d = fun(a, b, c)
print(d)    
  • 输出:
5

Python3

# Python program performing
# operation using lambda
 
d = (lambda x, y, z: x*y+z)(1, 2, 3)
print(d)
  • 输出:
5

lambda函数的缺点:

  • Lambda 函数只能有一个表达式。
  • Lambda 函数不能有文档字符串。
  • 很多时候 lambda 函数使代码难以阅读。例如,请参见下面给出的代码块。

Python3

def func(x):
    if x == 1:
        return "one"
    else if x == 2:
        return "two"
    else if x == 3:
        return "three"
    else:
        return "ten"
num = func(3)
print(num)
  • 输出:
three

Python3

# Python program showing use
# of lambda function
num = (lambda x: "one" if x == 1 else( "two" if x == 2
                       else ("three" if x == 3 else "ten")))(3)
print(num)
  • 输出:
three


滥用 Lambda 表达式:

  • lambda 表达式的赋值:官方Python风格指南 PEP8,强烈反对 lambda 表达式的赋值,如下例所示。
func = lambda x, y, z: x*y + z
  • 相反,建议将单行函数编写为,
def func(x, y, z): return x*y + z 
  • 虽然第二种方法鼓励 lambda 函数是匿名的这一事实,但它对于调试期间的回溯也很有用。运行下面的代码,看看def如何使回溯变得非常有用。

Python3

func = lambda x, y, z: x * y + z
print(func)
def func(x, y, z): return x * y + z
print(func)
  • 将 lambda 表达式包装在函数周围:很多时候,lambda 表达式不必要地包装在函数周围,如下所示。
nums = [-2, -1, 0, 1, 2]
sort = sorted(nums, key=lambda x: abs(x))
  • 虽然上述语法绝对正确,但程序员必须明白, Python中的所有函数都可以作为函数对象传递。因此,相同的代码可以(并且应该)写成,
sort = sorted(nums, key=abs)
  • 不必要地传递函数:很多时候,程序员传递只执行单个操作的函数。请参阅以下代码。
nums = [1, 2, 3, 4, 5]
summation = reduce(lambda x, y: x + y, nums)
  • 上面传递的 lambda函数只执行一个操作,将两个参数相加。使用内置函数sum可以获得相同的结果,如下所示。
nums = [1, 2, 3, 4, 5]
summation = sum(nums)
  • 程序员应避免将 lambda 表达式用于常见操作,因为很可能有一个内置函数提供相同的结果。


过度使用 lambda 表达式:

  • 将 lambda 用于非平凡的函数:有时,简单的函数可能是不平凡的。请参阅下面的代码。

Python3

details = [{'p':100, 'r':0.01, 'n':2, 't':4},
           {'p':150, 'r':0.04, 'n':1, 't':5},
           {'p':120, 'r':0.05, 'n':5, 't':2}]
sorted_details = sorted(details,
                        key=lambda x: x['p']*((1 + x['r']/
                                x['n'])**(x['n']*x['t'])))
print(sorted_details)
  • 输出:
  • 在这里,我们根据复利对字典进行排序。现在,请参阅下面编写的代码,它使用def

Python3

details = [{'p':100, 'r':0.01, 'n':2, 't':4},
           {'p':150, 'r':0.04, 'n':1, 't':5},
           {'p':120, 'r':0.05, 'n':5, 't':2}]
def CI(det):
    '''sort key: compound interest, P(1 + r/n)^(nt)'''
    return det['p']*((1 + det['r']/det['n'])**(det['n']*det['t']))
sorted_details = sorted(details, key=CI)
print(sorted_details)
  • 输出:
  • 虽然这两个代码做同样的事情,但使用def的第二个代码更具可读性。这里写在 lambda 下的表达式可能很简单,但它有一个含义(复利公式)。因此,这个表达式是不平凡的,值得一个名字。对非平凡函数使用 lambda 表达式会降低代码的可读性。
  • 在多行时使用 lambda 会有所帮助:如果使用多行函数使代码更具可读性,那么使用 lambda 表达式来减少一些代码行是不值得的。例如,请参见下面的代码。
  • 另请参阅以下使用def的代码。
def Key(person):
    name, sex, age = person
    return sex
sorted_people = sorted(people, key=Key)
  • 看看第二个代码块中的元组解包如何使其更具可读性和逻辑性。代码的可读性应该是在协作环境中工作的程序员的首要任务。
  • 对 map 和 filter 使用 lambda 表达式:如图所示,Lambda 非常常与 map() 和 filter() 一起使用。

Python3

nums = [0, 1, 2, 3, 4, 5]
mapped = map(lambda x: x * x, nums)
filtered = filter(lambda x: x % 2, nums)
print(list(mapped))
print(list(filtered))
  • 下面是另一个代码块,它使用生成器表达式来实现类似的结果。

Python3

nums = [0, 1, 2, 3, 4, 5]
mapped = (x * x for x in nums)
filtered = (x for x in nums if x % 2 == 1)
print(list(mapped))
print(list(filtered))
  • 与 map() 和 filter() 不同,生成器表达式是Python语言的通用功能。因此生成器增强了代码的可读性。而 map() 和 filter() 则需要这些函数的先验知识。
  • 高阶函数的使用:接受其他函数对象作为参数的函数称为高阶函数(即 map() 和 filter()),这在函数式编程中很常见。如上所述,lambda 表达式通常用作高阶函数的函数参数。比较下面显示的两个代码块。
    使用高阶函数reduce()
nums = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x*y, nums, 1)
  • 不使用高阶函数
nums = [1, 2, 3, 4, 5]
def multiply(nums):
    prod = 1
    for number in nums:
        prod *= number
    return prod
product = multiply(nums)
  • 虽然第一个代码块使用较少的代码行并且不难理解,但没有函数式编程背景的程序员会发现第二个代码块的可读性很高。除非练习正确的函数式编程范式,否则不要将一个函数传递给另一个函数,因为它会降低可读性。