python魔法方法_Python学习笔记(七)——魔法方法

1.构造和析造

魔法方法就是被双下划线包围的方法

__init__()方法

__init__方法默认没有参数,返回值为none。类实例化对象需有明确的初始化步骤要重写函数

>>> 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返回值一定是None

>>> class A:

def __init__(self):

return "A"

>>> a = A()

Traceback (most recent call last):

File "", line 1, in

a = A()

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

__new__()方法

__new__()方法在实例化对象时返回一个实例对象,参数是cls,是第一个被调用的方法

>>> class CapStr(str):

def __new__(cls,string):

string = string.upper()

return str.__new__(cls,string)

>>> a = CapStr("I love FishC.com")

>>> a

'I LOVE FISHC.COM'

__del__()方法

__del__()方法在对象将要被销毁时被调用

>>> class C:

def __init__(self):

print("我是init方法,我被调用了")

def __del__(self):

print("我是del方法,我被调用了")

>>> c1 = C()

我是init方法,我被调用了

>>> c2 = c1

>>> c3 = c2

>>> del c3

>>> del c2

>>> del c1

我是del方法,我被调用了

对象生成后,所有对它的引用都被del之后,才会启动垃圾回收机制

2.算数运算

运算符

对应的魔法方法

中文注释

+

__ add__(self, other)

加法

-

__ sub__(self, other)

减法

*

__ mul__(self, other)

乘法

/

__ truediv__(self, other)

真除法

//

__ floordiv__(self, other)

整数除法

%

__ mod__(self, other)

取余除法

divmod(a, b)

__ divmod__(self, other)

把除数和余数运算结果结合

**

__ pow__(self, other[,modulo])

self的other次方再对modulo取余

<<

__ lshift__(self, other)

按位左移

>>

__ rshift__(self, other)

按位右移

&

__ and__(self, other)

按位与操作

^

__ xor__(self, other)

按位异或操作(同为0,异为1)

__ or__(self, other)

按位或操作(有1则1)

反运算的魔方方法

>>> class Nint(int):

def __radd__(self,other):

return int.__sub__(self,other)

>>> a = Nint(5)

>>> b = Nint(3)

>>> a + b

8

>>> 1 + b

2

>>> #此处执行了3-1,self是3,other是1

3. 简单定制(计时器)

import time as t

class MyTimer():

def __init__(self):

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

self.prompt = "未开始计时!"

self.lasted = []

self.begin = 0

self.end = 0

# 调用实例直接显示结果

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

print(self.prompt)

>>> t1 = MyTimer()

>>> t2 = MyTimer()

>>> t1.start()

计时开始

>>> t2.start()

计时开始

>>> t1.stop()

总共运行了1分21秒

计时结束

>>> t2.stop()

总共运行了15秒

计时结束

>>> t1

总共运行了1分21秒

>>> t2

总共运行了15秒

>>> t1+t2

'总共运行了1分36秒'

利用perf_counter()和process_time()

import time as t

class MyTimer:

def __init__(self):

self.prompt = "未开始计时"

self.lasted = 0.0

self.begin = 0

self.end = 0

self.default_timer = t.perf_counter

def __str__(self):

return self.prompt

__repr__ = __str__

def __add__(self,other):

result = self.lasted + other.lasted

prompt = "总共运行了%0.2f秒" % result

return prompt

def start(self):

self.begin = self.default_timer()

self.prompt = "提示:请先调用stop()停止计时"

print("计时开始!")

def stop(self):

if not self.begin:

print("提示:请先调用start()开始计时")

else:

self.end = self.default_timer()

self._calc()

print("计时结束")

def _calc(self):

self.lasted = self.end - self.begin

self.prompt = "总共运行了%0.2f秒" % self.lasted

print(self.prompt)

self.begin = 0

self.end = 0

def set_timer(self,timer):

if timer == 'process_time':

self.default_timer = t.process_time

elif timer == 'perf_counter':

self.default_timer = t.perf_counter

else:

print("输入无效")

t1 = MyTimer()

t1.set_timer('perf_counter')

t1.start()

t.sleep(5.2)

t1.stop()

t2 = MyTimer()

t2.set_timer('perf_counter')

t2.start()

t.sleep(5.2)

t2.stop()

print(t1 + t2)

>>>

计时开始!

总共运行了5.23秒

计时结束

计时开始!

总共运行了5.21秒

计时结束

总共运行了10.44秒

>>>

4.属性访问

魔法方法

含义

__ getattr__(self, name)

定义当用户试图获取一个不存在的属性时的行为

__ getattribute__(self, name)

定义当该类的属性被访问时的行为

__ setattr__(self, name, value)

定义当一个属性被设置时的行为

__ delattr__(self, value)

定义当一个属性被删除时的行为

避免属性魔法方法的死循环:

使用super()调用基类、给特殊属性__dict__赋值

class Rectangle:

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

self.width = width

self.height = height

def __setattr__(self,name,value):

if name == 'square':

self.width = value

self.height = value

else: #避免死循环的两种方式

# super().__setattr__(name,value)

self.__dict__[name] = value

def getArea(self):

return self.width * self.height

>>> r1 = Rectangle(4,5)

>>> r1.getArea()

20

>>> r1.square = 10

>>> r1.getArea()

100

>>>

5. 描述符

将某种特殊类型的类的实例指派给另一个类的属性

__get__(self,instance,owner)

访问属性,返回属性的值

__set__(self,instance,value)

在属性分配中调用,不返回任何内容

__delete__(self,instance)

控制删除操作,不返回任何值

>>> class Mydecript:

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 = Mydescript()

Traceback (most recent call last):

File "", line 1, in

class Test:

File "", line 2, in Test

x = Mydescript()

NameError: name 'Mydescript' is not defined

>>> class Test:

x = Mydecript()

#Mydecript是x的描述类

>>> test = Test()

>>> test.x

getting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050>

>>> test.x = "X-man"

setting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050> X-man

>>> del test.x

deleting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050>

例题:温度的转换

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()

>>> temp = Temperature()

>>> temp.cel

26.0

>>> temp.cel = 30

>>> temp.fah

86.0

>>> temp.fah = 100

>>> temp.cel

37.77777777777778

>>>

6.定制序列

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

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]

>>> c1 = CountList(1,3,5,7,9)

>>> c1[1]

3

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

>>> c2[1]

4

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

7

>>> c1.count

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

>>> c2[1]

4

>>> c2.count

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

>>>

7.迭代器

迭代器是实现了__next__()方法的对象,不能回退

>>> 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

>>> string = "FishC"

>>> it = iter(string)

>>> while True:

try:

each = next(it)

except StopIteration:

break

print(each)

F

i

s

h

C

>>> for each in string:

print(each)

F

i

s

h

C

>>>

例题:使用迭代器实现斐波那契数列

>>> 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