Python基础笔记-11

70.魔法方法:http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&highlight=%C4%A7%B7%A8%B7%BD%B7%A8

魔法方法总是被双下划线包围,例如__init__

魔法方法的‘魔力’体现再他们总能再适当的时候被自动调用

1)__init__(self[,...])类在实例化对象的时候,首先会调用的一个方法

有时候在类定义是写__init__方法,有时候却没有,这是为什么呢?

>>> class Rectangle:

   def __init__(self,x,y):

      self.x=x

      self.y=y

   def getPeri(self):

      return (self.x+self.y)*2

   def getArea(self):

      return self.x*self.y

>>> rect=Rectangle(3,4)

>>> rect.getPeri()

14

>>> rect.getArea()

12

#__init__不能有返回值

>>> class A:

   def __init__(self):

      return 'haha'

>>> a=A()

Traceback (most recent call last):

 File "", line 1, in

   a=A()

TypeError: __init__() should return None, not 'str'

2)__new__(cls[,...]) 实际上在实例化的时候先自动调用了这个魔法方法,之后才自动调用了__init__魔法方法

该魔法方法的参数是这个类

这个方法的返回值是一个实例对象,通常返回cls这个类的实例对象,也可以返回其他类的对象

这个new方法一般很少去重写,一般让python用默认的方法去执行就行

当继承一个不可变类型但需要进行修改需要重写这个方法

>>> class CapStr(str):

   def __new__(cls,string):

      string=string.upper()

      return str.__new__(cls,string)

>>> a=CapStr('hahah') #由于CapStr这个类是继承了str类,str是不可改变的类,那么就不能修改str的__init__方法进行修改,所以应该在重写__new__,增加了将字符串转化成大写然后再调用父类str的__new__的方法

>>> a

'HAHAH'

3)__del__(self)析构方法,当对象被销毁时候自动调用(当垃圾回收机制自动销毁的时候:实例化对象都没有引用了的时候)

>>> class C:

   def __init__(self):

      print('我是__init__方法,我被调用了')

   def __del__(self):

      print('我是__del__方法,我被调用了')

>>> c=C()

我是__init__方法,我被调用了

>>> c1=c

>>> c2=c1

>>> c3=c2

>>> c4=c3

>>> del c1

>>> del c

>>> del c2

>>> del c3

>>> del c4

我是__del__方法,我被调用了

4)算数魔法方法当你的对象进行了算数操作的时候,以下魔法方法就会自动被调用,这些方法可以被重写

__add__(self,other):定义加法行为+

__sub__(self,other):定义减法行为-

>>> class New_int(int):

   def __add__(self,other):

      return int.__sub__(self,other)

   def __sub__(self,other):

      return int.__add__(self,other)

>>> a=New_int(3)

>>> b=New_int(5)

>>> a+b

-2

__mul__(self,other):定义乘法行为*

__truediv__(self,other):定义真除法行为/

__floordiv__(self,other):定义整数除法行为://

__mod__(self,other):定义取模算法的行为:%

__divmod__(self,other):定义当被divmod()调用时的行为

__pow__(self,other):定义当被power()调用或**运算时的行为

__lshift__(self,other):定义按位左移位的行为:<<

__rshift__(self,other):定义按右移位的行为>>

__and__(self,other):定义按位与操作的行为&

__xor__(self,other):定义按位异或操作的行为^

__or__(self,other):定义按位或操作的行为|

【反运算魔法方法(上面的所有魔法方法前面加上r)】当a+b,a是一个数值,那么不能利用a的魔法方法,只用利用b的r魔法方法,反魔法方法也可以改写

>>> class Nint(int):

   def __radd__(self,other):

      return int.__sub__(self,other)

>>> a=Nint(5)

>>> b=Nint(3)

>>> a+b

2

>>> 1+b

2

【增量运算符】a+=1 上面所有的魔法方法前面家i

【一元操作符】-a

5)案例练习

定制一个计时器的类

start和stop方法代表启动计时和停止计时

假设计时器对象t1,print(t1)和直接调用t1均显示结果

当计时器未启动或已经停止计时,调用stop方法会给予温馨提示

两个计时器对象可以进行相加:t1+t2

只能使用提供的有限资源完成

资源如下:

使用time模块的localtime方法获取当前时间

