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

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值