Python中值得注意的几点,你真的知道吗?
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].
听说有气质的人都会关注这个公众号!
文章来源: blog.csdn.net,作者:敲代码的灰太狼,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/tongtongjing1765/article/details/100581724
- 点赞
- 收藏
- 关注作者
评论(0)