time.localtime返回struct_time的时间格式(time模块详解http://bbs.fishc.com/forum.php?mod=viewthread&tid=51326&highlight=time%2B%C4%A3%BF%E9%CF%EA%BD%E2

表现你的类:__str__和__repr__:由于要求输入t1回车显示结果(__repr__)和print(t1)(__str__)显示结果果则需要重写这俩魔法函数

__str__

>>> class A:

   def __str__(self):

      return 'hahah'

>>> a=A()

>>> print(a) #__str__就是当要print出来一个实例化对象的时候要自动调用的魔法方法

hahah

__repr__

>>> class B:

   def __repr__(self):

      return 'haha'

>>> b=B()

>>> b #__repr__就是当要对实例化对象直接敲回车的时候要自动调用的魔法方法

haha

[1]编写代码模块MyTime.py

import time as t

class MyTimer():

   def __init__(self):

       self.unit=['年','月','日','时','分','秒']

       self.prompt= '未开始计时'

       self.begin=0

       self.end=0

       self.lasted=[]

   def __str__(self):

       return self.prompt

   __repr__=__str__

   def __add__(self,other):

       prompt='总共运行了' #局部变量

       result=[]

       for index in range(6):

           result.append(self.lasted[index]+other.lasted[index])

           if result[index]:

               prompt+=(str(result[index])+self.unit[index])

       return prompt

   #开始计时

   def start(self):

       self.begin=t.localtime()

       self.prompt='请先stop'

       print('计时开始。。')

   #停止计时

   def stop(self):

       if not self.begin:

           print('请先start')

       else:

           self.end=t.localtime()

           self._calc()

           print('计时结束')

   #内部方法,计算运行时间

   def _calc(self):

       self.lasted=[]

       self.prompt= '总过运行了'

       for index in range(6):

           self.lasted.append(self.end[index]-self.begin[index])

           if self.lasted[index]:

               self.prompt+=(str(self.lasted[index])+self.unit[index])

       #为下一轮初始化变量

       self.begin=0

       self.end=0

[2]运行代码模块

>>>

===================== RESTART: D:/python/3.5.1/Mytime.py =====================

>>> t1=MyTimer()

>>> t1

未开始计时

>>> t1.stop()

请先start

>>> t1.start()

计时开始。。

>>> t1.start()

计时开始。。

>>> t1

请先stop

>>> t1.stop()

计时结束

>>> t1

总过运行了15秒

>>> t2=MyTimer()

>>> t2.start()

计时开始。。

>>> t2.stop()

计时结束

>>> t2

总过运行了5秒

>>> t1+t2

'总共运行了20秒'

>>>

6)魔法方法对于属性访问的用用

__getattr__(self,name):定义当用户试图获取一个不存在的属性时候会被自动调用的方法

__getattribute__(self,name):定义当该类的属性被访问的时候会自动调用的方法

__setatter__(self,name,value):定义当一个属性被设置时候,会自动调用的方法

__delattr__(self,name):定义当一个属性被删除时候会自动调用的方法

>>> class C:

   def __getattribute__(self,name):

      print('getattribute')

      return super().__getattribute(name)

   def __getattr__(self,name):

      print('getattr')

   def __setattr__(self,name,value):

      print('setattr')

      super().__setattr__(name,value)

   def __delattr__(self,name):

      print('delattr')

      super().__delattr__(name)

>>> c=C()

>>> c.x

getattribute

getattr

>>> c.x=1

setattr

>>> c.x

getattribute

getattr

>>> del c.x

delattr

#以下例子会造成改造魔法方法后的死循环

class Rectangle:

   def __init__(self,width=0,height=0):

       self.width=width #既然发生赋值操作就会自动除法__setattr__但是这个魔法方法被改造后里头又有一个赋值,所以会死循环

       self.height=height

   def __setattr__(self,name,value):

       if name=='square':

           self.width=value

           self.height=value

       else:

           self.name=value

   def getAre(self):

       return self.width*self.height

7)描述符:将某种特殊类型的类的实例指派给另一个类的属性

特殊类型是实现以下三个方法一个或者多个的类就是特殊类型的类

__get__(self,instance,owner)用于访问属性,它返回属性的值

__set__(self,instance,value)将再属性分配操作中调用,不返回任何内容

__delete__(self,instance)控制删除操作,不返回任何内容

>>> class MyDecriptor: #这个类含有上述三个方法

   def __get__(self,instance,owner):

      print('getting...',self,instance,owner)

   def __set__(self,instance,value):

      print('setting...',self,instance,value)

   def __delete__(self,instance):

      print('deleting...',self,instance)

>>> class Test:

   x=MyDecriptor() #把MyDecriptor这个类的实例MyDecriptor() 赋值给 Test类的属性x,那么这个MyDecriptor类就是描述符类

>>> test=Test()

>>> test.x  #调用MyDecriptor的__get__方法

getting... <__main__.MyDecriptor object at 0x0000012E3FF4D748> <__main__.Test object at 0x0000012E3FF4D898>

>>> test

<__main__.Test object at 0x0000012E3FF4D898>

>>> Test

>>> test.x='x-man' #调用MyDecriptor的__set__方法

setting... <__main__.MyDecriptor object at 0x0000012E3FF4D748> <__main__.Test object at 0x0000012E3FF4D898> x-man

>>> del test.x  #调用MyDecriptor的__del__方法

deleting... <__main__.MyDecriptor object at 0x0000012E3FF4D748> <__main__.Test object at 0x0000012E3FF4D898>

以下是编写自己的property类

