Python中值得注意的几点,你真的知道吗?

举报
Python爱好者 发表于 2020/12/28 22:53:15 2020/12/28
【摘要】 1、下面这段代码的输出结果将是什么?请解释。 def multi():    return [lambda x:i*x for i in range(4)]print([m(2) for m in multi()]) 你如何修改上面的multipliers的定义产生想要的结果? 上面代码输出的结果是[6, 6, 6, 6]...

640?wx_fmt=gif



1、下面这段代码的输出结果将是什么?请解释。


def multi():
   return [lambda x:i*x for i in range(4)]
print([m(2) for m in multi()])



你如何修改上面的multipliers的定义产生想要的结果?

上面代码输出的结果是[6, 6, 6, 6] (不是我们想的[0, 2, 4, 6])。


上述问题产生的原因是Python闭包的延迟绑定。这意味着内部函数被调用时,参数的值在闭包内进行查找。因此,当任何由multipliers()返回的函数被调用时,i的值将在附近的范围进行查找。那时,不管返回的函数是否被调用,for循环已经完成,i被赋予了最终的值3。


因此,每次返回的函数乘以传递过来的值3,因为上段代码传过来的值是2,它们最终返回的都是6。(3*2)碰巧的是,《The Hitchhiker’s Guide to Python》也指出,在与lambdas函数相关也有一个被广泛被误解的知识点,不过跟这个case不一样。由lambda表达式创造的函数没有什么特殊的地方,它其实是和def创造的函数式一样的。



那如何使输出的结果变成我们想要的0,2,4,6呢?

答案:创造一个闭包,利用默认函数立即绑定

def multi2():
return [lambda x,i =i:i*x for i in range(4)]


这样我们再调用的时候就能输出正常的结果。


还有第二种方法,利用python自己的生成器也能获得答案:

def multi3():
for i in range(4):
yield lambda x:i*x



2、下面这段代码的输出结果将是什么?请解释。


class A:
x=1
class B(A):
pass
class C(A):
pass
print(A.x,B.x,C.x)

B.x=2
print(A.x,B.x,C.x)

A.x=4
print(A.x,B.x,C.x)



输出:

1 1 1

1 2 1

4 2 4



在Python中,类变量在内部是以字典的形式进行传递。


如果一个变量名没有在当前类下的字典中发现。则在更高级的类(如它的父类)中尽心搜索直到引用的变量名被找到。(如果引用变量名在自身类和更高级类中没有找到,将会引发一个属性错误。)


因此,在父类中设定x = 1,让变量x类(带有值1)能够在其类和其子类中被引用到。这就是为什么第一个打印语句输出结果是1 1 1


因此,如果它的任何一个子类被覆写了值(例如说,当我们执行语句B.x = 2),这个值只在子类中进行了修改。这就是为什么第二个打印语句输出结果是1 2 1


最终,如果这个值在父类中进行了修改,(例如说,当我们执行语句A.x = 3),这个改变将会影响那些还没有覆写子类的值(在这个例子中就是C)这就是为什么第三打印语句输出结果是4 2 4


(其实,这在python3中很好理解,他们都是新式类,但是再python2中就很折腾,对于经典类来说,这很折腾)





3、下面这段代码的输出结果将是什么?请解释。

 
 
list = ['a', 'b', 'c', 'd', 'e']

print(list[10:])


下面的代码将输出[],不会产生IndexError错误。就像所期望的那样,尝试用超出成员的个数的index来获取某个列表的成员。


例如,尝试获取list[10]和之后的成员,会导致IndexError.


然而,尝试获取列表的切片,开始的index超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。




4、下面代码的输出结果将是什么?

list = [ [ ] ] * 5
print(list)
list[0].append(10)
print(list)
list[1].append(20)
print(list)
list.append(30)
print(list)

输出:

[[], [], [], [], []]

[[10], [10], [10], [10], [10]]

[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]

[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]


第一行的输出结果直觉上很容易理解,例如 list = [ [ ] ] * 5 就是简单的创造了5个空列表。然而,理解表达式list=[ [ ] ] * 5的关键一点是它不是创造一个包含五个独立列表的列表,而是它是一个创建了包含对同一个列表五次引用的列表。只有了解了这一点,我们才能更好的理解接下来的输出结果。


list[0].append(10) 将10附加在第一个列表上。


但由于所有5个列表是引用的同一个列表,所以这个结果将是:


[[10], [10], [10], [10], [10]]


同理,list[1].append(20)将20附加在第二个列表上。但同样由于5个列表是引用的同一个列表,所以输出结果现在是:


[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].


作为对比, list.append(30)是将整个新的元素附加在外列表上,因此产生的结果是: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].









640?wx_fmt=jpeg


听说有气质的人都会关注这个公众号!

640?wx_fmt=jpeg


文章来源: blog.csdn.net,作者:敲代码的灰太狼,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/tongtongjing1765/article/details/100581724

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。