1. 类继承
如下代码
class A(object):
def show(self):
print 'This is calss A'
class B(A):
def show(self):
print 'This is calss B'
obj = B()
obj.show()
如何才能调用类 A 的 show 方法呢?
obj.__class__ = A
obj.show()
__ class __ 方法指向了类对象,只用给他赋值类型 A,然后调用方法 show,但是用完了记得修改回来。
2. 方法对象
问题:为了让下面这段代码运行,需要增加哪些代码?
class A(object):
def __init__(self,a,b):
self.__a = a
self.__b = b
def myprint(self):
print 'a=', self.__a, 'b=', self.__b
a1=A(10,20)
a1.myprint()
a1(80)
答案:为了能让对象实例能被直接调用,需要实现__ call __ 方法
class A(object):
def __init__(self, a, b):
self.__a = a
self.__b = b
def myprint(self):
print 'a=', self.__a, 'b=', self.__b
def __call__(self, num):
print 'call:', num + self.__a
3. __ new __ 和 __ init __
下面这段代码输出什么?
class B(object):
def fn(self):
print 'B fn'
def __init__(self):
print "B INIT"
class A(object):
def fn(self):
print 'A fn'
def __new__(cls,a):
print "NEW", a
if a>10:
return super(A, cls).__new__(cls)
return B()
def __init__(self,a):
print "INIT", a
a1 = A(5)
a1.fn()
a2=A(20)
a2.fn()
输出结果:
NEW 5
B INIT
B fn
NEW 20
INIT 20
A fn
使用__ new __ 方法,可以决定返回那个对象,也就是创建对象之前,这个可以用于设计模式的单例、工厂模式。__ init __ 是创建对象是调用的。
4. 默认方法
如下代码:
class A(object):
def __init__(self,a,b):
self.a1 = a
self.b1 = b
print 'init'
def mydefault(self):
print 'default'
a1 = A(10,20)
a1.fn1()
a1.fn2()
a1.fn3()
方法 fn1/fn2/fn3 都没有定义,怎样修改代码,使得没有定义的方法都调用 mydefault 函数,上面的代码应该输出
default
default
default
答案如下:
class A(object):
def __init__(self,a,b):
self.a1 = a
self.b1 = b
print 'init'
def mydefault(self):
print 'default'
def __getattr__(self,name):
return self.mydefault
a1 = A(10,20)
a1.fn1()
a1.fn2()
a1.fn3()
方法__ getattr __ 只有当没有定义的方法调用时,才是调用他。当 fn1 方法传入参数时,我们可以给mydefault 方法增加一个 *args 不定参数来兼容。
class A(object):
def __init__(self,a,b):
self.a1 = a
self.b1 = b
print 'init'
def mydefault(self,*args):
print 'default:' + str(args[0])
def __getattr__(self,name):
print "other fn:",name
return self.mydefault
a1 = A(10,20)
a1.fn1(33)
a1.fn2('hello')
a1.fn3(10)
输出结果如下:
init
other fn: fn1
default:33
other fn: fn2
default:hello
other fn: fn3
default:10
5. 包管理
一个模块中有很多变量和函数,但有些变量和函数仅被期望于模块内部使用,而不是作为对外公有接口。一个模块对外的公有接口可以通过 __all__
变量来定义,在导入模块的时候,通过 __all__
变量可以指定可导入的部分。如下实例:
#hello.py模块代码
def printInfo():
print('hello, world!')
def printSum(x,y):
print(x+y)
#内部函数,不期望被导出
def __fun__():
print("just for test!")
#通过__all__变量定义模块的公有接口
__all__=['printInfo','printSum']
运行 test.py 模块
hello, world!
135
Traceback (most recent call last):
File "D:\Users\xxx\testI\test.py", line 11, in <module>
__fun__()
NameError: name '__fun__' is not defined
一个包里有三个模块,mod1.py, mod2.py, mod3.py,但使用 from demopack import * 导入模块时,如何保证只有 mod1、mod3 被导入了。
答案:增加__ init __.py 文件,并在文件中增加:
__all__ = ['mod1','mod3']
6. 闭包
写一个函数,接收整数参数n,返回一个函数,函数的功能是把函数的参数和n相乘并把结果返回。
In [8]: def fun(n):
...: def g(val):
...: return n * val
...: return g
...:
...: ff = fun(7)
...: print(ff(9))
...:
63
7. 可变类型作为函数默认参数
下面代码输出结果是什么?
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’],因为他们以为每次 extendList 被调用时,列表参数的默认值都将被设置为[].但实际上的情况是,新的默认列表只在函数被定义的那一刻创建一次。当 extendList 被没有指定特定参数list调用时,这组list的值随后将被使用。这是因为带有默认参数的表达式在函数被定义的时候被计算,不是在调用的时候被计算。
因此 list1 和 list3 是在同一个默认列表上进行操作(计算)的。而 list2 是在一个分离的列表上进行操作(计算)的。(通过传递一个自有的空列表作为列表参数的数值)。
extendList 的定义可以作如下修改。尽管,创建一个新的列表,没有特定的列表参数。
下面这段代码可能能够产生想要的结果。
def extendList(val, list=None):
if list is None:
list = []
list.append(val)
return list
通过上面的修改,输出结果将变成:
list1 = [10]
list2 = [123]
list3 = ['a']
8. 超出成员个数的切片
下面代码输出的结果是什么?
list = ['a', 'b', 'c', 'd', 'e']
print list[10:]
输出结果为:
[]
例如,尝试获取list[10]和之后的成员,会导致 IndexError。
然而,尝试获取列表的切片,开始的index超过了成员个数不会产生 IndexError,而是仅仅返回一个空列表。
这成为特别让人恶心的疑难杂症,因为运行的时候没有错误产生,导致bug很难被追踪到。
9. 列表的引用
有以下代码
1. list = [ [ ] ] * 5
2. list # output?
3. list[0].append(10)
4. list # output?
5. list[1].append(20)
6. list # output?
7. list.append(30)
8. list # output?
2,4,6,8行的输出结果如下:
[[], [], [], [], []]
[[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]
10. L.sort() 与 sorted() 的区别
L.sort(cmp=None, key=None, reverse=False)
sorted(iterable, cmp=None, key=None, reverse=False)
- L.sort():该函数的三个参数和 sorted() 的后三个参数含义是一致的,而需要特别注意的是,该函数只适用于列表,而非任意可以迭代的对象。cmp 是比较函数,接受两个对象参数 x 和 y,返回 负数(x<y),0(x=y),正数(x>y)。
- 该函数第一个参数 iterable 为任意可以迭代的对象,cmp 是比较函数,通常为lambda函数,key 是用于比较的关键字,reverse表示排序结果是否反转。
In [10]: aa = [5,4,3,2,1]
In [11]: aa.sort()
In [12]: aa
Out[12]: [1, 2, 3, 4, 5]
调用 sort() 之后会改变原来的表的结构顺序。
可以指定关键字排序
student = [['Tom', 'A', 20], ['Jack', 'C', 18], ['Andy', 'B', 11]]
student.sort(key=lambda student: student[2])
## 输出结果
[['Andy', 'B', 11], ['Jack', 'C', 18], ['Tom', 'A', 20]]
sorted() 可以应用于任意的可以迭代的对象,所以应用范围比 L.sort() 广泛的多,可以应用于字符串,元组,列表,字典等可迭代对象。
In [19]: s = "zyx"
In [20]: sorted(s)
Out[20]: ['x', 'y', 'z']
In [21]: s
Out[21]: 'zyx'
需要注意的是,该函数会返回一个排序后的列表,原有可迭代对象保持不变,这与 L.sort() 函数不同。然而,这会浪费较大的存储空间,尤其是数据量较大时。所以,在列表进行排序时,需要考虑是否需要保存原列表,如果无需保存原列表,则优先使用L.sort() 节省内存空间,提高效率。
- L.sort() 函数只适用于列表排序,而sorted()函数适用于任意可以迭代的对象排序。
- L.sort() 函数排序会改变原有的待排序列表,而sorted()函数则不会改变。所以在使用列表进行排序时,需要考虑是否需要保存原列表,如果无需保存原列表,则优先使用L.sort() 节省内存空间,提高效率。
- 两个函数通过定义 key 和 cmp 都可以完成排序,但是 key 的效率要远远高于 cmp,所以要优先使用 key 。
11. append 与 extend 方法有什么区别
append
表示把某个数据当做新元素整体追加到列表的最后面,它的参数可以是任意对象。
extend
的参数必须是一个可迭代对象,表示把该对象里面的所有元素逐个地追加到列表的后面。
In [1]: x = [1,2,3]
In [2]: y = [4,5]
In [3]: x.append(y)
In [4]: x
Out[4]: [1, 2, 3, [4, 5]]
In [5]: x = [1,2,3]
In [6]: x.extend(y)
In [7]: x
Out[7]: [1, 2, 3, 4, 5]
参考:
http://www.bugcode.cn/PythonQuestions.html
https://segmentfault.com/a/1190000006265256
http://www.cnblogs.com/wilber2013/p/5178620.html
http://python.jobbole.com/86525/