前言
这篇笔记不太全,所以各一级标题没有编号,可以通过字体大小来区分~
函数重写 overwrite
定义
在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)像内建对象一样进行函数操作
问题
class MyDict:
Pass
D = MyDict()
len(D)可以求长度吗?
1.对象转字符串函数
repr(x)
返回一个能代表此对象的表达式字符串
通常:eval(repr(obj)) = obj
str(obj)
通过给定对象,返回一个字符串(给人阅读的字符串)
2.对象转字符串函数的重写方法
repr()函数的重写
def __repr__(self):
...
return 字符串
str()函数的重写
def __str__(self):
...
return 字符串
示例 mynumber.py
# mynumber.py
#示意 repr(obj) 和 str(obj)的重写方法
class MyNumer:
def __init__(self, value):
self.data = value
def __str__(self):
print('正在调用__Str__方法,转换为普通字符串')
s = '自定义数据%d' % self.data
return s
def __repr__(self):
return 'MyNumer(%d)' % self.data
n1 = MyNumer(100)
print(str(n1))
#__str__重写之前: <__main__.MyNumer object at 0x7fdf5701acf8>
#__str__重写之后:正在调用__Str__方法,转换为普通字符串
# 自定义数据100
# 此时 s = str(n1),
#先去找__str__, 再去找__repr__, 内建
print(repr(n1))
Str(obj)函数调用说明
1.str(obj)函数先查找obj.__str__()方法,调用此方法并返回结果
2.如果__obj.str__方法不存在,则调用obj.__repr__()方法并返回结果
3.如果obj.__repr__方法不存在,则调用object类的__repr__,实例方法显示<__main__.MyNumer object xxx>格式的字符串
3.内建函数重写
__abs__
Abs(obj)函数调用
__len__
Len(obj) 函数调用
__reversed__
Reversed(obj) 函数调用
__round__
round(obj) 函数调用
示例 myinteger.py
# myinteger.py
# 示意 abs \ len方法的重写方法
class MyInteger:
def __init__(self, v):
self.data = v
def __repr__(self):
return 'MyInteger(%d)' % self.data
def __abs__(self):
'''此方法用于制定abs(obj)函数取值时返回的结果'''
if self.data < 0 :
t = MyInteger(-self.data)
#临时用-self.data创建一个新的对象返回回去
#不用 return -self.data,是为了不改变数据类型
return t
return MyInteger(self.data)
i1 = MyInteger(-100)
print(i1) # = print(str(i1)) MyInteger(200)
#为什么i1可以取出值???
n = abs(i1) #abs返回啥,就print啥
print(n) #MyInteger(100)
i2 = MyInteger(200)
print(abs(i2)) #MyInteger(200)
示例 myinteger_len.py
# myinteger_len.py
# 示意 abs \ len方法的重写方法
class MyInteger:
def __init__(self, v):
self.data = v
def __repr__(self):
return 'MyInteger(%d)' % self.data
def __abs__(self):
'''此方法用于制定abs(obj)函数取值时返回的结果'''
if self.data < 0 :
t = MyInteger(-self.data)
#临时用-self.data创建一个新的对象返回回去
#不用 return -self.data,是为了不改变数据类型
return t
return MyInteger(self.data)
def __len__(self):#只能返回整形数,不能return 'hello'
return 10
i1 = MyInteger(-100)
print(len(i1)) #len帮你调
print(i1.__len__()) #自己手动调
4.数值转换函数重写
__complex__
Complex(obj)函数调用
__int__
int(obj)函数调用
__float__
float(obj)函数调用
__bool__
bool(obj)函数调用
示例 mynumber2.py
# mynumber2.py
#示意 自定义对象转为python内建的数据类型
class MyNumber:
def __init__(self, v):
self.data = v
def __repr__(self):
return 'MyNumber(%d)' % self.data
def __int__(self):
return int(self.data)
n1 = MyNumber(100.5)
n = int(n1) #没有__int__时,自定义转为整数,出错
print(n)
5.布尔测试函数重写
语法
Def __bool__(self):
…
作用
1.用于bool(obj)函数取值
2.用于if语句 真值表达式中
3.用于while语句 的表达式中
说明
1.当自定义类内有__bool__(self)方法时,以此方法的返回值作为bool(obj)的返回值
2.当不存在__bool__(self)方法时,bool(x)返回__len__(self)方法的返回值是否为零来测试布尔值
3.当不存在__len__(self)方法时,则直接返回True
示例 bool.py
# bool.py
# 示意 __bool__方法的重写方法及用法
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __len__(self):
print('__len__方法被调用')
return len(self.data)
def __bool__(self):
'''此方法用来制定一个bool(x)返回的规则'''
print('__bool__方法被调用')
# 如果没有任何元素,返回False
if len(self.data) ==0:
return False
#实现的是any()的功能
for x in self.data:
if x:
return True
return False
# myl = MyList([1, -2, 3, -4])
# print(myl) #MyList([1, -2, 3, -4])
# print(bool(myl)) # True
# print(len(myl)) # 4
myl = MyList()
print(myl) #MyList([])
print(bool(myl)) # 在添加__bool__之前,False,bool会调用里面的__len__
print(len(myl)) # 0
myl1 = MyList([0, 0.0, False, None])
print(bool(myl1)) #False
myl2 = MyList([0, 1, 2])
print(bool(myl2)) #True
迭代器
迭代器
可以通过next函数 取值的对象就是迭代器
迭代器协议
是指对象能够使用next函数获取下一个数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定
迭代器的实现方法
__next__(self) 此方法用来实现迭代器协议
什么是可迭代对象
1.是指能用iter(obj)函数返回迭代器对象
2.可迭代对象内部要定义__iter__(self)方法来返回迭代器对象
可迭代对象的语法形式
class MyIterable:
def __iter__(self):
语句块
return 迭代器
示例 myrange.py
# myrange.py
# 示意 用自定义的类MyRange实现可迭代对象
#用自定义的类MyIterator实现迭代器
class MyIterator:
def __init__(self, start, stop, step):
#self.start:初始位置和当前位置
self.start = start
self.stop = stop
self.step = step
def __next__(self):
'''此方法用于实现迭代器协议'''
print('MyIterator.__next__方法被调用!')
if self.start >= self.stop:
raise StopIteration
r = self.start #先将要返回的数存于变量r中
self.start += self.step #迭代器后移
return r #送回给next(it),调用
class MyRange:
def __init__(self, start, stop=None, step=1):
if stop is None:
stop = start
start = 0
self.start = start
self.stop = stop
self.step = step
def __repr__(self):
return 'MyRange(%d, %d, %d)' % (self.start,
self.stop, self.step)
def __iter__(self):
'''此方法用于把MyRange类型创建的对象当做可迭代对象'''
print('__iter__被调用')
# return None #出错
#此处必须返回迭代器
return MyIterator(self.start, self.stop, self.step)
L = [x for x in MyRange(5,10)]
print(L)
R = MyRange(5, 10, 2)
it = iter(R) # R.__iter__
print(next(it)) # it.__next__
面向对象编程语言的特征
(待完善)
封装
让有些东西变得不可见,只留一些方法给别人调用。
__双下划线开头,隐藏属性
继承/派生
不改变原有类的情况下,进行扩展、修改
覆盖
让原有的方法,在此类中不被调用;
Super()
用来访问被覆盖的方法
根据MRO顺序来查找方法
多态
如果一个对象有相同的方法,即使没有继承关系,也可以调用类中的函数。。。。
有继承/派生的类中
鸭子模型
多继承
支持多继承的:c++ 、python3
不支持多继承:Java、objective-C、Swift、C#
MRO属性
Method resolution order,用c3算法实现的(广度优先)
函数重写
让内建函数对我们自己写的函数进行操作
Repr、str、abs、… 、next(所有迭代器都有的方法)、iter(所有可迭代对象都有的方法)
可迭代对象 __iter__(self)
一定要返回迭代器
迭代器__next__(self)
用来实现迭代器协议
异常
相关语句
try-except:捕获异常
try-finally:一定要做的事,打开文件、关闭文件
Raise:触发异常,发送错误通知
Assert:根据条件触发AssertionError类型的错误通知
With语句
With语句
语法
With 表达式1 [ as 变量1], 表达式2 [ as 变量2],…:
语句块
作用
使用与对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的‘清理’操作,并释放资源
如:文件 使用后自动关闭,线程中锁的自动获取和释放等
说明
1.执行表达式用as子句中的变量绑定生成的对象
2.with语句并不会改变异常的状态
示例 with.py
# with.py
# 示意with语句的用法
src_file = input('请输入源文件:')
try:
src = open(src_file, 'rb')
try :
try:
#准备打开另一个文件
dst_file = input('请输入目标文件:')
dst = open(dst_file,'wb')
try:
#开始读写文件
b = src.read()
dst.write(b)
finally:
#关闭文件
dst.close()
except OSError:
print('打开写文件失败')
finally:
src.close()
except OSError:
print('打开文件失败')
示例 with2.py
# with2.py
# 示意with语句的用法
src_file = input('请输入源文件:')
dst_file = input('请输入目标文件:')
try:
with open(src_file, 'rb') as src
#准备打开另一个文件
with open(dst_file,'wb') as dst:
#开始读写文件
b = src.read()
dst.write(b)
#with会自动关闭文件
except OSError:
print('复制失败')
示例 with3.py
# with3.py
# 示意with语句的用法
src_file = input('请输入源文件:')
dst_file = input('请输入目标文件:')
try:
with open(src_file, 'rb') as src, \
open(dst_file, 'wb') as dst:
b = src.read()
dst.write(b)
except OSError:
print('复制失败')
环境管理器 / 上下文管理器
定义
1.类内有__enter__方法和__exit__实例方法的类 称为环境管理器
2.能够用with语句进行管理的对象 必须是环境管理器
3.__enter__ 将在进入with语句时被调用,并返回由as变量绑定的对象
4.__exit__ 将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并作出相应的处理
示例 with4.py
# with4.py
# 示意 环境管理器类的定义的使用
class A:
'''此类的对象可以用于with语句进行管理'''
def __enter__(self):
print('已经进入了with语句')
print('打开天然气')
return self
def __exit__(self, exc_type, exc_value, exc_tb):
#当with进入异常时,还是会执行__exit__.
#无论正常或异常,都会执行
#放 必须要做的事
if exc_type is None:
print('在with语句中没有异常,正常离开')
else:
print('离开with语句时出现异常')
print('异常类型是:', exc_type)
print('错误值是:',exc_value)
print('关闭天然气')
print('已经离开了with语句')
try:
with A() as a:
print('这是with语句里的打印语句')
3 / 0 #触发异常
except:
print('有异常发生,程序已转为正常!')
print('程序退出')
运算符重载
定义
让自定义的类生成的对象能够实例运算符进行操作
作用
1.让自定义类的实例像内建对象一样进行运算符操作
2.让程序简洁易读
3.对自定义的对象将运算符赋值新的运算规则
说明
1.运算符重载方法的参数已经有固定的含义,不建议改变原有的意义
1. 算术运算重载
方法名
运算符和表达式
__add__(self,rhs)
Self + rhs
__sub__(self,rhs)
Self - rhs
__mul__(self,rhs)
Self * rhs
__truediv__(self,rhs)
Self / rhs
__floordiv__(self,rhs)
Self // rhs
__mod__(self,rhs)
Self % rhs
__pow__(self,rhs)
Self ** rhs
rhs(right hands side) 右手边
2. 二元运算符的重载格式
格式
def __xxx__(self, other):
运算规则的语句...
练习:实现两个自定义的列表相加。
Mylist.py
#mylist.py
#exer_mylist.py的评讲
class MyList:
class MyIterator:
#把迭代器放进类里
def __init__(self, lst):
self.data = lst #绑定要迭代的列表
self.index = 0 #迭代的起始位置
def __next__(self):
if self.index >= len(self.data):
raise StopIteration #发送迭代结束通知
r = self.data[self.index]
self.index += 1
return r #返回此次迭代的数据
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def append(self, v):
self.data.append(v)
def __repr__(self):
return 'MyList(%r)' % self.data
def __iter__(self):
'''迭代器'''
return MyList.MyIterator(self.data)
#因为把迭代器放进类里了,所以是MyList.开头
def __len__(self):
return len(self.data) #self.data.__len__()
def __add__(self, rhs):
return MyList(self.data + rhs.data)
def __mul__(self, rhs):
return MyList(self.data * rhs)
L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L3 = L1 + L2
print(L3)
L4 = L2 + L1
print(L4)
L5 = L1 * 2
print(L5)
3.反向算术运算符的重载
定义
当运算符的左侧为内建类型时,右侧为自定义类型进行算术运算时,会出现TypeError错误,因无法修改内建类型的代码来实现运算符重载,此时需要使用反向算术运算符 重载来完成重载
方法名
运算符和表达式
__radd__(self,rhs)
lhs + self
__rsub__(self,rhs)
lhs - self
__rmul__(self,rhs)
lhs * self
__rtruediv__(self,rhs)
lhs / self
__rfloordiv__(self,rhs)
lhs // self
__rmod__(self,rhs)
lhs % self
__rpow__(self,rhs)
lhs ** self
rhs(right hands side) 右手边
示例 mylist2.py
#mylist2.py
#示意 反向算术运算 重载
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __mul__(self, rhs):
return MyList(self.data * rhs)
def __rmul__(self, lhs):
return MyList(self.data * lhs)
L1 = MyList([1, 2, 3])
L6 = 2 * L1 #没有反向运算符重载时,等同于 2.__mul__(L1)
# L1.__imul__(2)
print(L6)
4. 复合赋值算术运算符重载
说明
以复合赋值算术运算 x += y为例,此运算符会优先调用x.__iadd__(y)方法 ,如果没有__iadd__方法时会将复合赋值运算符拆为 x = x + y,然后调用x = x.__add__(y)方法 ,如果再不存在__add__方法则会触发TypeError异常
其它复合赋值算术运算符也具有相同规则
方法名
运算符和表达式
__iadd__(self,rhs)
Self += rhs
__isub__(self,rhs)
Self -= rhs
__imul__(self,rhs)
Self *= rhs
__itruediv__(self,rhs)
Self /= rhs
__ifloordiv__(self,rhs)
Self //= rhs
__imod__(self,rhs)
Self %= rhs
__ipow__(self,rhs)
Self **= rhs
rhs(right hands side) 右手边
5. 比较运算符的重载
方法名
运算符和表达式
__lt__(self, rhs)
Self < rhs little than
__le__(self, rhs)
Self <= rhs little equal
__gt__(self, rhs)
Self > rhs
__ge__(self, rhs)
Self >= rhs
__eq__(self, rhs)
Self == rhs
__ne__(self, rhs)
Self != rhs
ps
比较运算符通常返回布尔值
6. 位运算符的重载
方法名
运算符和表达式
说明
__invert__(self, rhs)
~self
取反
__and__(self, rhs)
self & rhs
位与
__or__(self, rhs)
self | rhs
位或
__xor__(self, rhs)
self ^ rhs
位异或
__lshift__(self, rhs)
self << rhs
左移
__rshift__(self, rhs)
self >> rhs
右移
7. 反向位运算符的重载
方法名
运算符和表达式
说明
__rand__(self, rhs)
lhs & self
位与
__ror__(self, rhs)
lhs | self
位或
__rxor__(self, rhs)
lhs ^ self
位异或
__rlshift__(self, rhs)
lhs << self
左移
__rrshift__(self, rhs)
lhs >> self
右移
8. 复合赋值位运算符的重载
方法名
运算符和表达式
说明
__iand__(self, rhs)
self &= rhs
位与
__ior__(self, rhs)
self |= rhs
位或
__ixor__(self, rhs)
self ^= rhs
位异或
__ilshift__(self, rhs)
self <<= rhs
左移
__irshift__(self, rhs)
self >>= rhs
右移
9. 一元运算符的重载
方法名
运算符和表达式
说明
__neg__(self)
- self
负号
__pos__(self)
+ self
正号
__invert__(self)
~ self
取反
语法格式
def __xxx__(self):
…
示例 mylist5.py
# mylist5.py
# 示意 一元运算符的重载
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __neg__(self):
'''规则是正变负,负变正'''
L = [-x for x in self.data]
return MyList(L)
L1 = MyList([1, -2, 3, -4, 5])
L2 = -L1 #等同于L1.__neg__()
print(L2)
10. in/not in 运算符
方法名
运算符和表达式
说明
__contains__(self, e)
e in self
成员运算
示例 mylist6.py
# mylist6.py
# in / not in 运算符重载
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __contains__(self, e):
return e in self.data
L1 = MyList([1, -2, 3, -4, 5])
if 3 in L1:
print('3 in L1')
else:
print('3 is not in L1')
11. 索引和切片运算符的重载
索引
重载方法
运算符和表达式
说明
__getitem__(self, i)
x = self [i]
索引/切片取值
__setitem__(self, i, val)
self [i] = val
索引/切片赋值
__delitem__(self, i)
del self [i]
del语句索引/切片
作用
让自定义的类型的对象能够支持索引和切片操作
示例 mylist7.py 索引
# mylist7.py
# 索引/切片重载
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __getitem__(self, i):
return self.data[i]
def __setitem__(self, i, val):
self.data[i] = val
L1 = MyList([1, -2, 3, -4, 5])
x = L1[0] #L1.__getitem__(0)
print(x)
L1[1] = 2 #L1.__setitem__(1, 2)
print(L1)
slice函数
作用
1.用于创建一个slice切片对象
2.此对象存储一个切片起始值,终止值,步长值信息
格式
slice(start=None, stop=None,step=None)创建一个slice切片对象
slice对象属性
s.start
切片的起始值
s.stop
切片的终止值
s.step
切片的步长
示例 mylist8.py 切片
# mylist8.py
#切片 重载
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%r)' % self.data
def __getitem__(self, i):
print('i = ', i )
if type(i) is slice:
print('起始值:', i.start)
#slice对象会被传给i,该对象存储start/stop/step
return self.data[i]
L1 = MyList([1, -2, 3, -4, 5])
x = L1[::2]
print(x)
特性属性
特性属性@property
实现其他语言所拥有的getter和setter功能
作用
1.用来模拟一个属性
2.通过@property装饰器 可以对模拟的属性赋值和取值加以控制
示例 property.py
# property.py
# 示意 特性属性
class Student:
def __init__(self, score):
self.__score = score
def get_score(self):
'''实现getter'''
return self.__score
def set_score(self, s):
'''实现setter'''
if 0 <= s <= 100:
self.__score = s
else:
raise ValueError
score = property(get_score, set_score)
s = Student(59)
print(s.score) #print(s.get_score())
s.score = 97 #s.set_score(97)
#最好不要操作属性,用方法对其进行操作
#用property,其实,s.score调用的是s.set_score()
print(s.score)