构造函数
Pythons中的构造函数命名为__init__,在对象创建后可以自动调用它们。
>>> class FooBar: def __init__(self): self.somever = 42 >>> f = FooBar() >>> f.somever #省略了之前f.init()的操作 42 >>> class FooBar: def __init__(self,value=42): self.somever = value >>> f = FooBar('This is a constructor argument') #带参数的构造函数可以直接传值 >>> f.somever 'This is a constructor argument'
方法重写super(SongBird,self)
>>> class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print('eat!') self.hungry = False else: print('No,thanks') >>> b = Bird() >>> b.eat() eat! >>> b.eat() No,thanks >>> class SongBird(Bird): def __init__(self): super().__init__() #调用super()时,将当前类和当前实例作为参数。对其返回的对象调用方法时,调用的将是超类的方法。 self.sound = 'Squawk' def sing(self): print(self.sound) >>> sb = SongBird() >>> sb.sing() Squawk >>> sb.eat() eat! >>> sb.eat() No,thanks
在上面的栗子中,SongBird类继承了超类Bird,所以SongBird类可以重写超类的构造函数。在Bird中构造函数的属性是hungry,但是SongBird类重写时只定义了属性sound,
为了让初始化得以执行,SongBird的构造函数就必须调用超类Bird的构造函数,可以使用super函数来解决。
元素访问
创建一个无穷序列:
>>> def check_index(key): #这是一个辅助函数 if not isinstance(key,int):raise TypeError if key < 0 : raise IndexError >>> class ArithmmeticSequence: def __init__(self,start=0,step=1): """ 初始化这个算术序列 start--序列中的第一个值 step---两个相邻值的差 changed ---一个字典,包含用户修改后的值 """ self.start = start #存储起始值 self.step = step #存储步长值 self.changed = {} #没有任何元素被修改 def __getitem__(self,key): #从算术序列中获取第一个元素 check_index(key) try: return self.changed[key] #如果允许修改元素,就将修改的值保存在changed中。 except KeyError: return self.start + key * self.step #如果元素未修改,就计算值 def __setitem__(self,key,value): #修改算术序列中的元素 check_index(key) self.changed[key] = value #存储修改后的值 >>> s = ArithmmeticSequence(1,2) >>> s[4] 9 >>> s.changed {} >>> s[4]=2 #修改元素 >>> s[4] 2 >>> s[5] 11 >>> s.changed {4: 2} >>> s['a'] Traceback (most recent call last): File "<pyshell#240>", line 1, in <module> s['a'] File "<pyshell#226>", line 14, in __getitem__ check_index(key) File "<pyshell#202>", line 2, in check_index if not isinstance(key,int):raise TypeError TypeError
特殊方法:
__len__(self):返回集合包含的项数。
__getitem__(self):返回与指定键相关联的值。
__setitem__(self,key,value):存储相关联的键值。(对象可变)
__delitem__(self,key):删除与key相关联的值。(当对象可变时才需要实现这个方法)
继承内置类型(从list,dict和str派生)
小栗子:一个带访问计数器的列表
>>> class CounterList(list): #继承超类list的行为 def __iniit__(self,*args): supper().__init__(*args) self.counter = 0 def __getitem__(self,index): self.counter += 1 #每访问1次,计数加1 return super(CounterList,self).__getitem__(index) #返回计数 >>> cl = CounterList(range(10)) >>> cl [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> cl.reverse() #可以调用超类的方法 >>> cl [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> del cl[3:6] >>> cl [9, 8, 7, 3, 2, 1, 0] >>> cl.counter # CounterList类的counter属性初始值为0 0 >>> cl[4] #访问1次列表元素,counter值加1 4 >>> cl.counter 1 >>> cl[4]+cl[2] 6 >>> cl.counter 3
特性(property):通过存取方法定义的属性。
>>> class Rectangle: def __init__(self): self.width = 0 self.height = 0 def set_size(self,size): self.width,self.height = size def get_size(self): return self.width,self.height >>> r = Rectangle() >>> r.width = 10 >>> r.height = 5 >>> r.get_size() (10, 5) >>> r.set_size((30,7)) >>> r.width 30 >>> class Rectangle: def __init__(self): self.width = 0 self.height = 0 def set_size(self,size): self.width,self.height = size def get_size(self): return self.width,self.height size = property(get_size,set_size) >>> r = Rectangle() >>> r.width = 30 >>> r.height = 20 >>> r.size (30, 20) >>> r.size = 100,150 >>> r.width 100
1.调用函数property,并将存取方法作为参数(获取方法在前,设置方法在后)创建了一个特性,然后将名称size关联到这个特性。
2.property其实是一个类。它的实例包含一些特殊方法,__get__、__set__、__delete__.
3.在调用函数property时,可以不指定参数(特性不可读和写),指定1个参数(特性是只读的),指定2个参数(特性是可读也可写的),指定3个参数(第三个参数可选,用于删除属性的方法)。
静态方法和类方法
创建:将方法分别包装在staticmethod和classmethod类的对象中。
静态方法无参数,直接通过类调用;类方法定义中包含cls参数(类似self),类方法也可通过对象直接调用,参数cls将自动关联到类。
>>> class MyClass: def smeth(): print('this is a static method') smeth = staticmethod(smeth) #静态方法 def cmeth(cls): print('this is a class method of ',cls) cmeth = classmethod(cmeth) #类方法 >>> MyClass.smeth() this is a static method >>> MyClass.cmeth() this is a class method of <class '__main__.MyClass'>
上面的小栗子替换方法有点繁琐,可以优化下:装饰器可代替手动包装,在方法或函数前面使用运算符@列出这些装饰器。(指定多个装饰器时,应用顺序与列出顺序相反)
>>> class MyClass: @staticmethod def smeth(): print('this is a static method') @classmethod def cmeth(cls): print('this is a class method of ',cls) >>> MyClass.smeth() this is a static method >>> MyClass.cmeth() this is a class method of <class '__main__.MyClass'>
迭代器
方法__iter__返回一个迭代器,它是包含方法__next__的对象,而调用这个方法时可不提供任何参数。
>>> 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): #在迭代器中实现方法__iter__,这样迭代器就可直接用于for循环中 return self >>> f = Fibs() >>> for i in f: if i > 1000: #找出第一个大于1000的斐波那契数后停止运行 print(i) break 1597
实现了方法__iter__的对象是可迭代的,而实现了方法__next__的对象是迭代器。
通过对可迭代对象调用内置函数iter,可获得一个迭代器。
>>> it = iter([1,2,3]) >>> next(it) 1 >>> next(it) 2
生成器
生成器是一种使用普通函数语法定义的迭代器。
>>> def flatten(nested): for sublist in nested: #查找列表中所有的子列表 for element in sublist: #按顺序迭代每个子列表的元素 yield element #包含yield语句的函数都被称为生成器 >>> nested = [[1,2],[3,4],[5]] >>> for num in flatten(nested): print(num) 1 2 3 4 5 >>> list(flatten(nested)) [1, 2, 3, 4, 5]
生成器与普通函数的差别在于,生成器不是使用return返回一个值,而是可以生成多个值,每次一个。
递归生成器
如果有多层嵌套列表,可以用递归实现。
>>> def fast(n): try: for sublist in n: for element in fast(sublist): yield element except TypeError: yield n >>> list(fast([[1,2],3,4,[5],[6,[7]],8])) [1, 2, 3, 4, 5, 6, 7, 8]