class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print Parent.x, Child1.x, Child2.x Child1.x = 2 print Parent.x, Child1.x, Child2.x Parent.x = 3 print Parent.x, Child1.x, Child2.x
以上代码的输出是:
php
1 1 1 1 2 1 3 2 3
在 Python 中,类变量在内部是做为字典处理的。若是一个变量的名字没有在当前类的字典中发现,将搜索祖先类(好比父类)直到被引用的变量名被找到(若是这个被引用的变量名既没有在本身所在的类又没有在祖先类中找到,会引起一个AttributeError
异常 )python
在父类中设置 x = 1
会使得类变量 X
在引用该类和其任何子类中的值为 1。若是任何它的子类重写了该值(例如,咱们执行语句 Child1.x = 2
),而后,该值仅仅在子类中被改变。算法
若是该值在父类中被改变(例如,咱们执行语句 Parent.x = 3
),这个改变会影响到任何未重写该值的子类当中的值(在这个示例中被影响的子类是 Child2
)apache
def div1(x,y): print("%s/%s = %s" % (x, y, x/y)) def div2(x,y): print("%s//%s = %s" % (x, y, x//y)) div1(5,2) div1(5.,2) div2(5,2) div2(5.,2.)
这个答案实际依赖于你使用的是 Python 2 仍是 Python 3。编程
在 Python 3 中,指望的输出是:segmentfault
5/2 = 2.5 5.0/2 = 2.5 5//2 = 2 5.0//2.0 = 2.0
在 Python 2 中,尽管如此,以上代码的输出将是:闭包
5/2 = 2 5.0/2 = 2.5 5//2 = 2 5.0//2.0 = 2.0
默认,若是两个操做数都是整数,Python 2 自动执行整型计算。结果,5/2
值为 2
,然而 5./2
值为 ```2.5``。app
注意,尽管如此,你能够在 Python 2 中重载这一行为(好比达到你想在 Python 3 中的一样结果),经过添加如下导入:编程语言
from __future__ import division
也须要注意的是“双划线”(//)操做符将一直执行整除,而无论操做数的类型,这就是为何 5.0//2.0
值为 2.0
。ide
注: 在 Python 3 中,/
操做符是作浮点除法,而 //
是作整除(即商没有余数,好比 10 // 3 其结果就为 3,余数会被截除掉,而 (-7) // 3
的结果倒是 -3
。这个算法与其它不少编程语言不同,须要注意,它们的整除运算会向0的方向取值。而在 Python 2 中,/
就是整除,即和 Python 3 中的 //
操做符同样,)
list = ['a', 'b', 'c', 'd', 'e'] print list[10:]
答案
以上代码将输出 []
,而且不会致使一个 IndexError
。
正如人们所指望的,试图访问一个超过列表索引值的成员将致使 IndexError
(好比访问以上列表的 list[10]
)。尽管如此,试图访问一个列表的以超出列表成员数做为开始索引的切片将不会致使 IndexError
,而且将仅仅返回一个空列表。
一个讨厌的小问题是它会致使出现 bug ,而且这个问题是难以追踪的,由于它在运行时不会引起错误。
def multipliers(): return [lambda x : i * x for i in range(4)] print [m(2) for m in multipliers()]
答案
以上代码的输出是 [6, 6, 6, 6]
(而不是 [0, 2, 4, 6]
)。
这个的缘由是 Python 的闭包的后期绑定致使的 late binding,这意味着在闭包中的变量是在内部函数被调用的时候被查找。因此结果是,当任何 multipliers()
返回的函数被调用,在那时,i
的值是在它被调用时的周围做用域中查找,到那时,不管哪一个返回的函数被调用,for
循环都已经完成了,i
最后的值是 3
,所以,每一个返回的函数 multiplies
的值都是 3。所以一个等于 2 的值被传递进以上代码,它们将返回一个值 6 (好比: 3 x 2)。
(顺便说下,正如在 The Hitchhiker’s Guide to Python 中指出的,这里有一点广泛的误解,是关于 lambda
表达式的一些东西。一个lambda
表达式建立的函数不是特殊的,和使用一个普通的 def
建立的函数展现的表现是同样的。)
这里有两种方法解决这个问题。
最广泛的解决方案是建立一个闭包,经过使用默认参数当即绑定它的参数。例如:
def multipliers(): return [lambda x, i=i : i * x for i in range(4)]
另一个选择是,你可使用 functools.partial
函数:
from functools import partial from operator import mul def multipliers(): return [partial(mul, i) for i in range(4)]
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']
许多人会错误的认为 list1
应该等于 [10]
以及 list3
应该等于 ['a']
。认为 list
的参数会在 extendList
每次被调用的时候会被设置成它的默认值 []
。
尽管如此,实际发生的事情是,新的默认列表仅仅只在函数被定义时建立一次。随后当 extendList
没有被指定的列表参数调用的时候,其使用的是同一个列表。这就是为何当函数被定义的时候,表达式是用默认参数被计算,而不是它被调用的时候。
所以,list1
和 list3
是操做的相同的列表。而 ````list2是操做的它建立的独立的列表(经过传递它本身的空列表做为
list``` 参数的值)。
extendList
函数的定义能够作以下修改,但,当没有新的 list
参数被指定的时候,会老是开始一个新列表,这更加多是一直指望的行为。
def extendList(val, list=None): if list is None: list = [] list.append(val) return list
使用这个改进的实现,输出将是:
list1 = [10] list2 = [123] list3 = ['a']
本文出处:https://segmentfault.com/a/1190000000618513