一个python新浪面试题

Finder / 2024-08-18


以下是一道新浪微博面试题,我们将详细拆解该题目。

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循环。让我们详细了解各种类型的推导式:

  1. 列表推导式(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]
    
  2. 字典推导式(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}
    
  3. 集合推导式(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}
    
  4. 生成器表达式(Generator Expression):

    基本语法:(expression for item in iterable if condition)

    例子:

    gen = (x**2 for x in range(10))
    # 创建一个生成器对象,可以逐个生成平方数
    

特点和注意事项:

  1. 简洁性:推导式通常比等效的for循环更简洁。
  2. 可读性:对于简单操作,推导式可提高代码可读性。但对于复杂逻辑,可能会降低可读性。
  3. 性能:在某些情况下,推导式可能比等效的for循环更高效。
  4. 条件筛选:可以使用if子句进行筛选。
  5. 嵌套:可以使用嵌套的for循环。 例如:[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
  6. 变量作用域:推导式有自己的局部作用域。
  7. 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

使用场景 #

  1. 简化代码:在需要简单功能的地方,如排序、过滤等,可以使用匿名函数,避免定义额外的函数。
  2. 函数式编程:与高阶函数(如mapfilterreduce)一起使用,可以使代码更简洁。
  3. 回调函数:在事件处理或异步编程中,匿名函数可以作为回调函数传递。

原理 #

匿名函数本质上是一个内联函数(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