>>> class Myproperty:

   def __init__(self,fget=None,fset=None,fdel=None):

      self.fget=fget

      self.fset=fset

      self.fdel=fdel

   def __get__(self,instance,owner):

      return self.fget(instance)

   def __set__(self,instance,value):

      self.fset(instance,value)

   def __del__(self,instance):

      self.fdel(instance)

>>> class C:

   def __init__(self):

      self._x=None

   def getx(self):

      return self._x

   def setx(self,value):

      self._x=value

   def delx(self):

      del self._x

   x=Myproperty(getx,setx,delx)

>>> c=C()

>>> c.x='haha'

>>> c.x

'haha'

>>> x._x

Traceback (most recent call last):

 File "", line 1, in

   x._x

NameError: name 'x' is not defined

>>> c,_x

Traceback (most recent call last):

 File "", line 1, in

   c,_x

NameError: name '_x' is not defined

>>> c._x

'haha'

#以下是一个温度计数值转化的练习

先定义一个温度类,然后定义两个描述符类哟关于描述摄氏度和华氏度两个属性

要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果

class Celsius:

   def __init__(self,value=26.0):

       self.value=float(value)

   def __get__(self,instance,owner):

       return self.value

   def __set__(self,instance,value):

       self.value=float(value)

class Fahrenheit:

   def __get__(self,instance,owner):

       return instance.cel*1.8+32

   def __set__(self,instance,value):

       instance.cel=(float(value)-32)/1.8

class Temperature:

   cel=Celsius()

   fah=Fahrenheit()

调用后

>>>

====================== RESTART: D:/python/3.5.1/temp.py ======================

>>> temp=Temperature()#实例化对象此时调用了__init__方法,使得temp的value=26.0

>>> temp.cel  #这个操作会触发Celsius描述符的__get__方法,返回对象temp的value

26.0

>>> temp.cel=30 #这个操作会触发Celsius描述符的__set__方法,将对象的value修改成30

>>> temp.fah #这个操作会触发Fahrenheit描述符的__get__方法

86.0

>>> temp.fah=100 #这个操作会触发Fahrenheit描述符的__set__方法

>>> temp.cel

37.77777777777778

>>>

8)定制序列

协议与其他编程语言中的接口很相似,他对丁你哪些方法必须要定义

容器类型的协议

如果说希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()方法

如果说你希望定制的容器是可变的话,除了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个方法

编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数

class Countlist:

   def __init__(self,*args):

       self.values=[x for x in args]

       self.count={}.fromkeys(range(len(self.values)),0)

   def __len__(self):

       return len(self.values)

   def __getitem__(self,key):

       self.count[key]+=1

       return self.values[key]

运行脚本

>>>

=================== RESTART: D:/python/3.5.1/Countlist.py ===================

>>> c1=Countlist(1,3,5,7,9) #调用__init__方法

>>> c2=Countlist(2,4,6,8,10)

>>> c1[1] #调用__getitem__方法

3

>>> c2[1]

4

>>> c1[1]+c2[1]

7

>>> c1.count

{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

9)迭代器 http://bbs.fishc.com/forum.php?mod=viewthread&tid=56023&highlight=yield

iter()  对一个容器对象调用该bif可以得到一个迭代器

next() 对一个迭代器调用该big可以返回一个值

当迭代器没有值返回系统会返回报错

>>> string='fishc'

>>> it=iter(string)

>>> next(it)

'f'

>>> next(it)

'i'

>>> next(it)

's'

>>> next(it)

'h'

>>> next(it)

'c'

>>> next(it)

Traceback (most recent call last):

 File "", line 1, in

   next(it)

StopIteration

用这里的两个bif实现for的作用

>>> string='fishc'

>>> it=iter(string)

>>> while True:

   try:

      each=next(it)

   except StopIteration:

      break

   print(each)

f

i

s

h

c

#利用__iter__() 和 __next__()方法

>>> class Fibs:

   def __init__(self,n=10):

      self.a=0

      self.b=1

      self.n=n

   def __iter__(self):

      return self

   def __next__(self):

      self.a,self.b=self.b,self.a+self.b

      if self.a>self.n:

         raise StopIteration

      return self.a

>>> fibs=Fibs()

>>> for each in fibs:

   print(each)

1

1

2

3

5

8

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容

  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,165评论 4 16
  • 八大排序 - Shuai-Xie - Github 内部排序和外部排序 内部排序数据少,数据记录在内存中进行排序,...
    谢小帅阅读 1,063评论 1 1
  • 散步在午后的校园 三月,天转暖 一切都欣欣然 雨后小径的泥土,踩起来 一定是凉爽又温柔。...
    两条路阅读 183评论 0 0
  • 最近根据公司的业务需要,封装了一些平时开发中基本都会用到的基础业务模块,其中用的最多的就是各个工厂模式了,同时也趁...
    Knight_Davion阅读 7,949评论 7 27