Python|关于 Python,一些不得不吐槽的“迷惑行为”( 二 )


firstchild.x = 2print(parent.x firstchild.x secondchild.x) # returns 1 2 1

如果这时父母染发 , 孩子的发色会变吗?不会变 , 对不对?
parent.x = 3print(parent.x firstchild.x secondchild.x) # returns 3 2 3

出现这个结果是因为Python的方法解析顺序(http://python-history.blogspot.com/2010/06/method-resolution-order.html) 。 简单来说 , 只要没有另行说明 , 子类就会继承父类拥有的一切 。 也就是说 , 在Python的世界里 , 如果你不提前抗议 , 那么你妈妈在染头发的时候 , 会顺带连你的头发一起染了 。
反方向的作用域我个人已经因为这个问题多次栽跟头 。
在Python中 , 函数内部定义的变量无法在函数外部使用 , 这是因为超出了作用域:
def myfunction(number):basenumber = 2return basenumber*numberbasenumber## Oh no! This is the error:# Traceback (most recent call last):# File \"<stdin>\" line 1 in <module># NameError: name 'basenumber' is not defined

这部分完全符合直觉 , 我栽跟头也不是因为这部分代码 。
但是反过来呢?我的意思是 , 如果我在函数外部定义一个变量 , 然后在函数内部引用它呢?
x = 2def add_5():x = x + 5print(x)add_5()## Oh dear...# Traceback (most recent call last):# File \"<stdin>\" line 1 in <module># File \"<stdin>\" line 2 in add_y# UnboundLocalError: local variable 'x' referenced before assignment

这就很奇怪了 , 不是吗?我们生活在一个有树的世界里 , 虽然平时我们住在房子里 , 但肯定也知道树长什么样子 , 对不对?(树是 x , 房子是 add_5() , 我们是 5……)
有好多次 , 我在某个类中调用另一个类中定义的函数 , 就遇到了错误 。 我花了很长一段时间才找到问题的根源 。
其背后的基本思想是 , 函数内部的 x 与外部的 x 是不同的 , 所以你不能在外部调用它 。
幸运的是 , 这个问题有一个简单的解决方案 , 即在 x 之前加一个global , 让x变成全局变量!
x = 2def add_5():global xx = x + 5print(x)add_5() # works!

所以说 , 如果你认为作用域的目的仅仅是保护函数内部的变量不被外部干扰 , 那就大错特错了 。 在Python中 , 局部作用域也无法访问外部 。
在迭代的过程中修改列表请看如下代码:
mynumbers = [x for x in range(10)
# this is [0 1 2 3 4 5 6 7 8 9
for x in range(len(mynumbers)):if mynumbers[x
%3 == 0:mynumbers.remove(mynumbers[x
)## Ew! # Traceback (most recent call last):# File \"<stdin>\" line 2 in <module># IndexError: list index out of range

这个循环出错 , 是因为循环在迭代的过程中不断删除列表中的元素 。 因此 , 列表不断缩短 , 循环不可能到达第10个元素 , 因为它不存在了!
有一种解决方法是 , 为你想删除的所有元素统一分配一个值 , 然后在循环结束后删除它们 。
此外 , 似乎还有一种更好的解决方式:
mynumbers = [x for x in range(10) if x%3 != 0
# that's what we wanted! [1 2 4 5 7 8


只需要一行代码!
请注意 , 在上面的示例中 , 我们使用了 Python 的列表推导式来调用列表 。
列表推导式指的是方括号([
)中的表达式 , 一般都是循环的缩写形式 。 列表推导式通常比常规循环更快 , 因此非常适合处理大型数据集 。
在这个示例中 , 我们添加了一个 if 子句来告诉列表推导式:不应包含可被 3 整除的数字 。
这个问题与前面的几个不同 , 我不认为这是Python的迷惑行为 , 相反我认为这种处理很聪明 , 尽管初学者理解起来会有些困难 。
总结实际上 , 我们对Python的不满不只是编写代码的痛苦 , 别忘了 , 以前Python的执行速度非常慢 , 比大多数其他语言慢 2~10 倍 。