构造函数
1. 一个对象被创建之后立刻调用构造函数
__function__这种形式的函数会在特殊情况下被调用,如:__init__
两行变一行:
f = FooBar()
f.init() #这一行就不用调用了
使用__init__:f = FooBar() 即可
# -*- coding: utf-8 -*-
class FooBar:
def __init__(self):
self.var = 42
f = FooBar()
print f.var
class FooBar:
def __init__(self,value = 42): # 赋予参数默认值
self.var = value
f = FooBar('That is it') # 构造方法有参数
print f.var
f = FooBar() # 构造方法有参数
print f.var
2. 继承重写构造方法
如果重写超类的构造方法,那么需要调用超类的构造方法,否则可能会出错:
# -*- coding: utf-8 -*-
class Bird:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print 'Aaah...'
self.hungry = False # 调用了构造方法中的值
else:
print 'No,thanks'
b = Bird()
b.eat()
b.eat()
class SongBird(Bird):# 继承超类
def __init__(self):
self.sound = 'Squawk!' # 没有 hungry 特性
def sing(self):
print self.sound
sb = SongBird()
sb.sing()
sb.eat() # 超类有的子类也有
调用超类构造方法解决上述问题:super函数 / 调用超类构造方法未绑定版本
class SongBird(Bird):# 继承超类
def __init__(self):
super(SongBird,self).__init__() # 使用类+对象作为参数
#Bird.__init__(self) # 使用类方法,实例没有被绑定
self.sound = 'Squawk!'
def sing(self):
print self.sound
未绑定方法:没有实例被绑定,可以自由的提供所需要的self 参数
*3. 引申出模仿方法
创建类似序列的对象:
# -*- coding: utf-8 -*-
def checkIndex(key): # 检查索引是否合法
if not isinstance(key,(int,long)):raise TypeError
if key<0:raise IndexError
class sequence:
def __init__(self, start=0, step=1):# 初始化参数防止出事
self.start = start
self.step = step
self.changed = {}
def __getitem__(self,key): #生成了一个无限长的序列
checkIndex(key)
try:# 异常捕捉的妙用: 改变了值则返回改变的值,没有改变值则返回设定值
return self.changed[key] # self.changed = {}初始化默认为空
except KeyError:#用户没有给序列设定值
return self.start + self.step * key
def __setitem__(self, key, value): #给用户用于修改的
checkIndex(key)
self.changed[key] = value
s=sequence(1,2)
print s[4] # 调用方法__getitem__
s[4]=2
print s[4],s[5]
print s['four']
子类化列表,字符串,字典:
# -*- coding: utf-8 -*-
class CounterList(list): # 继承list
def __init__(self, *args):
super(CounterList,self).__init__(*args)
self.counter = 0 # 新增功能:访问技术
def __getitem__(self,index):
self.counter += 1
return super(CounterList,self).__getitem__(index)
cl = CounterList(range(10))
print cl #没有重写任何方法,超类的都可以用
print cl.counter
cl[4]+cl[2] #访问了两次
print cl.counter
迭代器
__iter__方法:迭代器规则的基础,返回一个迭代器
for 循环除了对序列,字典迭代,可以对实现了__iter__方法(返回一个iterator)的对象迭代(使用迭代器的原因:更通用,简单)。
比如需要计算值:迭代器一个个算,列表一次获取所有值,若值很多则很占内存。
使用迭代器实现斐波那契:
# -*- coding: utf-8 -*-
class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def next(self):
self.a, self.b = self.b, self.a+self.b
return self.a
def __iter__(self): # 放到会在for循环中使用的对象中
return self
fibs = Fibs()
for f in fibs: # __iter__
if f>1000:
print f
break
生成一个10以内的迭代器:
# -*- coding: utf-8 -*-
class Iteration:
value = 0
def next(self):
self.value += 1
if self.value>10: raise StopIteration
return self.value
def __iter__(self):
return self
ti = Iteration()
for t in ti:
print t
1. 生成器
包含 yield 语句的函数:生成器
生成器与return不同,生成一个值就pause,下次调用时继续函数,而不会像return 一样终止函数。
所以在处理:任意层嵌套(例如树形结构),并不知道到底有多少层嵌套——需要递归+生成器:
# -*- coding: utf-8 -*
def flatten(nested):
try: #对于一个任意的树形结构,至少应该有两层for循环:两种情况
for sublist in nested: #基本情况:展开一个元素——TypeError
for element in flatten(sublist): # 需要递归的情况:展开可迭代对象
print element
yield element
#return element 找到第一个元素的时候就返回了,无法遍历后面的元素
except TypeError: # 排除TypeError: 'int' object is not iterable, 基本情况:展开一个元素
yield nested
#return nested
print list(flatten([[[1],2],3,4,[5,[6,7]],8]))
遇到字符串怎么办,因为对字符串进行迭代会导致无穷递归:
def flatten(nested):
try:
try:nested + '' # 检验是否是字符串
except TypeError:pass # 不是则进行下一步
else:raise TypeError # 是字符串就异常终止程序
for sublist in nested:
for element in flatten(sublist):
print element
yield element
except TypeError:
yield nested
普通函数实现上述:
def flatten(nested):
result = []
try:
try:nested + ''
except TypeError:pass
else:raise TypeError
for sublist in nested:
for element in flatten(sublist):
result.append(element)
except TypeError:
result.append(nested)
return result
一层循环实现:(很局限,首先需要知道每一个元素可能的类型)
# -*- coding: utf-8 -*
listx = []
def flatten(nested):
#listx = [] 注意位置!在后面调用flatten的时候又会产生一个新的listx
for i in nested:
if type(i) is not list:
listx.append(i)
else:
flatten(i)
return listx
print flatten([[[1],2],3,4,[5,[6,7]],8])
这段代码就要求提前想好 i 可能的类型,而之前的两段代码是直接创造一个可能会出错(如果不是集合类型,而像数字之类的是不能迭代的)的代码,之后的事全交给异常处理来管TypeError,不用预知每个元素可能是什么类型。