python学习笔记——第九章 属性 方法和迭代器

第九章 属性 方法和迭代器

创建一个构造方法

>>> class FooBar:
	def __init__(self):
		self.somevar = 42

		
>>> f = FooBar()
>>> f.somevar
42

构造方法传几个参数

>>> class FooBar:
	def __init__(self,value=42):  #默认参数  
		self.somevar = value

	
>>> f = FooBar('This is a constructor argumnet')
>>> f.somevar
'This is a constructor argumnet'

重写一般方法和特殊的构造方法
>>> class A:
	def hello(self):
		print("hello, I'm A.")

>>> class B(A):
	pass

>>> a=A()   #创建类A的对象
>>> b=B()   #创建类B的对象
>>> a.hello() #调用自己的hello方法
hello, I'm A.
>>> b.hello() #调用超类A的hello方法
hello, I'm A.

>>> class B(A):
	def hello(self): #B类重写A类的hello方法
		print("hello, I'm B.")

		
>>> b=B()
>>> b.hello()
hello, I'm B.

>>> class Bird:
	def __init__(self):
		self.hungry = True
	def eat(self):
		if self.hungry:
			print('Aaaah...')
			self.hungry = False
		else:
			print('No, thanks!')

			
>>> b = Bird()
>>> b.eat()
Aaaah...
>>> b.eat()
No, thanks!
>>> class SongBird(Bird):
	def __init__(self):
		self.sound = 'Squawk!'
	def sing(self):
		print(self.sound)

		
>>> sb = SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat() # SongBird没有hungry特性,所以子类调用eat()方法出现错误
Traceback (most recent call last):
  File "<pyshell#53>", line 1, in <module>
    sb.eat()
  File "<pyshell#41>", line 5, in eat
    if self.hungry:
AttributeError: 'SongBird' object has no attribute 'hungry'
解决上面出错的办法:(1)调用超类构造方法的未绑定版本;(2)使用super函数

(1)调用未绑定的超类构造方法:Bird.__init__(self)
>>> class SongBird(Bird):
	def __init__(self):
		Bird.__init__(self)  #未绑定方法,当前的实例作为self参数提供未绑定方法,SongBird能够使用其超类的构造方法的所有实现,属性hungry能被设置
		self.sound = 'Squawk!'
	def sing(self):
		print(self.sound)

		
>>> sb = SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaaah...
>>> sb.eat()
No, thanks!
>>> 

(2)使用super函数 super(SongBird, self).__init__()
当前的类和对象可以作为super函数的参数使用,调用函数返回的对象的任何方法都是调用超类的方法,而不是当前类的方法
直接使用super(SongBird,self)
>>> class SongBird(Bird):
	def __init__(self):
		Bird.__init__(self)
		self.sound = 'Squawk!'
	def sing(self):
		print(self.sound)

		
>>> sb = SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaaah...
>>> sb.eat()
No, thanks!
>>> 
>>> __metaclass__ = type
>>> class Bird:
	def __init__(self):
		self.hungry = True
	def eat(self):
		if self.hungry:
			print('Aaah...')
			self.hungry = False
		else:
			print('No, thanks!')

			
>>> class SongBird(Bird):
	def __init__(self):
		super(SongBird, self).__init__()  #super函数,子类就会调用超类的属性和方法
		self.sound = 'Squawk!'
	def sing(self):
		print(self.sound)

		
>>> sb = SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaah...
>>> sb.eat()
No, thanks!
2、成员访问
2.1 基本的序列和映射规则
序列和映射是对象的集合,对象不可变,需使用2个魔法方法;对象可变需使用4个
(1)__len_(self):这个方法返回集合中所含项目的数量。对于序列就是元素的个数;对于映射则是键-值对的数量。
(2)__getitem__(self,key):这个方法返回与所给键对应的值。对于序列:键应该是一个0~n-1的整数,n是序列的长度;对于映射:可以使用任何种类的键。
(3)__setitem__(self,key,value):这个方法按一定的方式存储和key相关的value,该值随后可使用__getitem__来获取。
(4)__delitem__(self,key):对一部分对象使用del语句是被调用,同时必须删除和元素相关的键;可修改对象定义的(并不是删除全部的对象,而只删除一些需要移除的元素)


3、子类化列表,字典和字符串

>>> class CounterList(list):
	def __init__(self,*args):
		super(CounterList,self).__init__(*args)  #super方法被用来调用相应的超类的方法,只在__init__中添加了所需的初始化counter特性的行为,并在__getitem__中更新了counter特性
		self.counter = 0
	def __getitem__(self,index):
		self.counter += 1
		return super(CounterList,self).__getitem(index)

	
>>> c1 = CounterList(range(10))
>>> c1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> c1.reverse()
>>> c1
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del c1[3:6]
>>> c1
[9, 8, 7, 3, 2, 1, 0]
>>> c1.counter
0

4、属性:通过访问器定义的特性称为属性

>>> class Rectangle:
	def __init__(self):
		self.width = 0
		self.height = 0
	def setSize(self,size):
		self.width,self.height=size #size是由width和height构成的元组
	def getSize(self):
		return self.width,self.height

	
>>> r =Rectangle()
>>> r.width=10
>>> r.height = 5
>>> r.getSize()
(10, 5)
>>> r.setSize((100,150))
>>> r.width
100

4.1 property函数
>>> __metaclass__=type  #子类化object,或者使用__metaclass__=type
>>> class Rectangle:
	def __init__(self):
		self.width = 0
		self.height = 0
	def setSize(self,size):
		self.width,self.height=size
	def getSize(self):
		return self.width,self.height
	size = property(getSize,setSize) #property函数创建一个属性,访问器函数被用作参数(先取值,后赋值),属性命名为size

	
