错题整合(1)

错题整合

1 读取文件最后一行

f = open('file_modify.txt', 'rb')
offset = -10
while True:
    f.seek(offset, 2)
    if len(f.readlines()) > 1:
        print(f'最后一行是{f.readlines()[-1].decode("utf-8")}')
        break
    offset *= 2

解析:

先估算最后一行的大概长度,然后根据最后seek方法从最后位置往前定光标位置,首先光标位置给小一点,再根据f.readline()读取内容,判断读取内容是否有一行,没有一行的话,加大偏移位置,有一行的读取出来,并break。

2 判断下面代码运行的结果。

def extendList(val,list=[]):
    list.append(val)
    return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print('list1=%s'%list1)
print('list2=%s'%list2)
print('list3=%s'%list3)

运行结果:
list1=[10, 'a']
list2=[123]
list3=[10, 'a']
默认列表的使用

解析:

函数参数中如果默认参数定义了空列表,如果函数第一次调用中使用了默认的空列表,函数体对这个列表进行修改,第二次调用的参数还是用默认空列表时,此时的列表是之前调用时修改后的列表,也就不是默认的空列表。

如果第二次调用给定参数是空列表,而不是使用默认的空列表,则此时对列表修改用的是传入的空列表参数。

3 迭代器只能迭代一次,判断下面代码运行的结果?

def g_test():
    """定义一个生成器"""
    for i in range(4):
        yield i
t = g_test()
for i in t:
    print(i)  # 结果:0,1,2,3

t_g = (i for i in t)
print(list(t_g))  # 结果:[]
迭代器遍历次数

解析:t = g_test() 获取了一个生成器函数产生的一个迭代器对象,但是t里面没有任何值,使用for循环是对t使用.__next__()方法执行迭代器对象,获取返回的值。因为for已经对迭代器遍历完了,而迭代器只能遍历一次所以当t_g生成器表达式再次遍历t时,什么也没有遍历到,得到的t_g是个空的迭代器,用list转换后得到一个空列表。

4 生成器表达式内在运行机制,和list运行机制。

def g_test():
    """定义一个生成器"""
    for i in range(4):
        yield i

t = g_test()

t1 = (i for i in t)
t2 = (i for i in t1)

print(list(t1))
print(list(t2))
# 运行结果
# [0, 1, 2, 3]
# []
生成器表达式运行机制

解析:

生成器返回的是一个迭代器对象,但是有三点需要注意:第一个是迭代器只能遍历一次;第二个,生成器在复制给变量时,并没有运行调用执行迭代器。第三个,对象迭代器对象并不是一个容器类型的数据,本身并没有任何值,而是根据next方法依次取值。

本题中,在表达式t1=(i for i in t)时,生成器表达式只是生成了一个迭代器对象,并没有调用生成器执行,所以这一步也没有遍历t,同理t2=(i for i in t1)也没有遍历t1。当知道list(t1)时,list开始

5 求下面代码运行结果

v = [lambda :x for x in range(10)]
print(v)
print(v[0])
print(v[0]())
View Code

解析:

[lambda :x for x in range(10)]是一个列表推导式,等效于下面代码

v = []
for x in range(10):
def func():
return x
v.append(func)

因为for循环了10次,所以列表v中生成了10个函数,都是func,内部代码都是return x,但是都没有调用,当取出第一个函数调用时,for循环已经完成,x的值已指向9存在全局。函数func没有参数传入,所以去全局找x返回,所以返回的是9。对内部所有函数都是这样,调用的时候取得值都是9.

6 求下面代码运行结果

v = (lambda :x for x in range(10))
print(v)  # 生成器
print(v[0])  # 报错
print(v[0]())  # 报错
print(next(v))  # 第一个函数的内存地址
print(next(v)()) # 1,第二个函数调用,此时x=1,所返回1
View Code

解析:

首先 (lambda :x for x in range(10))就是一个生成器表达式,赋值给v,所以v就是一个生成器,所以v[0]和v[0]()会报错,但是这个时候的生成器仅仅只是一个生成器,没有next取值,通过next取值,获取的是当x=0的时候,生成器返回的lambda : x函数,所以next(v)返回的是一个匿名函数的地址,注意,此时生成器是驻留的状态,x是0并没有在for中累加。当我们又一次使用next(v)()时,已经是第二次next取值,此时我们获取的是当x=1的时候,生成器返回的lambda : x函数,然后对匿名函数调用,传入参数1,所以打印的结果是1。

 

posted @ 2019-03-29 19:45  ryxiong728  阅读(103)  评论(0)    收藏  举报