魔法方法目录

  • ​​\__init__(self[, ...])​​
  • ​​\__new__(cls[, ...])​​
  • ​​upper()​​
  • ​​\__del__(self)​​
  • ​​定时器​​
  • ​​描述符​​
  • ​​\__get__(self, instance, owner)​​
  • ​​\__set__(self, instance, value)​​
  • ​​\__delete__(self, instance)​​
  • ​​练习1:摄氏度华氏度转换​​
  • ​​协议​​
  • ​​容器类型的协议​​
  • ​​练习2​​
  • ​​迭代​​
  • ​​迭代器​​
  • ​​iter()​​
  • ​​next()​​
  • ​​版本一​​
  • ​​__iter __()​​
  • ​​__next __()​​
  • ​​版本二​​
  • ​​版本三​​






魔法方法总是被双下划线包围,例如__init__
魔法方法是面向对象的python的一切
魔法方法总能够在适当的时候被自动调用


_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)
print(rect.getPeri()) #周长
print(rect.getArea()) #面积
14
12


_new_(cls[, …])

upper()

class CapStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)

a = CapStr('Hu zhuzhu')
print(a)
HU ZHUZHU


_del_(self)

错误表示: del x = x._del_()

class C:
def __init__(self):
print('我是__init__方法,我被调用了...')
def __del__(self):
print('我是__del__方法,我被调用了...')

c1 = C()
c2 = c1
c3 = c2
del c3
del c1

python入门------魔法方法_Test


print(type(len))
print(type(dir))
print(type(int))
print(type(list))

class C:
pass
print(type(C))

print(type(int('123')))
print(type('123'))
<class 'builtin_function_or_method'>
<class 'builtin_function_or_method'>
<class 'type'>
<class 'type'>

<class 'type'>

<class 'int'>
<class 'str'>


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)
print(a+b) #int(a)-int(b)
print(a-b)
-2
8


class Try_int(int):
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)

a = Try_int(3)
b = Try_int(5)
print(a+b)
print(a-b)
8
-2


python入门------魔法方法_python_02

class int(int):
def __add__(self, other):
return int.__sub__(self, other) #返回减法

a = int('5')
b = int(3)
print(a+b)
2


class Nint(int):
def __radd__(self, other):
return int.__sub__(self, other)

a = Nint('5')
print(a)

b = Nint(3)
print(a+b)

print(1+b)
5
8
2


class Nint(int):
def __radd__(self, other):
return int.__sub__(other, self)

a = Nint('5')
print(3-a)
-2


定时器

python入门------魔法方法_描述符_03


python入门------魔法方法_删除操作_04

class A():
def __str__(self):
return '胡猪猪'
a = A()
print(a)

class B():
def __repr__(self):
return '胡大猪'
b = B()
print(b)
胡猪猪
胡大猪


python入门------魔法方法_描述符_05

import time as t    #调用import,   t  = import
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): #前六个,0-5
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)

python入门------魔法方法_描述符_06


描述符

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

_get_(self, instance, owner)

用于访问属性,它返回属性的值

_set_(self, instance, value)

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

_delete_(self, instance)

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

python入门------魔法方法_python_07

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

test = Test()
test.x

print(test)
print(Test)

test.x = 'X.man'
getting... <__main__.MyDecriptor object at 0x0000014D64D845C8> <__main__.Test object at 0x0000014D64D846C8> <class '__main__.Test'>

<__main__.Test object at 0x0000014D64D846C8> #test
<class '__main__.Test'> #Test

setting... <__main__.MyDecriptor object at 0x0000014D64D845C8> <__main__.Test object at 0x0000014D64D846C8> X.man


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 __delete__(self, instance): #控制删除操作,不返回任何内容
self.fdel(instance)

class C:
def __init__(self):
self._x = None #private

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 = 'X.man' #赋值
print(c.x)
print(c._x)
X.man
X.man


练习1:摄氏度华氏度转换

1、先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性
2、要求两个属性会自动进行转换,给摄氏度输出华氏度,给华氏度输出摄氏度

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 = 30
print(temp.fah)

temp.fah = 86
print(temp.cel)
86.0
30.0


协议

协议(Protocols)与其他编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在python中的协议就显得不那么正式。事实上,在python中,协议更像是一种指南。

容器类型的协议

1、如果定制的容器是不可变的,只需定义__len__()和__getitem__()方法。
2、如果定制的容器是可变的,除了__len__()和__getitem__()方法,还需定义__setitem__()和__delitem__()两个方法。

练习2

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

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)
c2 = CountList(2,4,6,8,10)
print(c1[1])
print(c2[1])
print(c1[1]+c2[1])

print(c1.count)
print(c2.count)
3
4
7
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}


迭代

for i in 'FishC':
print(i)
F
i
s
h
C



links = {'胡猪猪':'是猪',\
'胡大猪':'shizhu',\
'胡二猪':'是只猪',\
'胡三猪':'zhu'}
for each in links:
print('%s -> %s' % (each, links[each]))
胡猪猪 -> 是猪
胡大猪 -> shizhu
胡二猪 -> 是只猪
胡三猪 -> zhu


迭代器

iter()

next()

string = 'Fishc'
it = iter(string)
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
F
i
s
h
c


string = 'Fishc'
it = iter(string)
while True:
try:
each = next(it)
except StopIteration:
break
print(each)


for each in string:
print(each)
F
i
s
h
c
F
i
s
h
c


版本一

__iter __()

__next __()

class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
#self.a = self.b
#self.b = self.a + self.b
return self.a

fibs = Fibs()
for each in fibs:
if each < 20:
print(each)
else:
break #大于等于20跳出循环输出
1
1
2
3
5
8
13 #等于前两个数相加


版本二

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 #大于10生成错误输出
return self.a

fibs = Fibs()
for each in fibs:
if each < 20:
print(each)
else:
break
1
1
2
3
5
8


版本三

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(100) #这个不一样
for each in fibs:
print(each) #没有了if-else
1
1
2
3
5
8
13
21
34
55
89