>>> r=Rectangle()
>>> r.width =10
>>> r.height = 5
>>> r.size
(10, 5)
>>> r.size = 150,100 #size特性仍然取决于getSize和setSize中的计算
>>> r.width
150

property函数可以用0,1,2,3或者4个参数来调用。
property的4个参数分别被叫做fget,fset,fdel和doc--
在新式类中应该使用property函数而不是访问器方法。


4.2静态放法和类成员方法
静态方法:定义没有self参数,并且能够被类本身直接调用
类成员方法:定义时需要名为cls的类似于self的参数,类成员方法可以直接用类的具体对象调用,cls参数是自动被绑定到类的。

>>> __metaclass__=type
>>> 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)

装饰器:使用@操作符
使用装饰器的版本

>>> __metaclass__ = type
>>> 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() #静态方法:定义没有self参数,并且能够被类本身直接调用
This is a static method
>>> MyClass.cmeth()
This is a class method of <class '__main__.MyClass'>

4.3 __getattr__、__setattr__和它的朋友们
拦截对象的所有特性访问是可能的
魔法方法(可以对处理很多属性的方法进行再编码)
(1)__getattribute__(self,name):当特性name被访问时自动被调用(只能在新式类中使用)
(2)__getattr__(self,name):当特性name被访问且对象没有相应的特性时被自动调用。
(3)__setattr__(self,name,value):当试图给特性name赋值时会被自动调用。
(4)__delattr__(self,name):当试图删除特性name时被自动调用。

>>> class Rectangle:
	def __init__(self):
		self.width = 0
		self.height = 0
	def __setattr__(self,name,value):
		if name == 'size':
			self.width,self.height = value
		else:
			self.__dict__[name] = value #特殊方法__dict__,该方法包含一个字典,字典里面是所有实例的属性,为避免__setattr__方法被再次调用(这样程序陷入死循环),__dict__方法被用来代替普通的特性赋值操作。
	def __getattr__(self,name):
		if name == 'size':
			return self.width,self.height
		else:
			raise AttributeError

5、迭代器
特殊方法:__iter__,这个方法是迭代器规则的基础
5.1 迭代器规则:
迭代:重复做一些事很多次
__iter__方法返回一个迭代器,迭代器具有next方法(这个方法在调用时不需要任何参数)的对象,在调用next方法时,迭代器会返回它的下一个值。
一个实现了__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__方法,返回迭代器本身
		return self

	
>>>

>>> 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):
		return self

	
>>> fibs = Fibs()
>>> for f in fibs:
	if f>1000:
		print(f)
		break

#出现该错误的原因是def next(self):需要修改成def __next__(self):	
Traceback (most recent call last):   
  File "<pyshell#27>", line 1, in <module>
    for f in fibs:
TypeError: iter() returned non-iterator of type 'Fibs' 
正确的版本:

>>> 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):
		return self

	
>>> fibs = Fibs() #产生一个Fibs对象
>>> for f in fibs:  #在for循环中使用该对象
	if f >1000:
		print(f)
		break

	
1597

内建函数iter可以从可迭代的对象中获得迭代器

>>> it = iter([1,2,3])
>>> it.__next__()  #python3.0版本用__next__()方法
1
>>> it.__next__()
2
>>> it.__next__()
3

5.2 从迭代器得到序列
使用list构造方法显示地将迭代器转化为列表

>>> class TestIterator:
	value = 0
	def __next__(self): #此处是python3.0的版本,3.0以前的版本是用def next(self):
		self.value +=1
		if self.value >10:
			raise StopIteration
		return self.value
	def __iter__(self):
		return self

	
>>> ti = TestIterator()
>>> list(ti)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

6、生成器
6.1 创建生成器(处理两层嵌套)
功能:顺序打印出列表中的数字

>>> nested=[[1,2],[3,4],[5]] #列表的列表
>>> def flatten(nested):
	for sublist in nested:
		for element in sublist:
			yield element     #包含yield语句的函数称为生成器

			
>>> for num in flatten(nested):
	print(num)

	
1
2
3
4
5

6.2 递归生成器(处理树形结构)
>>> def flatten(nested):
	try:
		for sublist in nested:
			for element in flatten(sublist):
				yield element
	except TypeError:
		yield nested

		
>>> list(flatten([[[1],2],3,4,[5,[6,7]],8]))
[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):
				yield element
	except TypeError:
		yield nested

		
>>> list(flatten(['foo',['bar',['baz']]]))
['foo', 'bar', 'baz']
6.3 通用生成器
生成器是一个包含yield关键字的函数,当它被调用时,在函数体中的代码不会被执行,而返回一个迭代器。
每次请求一个值,就会执行生成器中的代码,直到遇到一个yield或者return语句。
yield语句意味着应该生成一个值
return语句意味着生成器要停止执行。
生成器由两部分组成:生成器的函数和生成器的迭代器
生成器的函数是用def语句定义的,包含yield的部分
生成器的迭代器是这个函数返回的部分

>>> def simple_generator():
	yield 1

	
>>> simple_generator
<function simple_generator at 0x01405ED0>
>>> simple_generator()
<generator object simple_generator at 0x0140F7D8>

生成器的方法
外部作用域访问生成器的send方法
内部则挂器生成器,yield作为表达式而不是语句使用。

>>> def repeater(value):
	while True:
		new = (yield value)
		if new is not None:
			value = new

			
>>> r=repeater(42)
>>> r.__next__()
42
>>> r.send("Hello, world! ")
'Hello, world! '






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值