以下是一道新浪微博面试题,我们将详细拆解该题目。
data_list = [lambda x: x + i for i in range(10)] # [函数, 函数, 函数] i=9
v1 = data_list[0](100)
v2 = data_list[3](100)
print(v1, v2) # 109 109
如果不仔细阅题,可能会得出"100"和"102"的答案。有趣的是,如果将此题目输入ChatGPT-4或Kimi,它们会给出"100"和"103"的答案。唯一给出正确答案的是Claude 3.5(值得表扬)。
为了便于后续拆解题目,让我们先复习一些相关知识:
推导式 #
推导式(Comprehension)是Python中一种简洁而强大的语法特性,用于创建列表、字典、集合或生成器。它允许你用一行简洁的代码替代更冗长的for循环。让我们详细了解各种类型的推导式:
-
列表推导式(List Comprehension):
基本语法:
[expression for item in iterable if condition]
例子:
squares = [x**2 for x in range(10)] # 结果:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
-
字典推导式(Dictionary Comprehension):
基本语法:
{key_expression: value_expression for item in iterable if condition}
例子:
square_dict = {x: x**2 for x in range(5)} # 结果:{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
-
集合推导式(Set Comprehension):
基本语法:
{expression for item in iterable if condition}
例子:
even_squares = {x**2 for x in range(10) if x % 2 == 0} # 结果:{0, 4, 16, 36, 64}
-
生成器表达式(Generator Expression):
基本语法:
(expression for item in iterable if condition)
例子:
gen = (x**2 for x in range(10)) # 创建一个生成器对象,可以逐个生成平方数
特点和注意事项:
- 简洁性:推导式通常比等效的for循环更简洁。
- 可读性:对于简单操作,推导式可提高代码可读性。但对于复杂逻辑,可能会降低可读性。
- 性能:在某些情况下,推导式可能比等效的for循环更高效。
- 条件筛选:可以使用if子句进行筛选。
- 嵌套:可以使用嵌套的for循环。
例如:
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
- 变量作用域:推导式有自己的局部作用域。
- lambda函数:可以在推导式中使用lambda函数。
示例:结合多个特性的复杂推导式
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row if num % 2 != 0]
# 结果:[1, 3, 5, 7, 9]
推导式是Python中非常有用的特性,能够使代码更加简洁和富有表现力。但是,过度使用或在复杂情况下使用可能会降低代码的可读性,所以需要权衡使用。
匿名函数 #
Python中的匿名函数通常被称为lambda
函数。它们是简洁的一行函数,没有名字,适合用于需要简单功能的小场景。以下是关于匿名函数的定义、使用场景、原理和一些例子的详细介绍。
定义 #
匿名函数使用lambda
关键字定义,语法如下:
lambda 参数1, 参数2, ... : 表达式
例如,一个简单的匿名函数如下:
add = lambda x, y: x + y
print(add(3, 5)) # 输出: 8
使用场景 #
- 简化代码:在需要简单功能的地方,如排序、过滤等,可以使用匿名函数,避免定义额外的函数。
- 函数式编程:与高阶函数(如
map
、filter
、reduce
)一起使用,可以使代码更简洁。 - 回调函数:在事件处理或异步编程中,匿名函数可以作为回调函数传递。
原理 #
匿名函数本质上是一个内联函数(inline function),它在定义时即创建,不需要命名。与普通函数不同,匿名函数只能包含一个表达式,不能包含复杂的语句或多行代码。这使得匿名函数非常轻量,适合用于简单的操作。
题目代码拆解 #
根据上面的两个知识点,我们可以将
data_list = [lambda x: x + i for i in range(10)]
代码拆解成常规函数的样子,如下:
data_list = []
for i in range(10):
def func(x):
return x + i
data_list.append(func)
起初,我理所当然地将函数拆解成了如下的样子:
# 错误写法
data_list = []
def func(x):
for i in range(10):
return x + i
分析列表推导式
data_list = [lambda x: x + i for i in range(10)]
首先确定的应该是data_list的元素,也就是for前面的部分lambda x: x + i。这意味着匿名函数是列表的元素。所以可以写成:
for i in range(10):
lambda x: x + i
进而可以整理出它的完整函数写法(如上所示)。
接下来查看
v1 = data_list[0](100) # 列表第1个函数,参数x为100
v2 = data_list[3](100) # 列表第4个函数,参数x为100
print(v1, v2) # 109 109
这里需要确定的是隐藏参数i的值。由于Python的后期绑定特性,i的值都为9。因此,可以确定v1和v2都是109。
#Python学习记录最后一次修改于 2024-08-18