Python【知识点】面试小点列表生成式小坑

1、问题

有这么一个小面试题:

看下面代码请回答输出的结果是什么?为什么?

result = [lambda x: x + i for i in range(10)]
print(result[0](10))

2、解答

当你看到这篇文章的时候如果不知道这个知识点肯定会拿去直接运行,输出的结果是什么呢?

结果是:19

通过result[0~9](10)结果都是19就,懵逼了吧~~

想知道这个我们先看几个知识点

2.1、列表生成式

顾名思义,列表生成式就是一个用来生成列表的特定语法形式的表达式。

语法格式:

[expression for iterable_var in iterable]

工作过程:

  • 迭代iterable的每个元素
  • 把迭代的值赋值给iterable_var,然后通过expression的表达式进行计算得到一个新的值
  • 最后把所有expression的值以新列表的形式返回

工作过程类似于:

L = []

for i in range(10):
    # 举例expression 表达式 iterable_var * 5 ,最后把这个结果加到列表中
    L.append(i * 5)  

点到为止,我们来看下我们的这个小面试题

result = [lambda x: x + i for i in range(10)]
# 后面的lambada x:x +i 为expression 这是一个普通的lambada表达式那他生成的结果是什么? 一个一个的函数
# 看下面的例子就舒服多了
L = []

for i in range(10):
    L.append(lambda x: x + i)

那在我们执行result[0](10),其实就是在执行lambda 10: 10 + i ,但是为什么每个i都是9呢?

2.2、函数内部变量的后期绑定(last binding)

我们在写一个函数的时候,函数内不保存这个变量的值,而是在执行的时候去找这个值在哪里绑定上的。

举个例子来说我们在函数中定引用了一个变量,可以不需要提前定义我们只要在使用前定义就可以了,如下面代码

def func():
    print(foo)

foo = "hello tim"

func()

注:这里有个点稍微提醒下,调用函数时这个函数必须是提前定义好的,这个我们称之为“前向引用”,而函数内部变量可以后期再定义,我们称之为“后期绑定”

因为这个变量不是在lambda内定义的,而是在列表生成式内定义的,我先把列表生成式翻译一下:

def make_list():
    L =[]
    for i in range(10):
        def inner(arg):
            return i + arg
        L.append(inner)
    return L

result = make_list()
print(result[2](10))

看上面的代码最后返回的都是一个一个的函数,而这个i的值是在循环的时候赋值的,那我们知道这个i的值不是在,inner(lambda)函数中定义的,而是引用的上层函数的变量,当我们使用inner去调用的时候,这时这个for循环已经结束了,i的值也就变成固定了9

所以每当我们通过函数lambda x: x + i 的时候这个i永远是9

2.3、小作修改

那如果说我不想要这样的结果,我想要i是循环的值怎么办,不要直接引用上层变量,把变量传进来就可以了

result = [lambda x, i=i, : x + i for i in range(10)]
print(result[1](10))

翻译一下

def make_list():
    L =[]
    for i in range(10):
        def inner(arg, i=i):
            return i + arg
        L.append(inner)
    return L

result = make_list()
print(result[2](10))

2.4、闭包

简单解释下这个概念,在嵌套函数内,嵌套函数应用上层函数的变量(不是全局变量)称之为闭包,

def func():
    x = 1

    def inner():
        print(x)

当我们执行func的时候就会生成一个闭包,func执行完后里面的变量x不会被回收,因为嵌套函数inner还在使用它,常见的应用场景就是我们的装饰器

时间: 2024-10-10 00:05:37

Python【知识点】面试小点列表生成式小坑的相关文章

【Python&知识点】2个列表合成一个字典

·放一些网上的链接:https://baijiahao.baidu.com/s?id=1617397248551208688&wfr=spider&for=pc python,2列表组合成一个字典list_1 = [1,2,3,4,5,6] list_2 = ['a','b','c','d','e','f'] 方法一:dict(map(lambda x,y:[x,y],list_1,list_2)) 方法二:dict(zip(list_1,list_2)) 最简便!!! 输出:{1: 'a

Python高级特性:Python迭代、生成器、列表生成式

迭代 给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历称为迭代(Iteration). 在java和C语言中,迭代是通过循环list的下标来完成的,Python中迭代的抽象程度更高,不仅可以迭代list和tuple,而且可以迭代任何可迭代对象,包括我们自己创建的数据类型,只要符合迭代条件,无论有无下标,都可以使用for循环. Python中的迭代是通过for -in -来完成的. 字典的迭代 比如字典就是可以迭代的: 1 >>> d = {'a

python学习日常-切片&迭代&列表生成式

切片:顾名思义,就是将一个东西切成一块一块的,python中的切片就是将数组切成一片一片的 L=list(range(1,100)); L(f:e:p)#f代表开始切的位置,e代表结束的位置(但不包括),p代表切的间隔. 比如L(10:26:2)代表从第10位开始切(即从数字为11开始)到26结束(即数字27),但是不包括第26位,其中间隔为2. 切片也支持从后面切比如L(-10:-1:none)就是从倒数第10位开始切到最后一位. 值得注意的是切片的三个参数都是可以缺省的. 迭代:非常简单的一

Python 入门(十)列表生成式

生成列表 要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],我们可以用range(1, 11): >>> range(1, 11) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环: >>> L = [] >>> for x in range(1, 11): ... L.append(x * x) ... >>

Python知识点——面试常考题

1.python中在使用while时,可以与else一起使用.即当条件不满足时不是跳出循环,而是执行else后面的语句后再跳出循环 2.python中不用声名变量,可以直接使用 3.python中的数据类型有1)数字:int double 等2)字符串:用"" '' 表示.单个字符也默认为字符串.字符串可索引和单个提取.3)元组:特殊的字符串,用()4)列表:用[]5)集合:用{}或set()6)字典:字典和以上差别较大,多了一个关键字的定义:用d = {key1 : value1,

python学习进度9(列表生成式,生成器和迭代器)

列表生成式 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11)): >>> list(range(1, 11)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环: >>>

PYTHON学习0034:函数---列表生成式和生成器---2019-6-29

```也可以在列表生成器里加三元运算:a=[i5 if i>5 else i2 for i in range(11)]print(a)输出为:[0, 2, 4, 6, 8, 10, 30, 35, 40, 45, 50] 列表生成器格式: a=(i for i in range(10) print(a) 输出为: <generator object <genexpr> at 0x0000000001DC77C8> 并没有输出列表,只是返回了一个表达式,generato就是列表

python高级特征:列表生成式;generator, 迭代器。

Python高级特性 列表生成式:不过一种语法糖 生成器:不过一个方法 迭代器: 列表生成式 Python内置的函数,来创建list. 简单的生成: >>> list(range(1,11)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 复杂的生成:增加一个for循环. >>> a = [x*x for x in range(1, 11)] >>> a [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 还

[Python]小甲鱼Python视频第012课(列表:一个打了激素的数组3)课后题及参考解答

# -*- coding: utf-8 -*- """ Created on Tue Mar 5 22:43:25 2019 @author: fengs """ """ 测试题: 0. 注意,这道题跟上节课的那道题有点儿不同,回答完请上机实验或参考答案. >>> old = [1, 2, 3, 4, 5] >>> new = old >>> old = [6]