设为首页 收藏本站
查看: 1129|回复: 0

[经验分享] 《Python基础教程》 读书笔记 第九章 魔法方法、属性和迭代器(上)

[复制链接]

尚未签到

发表于 2015-11-30 10:27:26 | 显示全部楼层 |阅读模式
  构造方法
  
  在Python中创建一个构造方法很容易。只要把init方法的名字从简单的init修改为魔法版本__init__即可:
  >>> 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 argument')
  >>> f.somevar
  'this is a constructor argument'
  
  重写一般方法和特殊的构造方法
  
  构造方法用来初始化新创建对象的状态,大多数子类不仅要拥有自己的初始化代码,还要拥有超类的初始化代码。虽然重写的机制对于所有方法来说都是一样的,但是当处理构造方法比重写普通方法时,更可能遇到特别的问题:如果一个类的构造方法被重写,那么就需要调用超类(你所继承的类)的构造方法,否则对象可能不会被正确地初始化。
  >>> 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()
  aaah...
  >>> b.eat()
  no thanks
  鸟吃过了以后,它就不再饥饿。现在考虑子类SongBird,它添加了唱歌的行为:
  >>> class SongBird(Bird):
  ...     def __init__(self):
  ...         self.sound='Squawk'
  ...     def sing(self):
  ...         print self.sound
  ...        
  >>> s=SongBird()
  >>> s.sing()
  Squawk
  因为SongBird是Bird的一个子类,它继承了eat方法,但如果调用eat方法,就会产生一个问题:
  >>> s.eat()
  Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 5, in eat
  AttributeError: SongBird instance has no attribute 'hungry'
  错误:SongBird没有hungry特性。原因是这样的:在SongBird中,构造方法被重写,但新的构造方法没有任何关于初始化hungry特性的代码。为了达到预期的效果,SongBird的构造方法必须调用其超类Bird的构造方法来确保进行基本的初始化。有两种方法能达到这个目的:调用超类构造方法的未绑定版本,或者使用super函数。
  
  调用未绑定的超类构造方法
  
  >>> class SongBird(Bird):
  ...     def __init__(self):
  ...         Bird.__init__(self)
  ...         self.sound='Squawk'
  ...     def sing(self):
  ...         print self.sound
  ...        
  >>> s=SongBird()
  >>> s.eat()
  aaah...
  >>> s.eat()
  no thanks
  >>> s.sing()
  Squawk
  在调用一个实例的方法时,该方法的self参数会被自动绑定到实例上(这称为绑定方法)。但如果直接调用类的方法(比如Bird.__init__),那么就没有实例会被绑定。这样就可以自由地提供需要的self参数。这样的方法称为未绑定(unbound)方法
  
  使用super函数
  
  当前的类和对象可以作为super函数的参数使用,调用函数返回的对象的任何方法都是调用超类的方法,而不是当前类的方法。
  >>> __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__()
  ...         self.sound='Squawk'
  ...     def sing(self):
  ...         print self.sound
  ...  
  这个新式的版本的运行结果和旧式版本的一样      
  >>> s=SongBird()
  >>> s.sing()
  Squawk
  >>> s.eat()
  aaah...
  >>> s.eat()
  no thanks
  
  基本的序列和映射规则
  
  序列和映射是对象的集合。为了实现它们基本的行为(规则),如果对象是不可变的,那么就需要使用两个魔法方法,如果是可变的则需要使用4个。
  __len__(self):这个方法应该返回集合中所含项目的数量。对于序列来说,这就是元素的个数。对于映射来说,则是键-值对的数量。
  __getitem__(self,key):这个方法返回与所给键对应的值。对于一个序列,键应该是1个0~n-1的整数(或者像后面所说的负数),n是序列的长度;对于映射来说,可以使用任何种类的键。
  __setitem__(self,key,value):这个方法应该按一定的方式存储和key相关的value,该值随后可使用__getitem__来获取。当然,只能为可以修改的对象定义这个方法。
  __delitem__(self,key):这个方法在对一部分对象使用del语句时被调用,同时必须删除和元素相关的键。这个方法也是为可修改的对象定义的(并不是删除全部的对象,而只删除一些需要移除的元素)。
  >>> def checkIndex(key):
  ...     if not isinstance(key,(int,long)):raise TypeError
  ...     if key<0:raise IndexError
  ...  
  >>> class ArithmeticSequence:
  ...     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]
  ...         except KeyError:
  ...             return self.start+key*self.step
  ...     def __setitem__(self,key,value):
  ...         checkIndex(key)
  ...         self.changed[key]=value
  ...         
  >>> s=ArithmeticSequence(1,2)
  >>> s[4]
  9
  >>> s[4]=2
  >>> s[4]
  2
  >>> s[5]
  11
  没有实现__del__方法的原因是希望删除元素是非法的:
  >>> del s[4]
  Traceback (most recent call last):
  File "<input>", line 1, in <module>
  AttributeError: ArithmeticSequence instance has no attribute '__delitem__'
  这个类没有__len__方法,因为它是无限长的。
  如果使用了一个非法类型的索引,就会引发TypeError异常,如果索引的类型是正确的但超出了范围(在本例中为负数),则会引发IndexError异常:
  >>> s[four]
  Traceback (most recent call last):
  File "<input>", line 1, in <module>
  NameError: name 'four' is not defined
  >>> s[-4]
  Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 7, in __getitem__
  File "<input>", line 3, in checkIndex
  IndexError
  子类化列表,字典和字符串
  例子----带有访问计数的列表:
  >>> class CounterList(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)
  ...
  CounterList类严重依赖于它的子类化超类(list)的行为CounterList类没有重写任何的方法(和append  extend, index一样)都能被直接使用。在两个被重写的方法中,super方法被用来调用相应的超类的方法,只在__init__中添加了所需的初始化counter特性的行为,并在__getitem__中更新了counter特性。
  >>> 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[4]+c1[2]
  9
  >>> c1.counter
  2
  CounterList在很多方面和列表的作用一样,但它有一个counter特性(被初始化为0),每次列表元素被访问时,它都会自增,所以在执行加法c1[4]+c1[2〕后,这个值自增两次,变为2.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-145280-1-1.html 上篇帖子: Python--Cmd窗口运行Python时提示Fatal Python error: Py_Initialize: can't initialize sys 下篇帖子: Python自然语言处理(1):初识NLP
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表