day19
类的函数 issubclass(子类, 父类) 判断一个类是否继承自其他的类
封装 (以__开头的属性为私有属性)
多态(只有动态没有静态)
面向对象的三大特征
多继承
多继承的问题(标识符冲突)
多继承的 MRO(Method Resolution Order)问题
(__mro__用来记录类的方法查找顺序)
函数重写 overwrite
对象转字符串函数 1.repr(x) 2. str(x)
覆盖父类继承 __repr__,__str__
重新定义新的__repr__,__str__方法
对象转字符串的重写方法:
repr() 函数的重写方法:
def __repr__(self):
return 字符串
str()函数重写方法:
def __str__(self):
return 字符串
内建函数重写(len, abs, reversed, round)
数值转换函数(int, complex, bool, float)
对象属性管理函数
eg:
class Dog:
pass
d = Dog()
setattr(d, 'color', '白色') #等同于d.color = '白色'
hasattr(d, 'kins') #False 判断有没有相应的属性
getattr(d, 'color') #'白色'
getattr(d, 'kinds') #报错
getattr(d, 'kinds', '没有这个属性') #没有这个属性
delattr(d, 'color') 等同于del d.color
dir(d)
迭代器:
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __iter__(self):
'''此方法用于返回一个能访问self对象的迭代器'''
print('__iter__被调用')
return MyListIterator(self.data) #创建迭代器并返回
class MyListIterator:
'''此类用来描述能够访问MyListIterator类型的对象的迭代器'''
def __init__(self, lst):
self.data_lst = lst
self.cur_index = 0 #迭代器访问起始位置
def __next__(self):
'''此方法用来实现迭代器协议'''
print("__next__方法被调用")
if self.cur_index >= len(self.data_lst):
raise StopIteration
r = self.data_lst[self.cur_index]
self.cur_index += 1
return r
############################################################
day19笔记
用于类的函数
issubclass(cls,class__or__tuple)
判断一个类是否继承自其他的类.如果此类cls是class或tuple中一个派生子类则返回True,否则返回False
示例:
class A:
pass
class B(A):
pass
class C(B):
pass
issubclass(C,B) #True
issubclass(B,A) #True
issubclass(C,A) #True
issubclass(A,C) #False
issubclass(bool, int) #True
封装 enclosure
封装是指隐藏类的实现细节,让使用者不关心这些细节
封装的目的是让使用者通过尽可能少的方法(或属性)操作对象
私有属性和方法
python类中,以双下划线('__')开头,不以双下划线结尾的标识符
为私有成员,私有成员只能使用该类的方法来进行访问和修改
1.以__开头的属性为私有属性
2.以__开头的方法为私有方法
示例见:enclosure.py
#此示例示意用私有属性和私有方法来实现封装
class A:
def __init__(self):
self.__p1 = 100 #p1为私有属性 等同于self._A__p1
# self._p2 = 200
# self.__p2__ = 200
def show_info(self):
self.__p1 = 200
print(self.__p1) #此对象的实例方法可以访问和修改私有属性4
self.__m() #实例方法调用私有方法 5
def __m(self):
print("A类对象的__m方法被调用") #6
a = A() #创建对象a 2
a.show_info() #200 3
a.__m() #出错,除A类的实例方法外,不能调用a对象的私有方法
# print(a.__p1) #不允许访问私有属性,只能用实例方法来访问
# print(a._p2) #非双下划线开头,可以访问非私有属性
# print(a.__p2__) #只是双下划线开头的是私有属性
注: python的封装是假的封装(模拟的封装)
多态 polymorphic
字面意思:'多种状态'
多态是指有继承和派生关系的类中,调用基类对象的方法,实际能调动子类的覆盖方法的现象叫做多态
状态:
静态(编译时状态)----->> python无静态
动态(运行时状态)
说明:
1.多态调用方法与对象相关,不写类型相关
2.pyhthon全部对象都只有'运行时状态(动态)'
没有'C++语言'里的编译时状态(静态)
面向对象编程语言的特征:
继承
封装
多态(执行子类覆盖版本的内容)
多继承 multipe inheritance
多继承是指一个子类继承自两个或两个以上的基类
语法:
class 类名(基类名,基类名2,.....)
说明:
一个子类同时继承自多个父类,父类的方法可以同时被继承下来
如果两个父类中有同名的方法,而在子类中又没有覆盖此方法,调用
结果难以确定
示例见:
multipe_inherit.py
#此示例示意多继承
class Car:
'''汽车类'''
def run(self, speed):
print('汽车以', speed, '公里/小时速度行驶')
class Plane:
'''飞机类'''
def fly(self, height):
print('飞机以海拔', height, '米的高度飞行')
class PlaneCar(Car, Plane):
'''PlaneCar类同时继承自汽车类和飞机类'''
p = PlaneCar()
p.fly(10000)
p.run(300)
注:python中尽量使用单继承,避免使用多继承
多继承的问题(缺陷)
标识符冲突的问题(要谨慎使用多继承)
示例见:
multipe_inherit2.py
#小张写了一个类A:
class A:
def m(self):
print("A.m()被调用")
#小李写了一个类B:
class B:
def m(self):
print("B.m()被调用")
#小王干觉小张和小李写的两个类自己都可以用
class AB(A, B):
def m(self):
print("AB.m()被调用")
ab = AB()
ab.m() #请问调用谁?为什么?
多继承的 MRO(Method Resolution Order)问题
pyhotn3的类的__mro__属性
作用: 用来记录类的方法查找顺序
示例见:
mro.py
#菱形继承
class A:
def go(self):
print("A")
class B(A):
def go(self):
print("B")
super().go() #打印C
class C(A):
def go(self):
print('C')
class D(B, C):
def go(self):
print("D")
super().go() #调用基类B
d = D()
d.go()
super()函数就是根据__mro__来调用上层的方法
练习一:
写一个农民类,Peasant ,有方法:
def farm(self, plant):
....
写一个工人类Worker,有方法:
def work(self, that):
....
创建一个农民工为MigrantWorker,让此类的对象拥有上面两个类的全部方法
person = MigrantWorker()
person.farm('水稻') #正在种植水稻
person.work('汽车') #正在制造汽车
查看各个类的__mro__属性
函数重写 overwrite
什么是函数重写
在自定义的类内添加相应的方法,让自定义的类创建的实例能够
使用内建函数进行操作
对象转字符串函数
repr(x) 返回一个能够表示python对象的表达式字符串,通常
eval(repr(obj)) == obj
str(x) 通过给定的对象返回一个字符串(这个字符串通常供人阅读)
示例:
s = 'I'm a Teacher'
print(str(s)) #I'm a Teacher #人可阅读的字符串
print(repr(s)) #"I'm a Teacher" --->python语言识别的字符串
对象转字符串的重写方法:
repr() 函数的重写方法:
def __repr__(self):
return 字符串
str()函数重写方法:
def __str__(self):
return 字符串
str(obj)函数调用方法说明:
1.str(obj) 函数先查找obj.__str__(方法),调用此方法返回结果
2.如果obj.__str__()
方法不存在,则调用obj.__repr__方法并返回结果
3.如果obj.__repr__方法不存在,则调用objice类的__repr__实例显示
<__main__.XXXX object at 0xXXXXXXX> 格式的字符串
示例见:
mynumber.py
#此示例示意对象转字符串函数的重写方法
class Mynumber:
def __init__(self, val):
self.data = val #在每个对象内部创建一个实例变量来绑定数据
def __str__(self):
print("__srt__方法被调用")
return '自定义数字:%d' % self.data
def __repr__(self):
'''此方法返回的字符串一定是能表示self对象的表达式字符串'''
print("__repr__方法被调用")
return '自定义数字:%d' % self.data
n1 = Mynumber(100)
print("str(n1) =", str(n1)) #自定数字:100
#str(n1)等同于 n1.__str__()
print("repr(n1) =", repr(n1)) # Mynumber(100)
#调用objice内的__repr__方法
n2 = Mynumber(200)
print("str(n2) =", str(n2))
#等同于
print(n2.__str__())
print(n2) #在print内部会将n2用str(x)转为字符串在写到sys.stdout
内建函数重写
方法名 函数名
def __abs__(self): abs(obj) 函数调用
def __len__(self): len(obj) 函数调用
def __reversed__(self): reverised(obj) 函数调用
def __round__(self): round(obj) 函数调用
示例见:
len_overwrite.py
class MyList:
'''这是一个自定义的列表类型,
此类型的对象用data属性绑定的列表来存储数据'''
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __len__(self):
return len(self.data)
def __abs__(self):
# L = []
# for x in self.data:
# x = abs(x)
# L.append(x)
L = [abs(x) for x in self.data]
return MyList(L)
myl = MyList([1, -2, 3, -4])
print(myl) #MyList([1, -2, 3, -4])
print(len(myl)) #4 #len(L) 相当于 L.__len__()
print(abs(myl)) #MyList([1, 2, 3, 4])
数值转换函数的重写:
方法名 函数名
def __complex__(self): complex(obj) 函数调用
def __int__(self): int(obj) 函数调用
def __float__(self): float(obj) 函数调用
def __bool__(self): bool(obj) 函数调用
示例见:mynumber3.py
#此示例示意数值转化的重写
class Mynumber:
def __init__(self, val):
self.data = val #在每个对象内部创建一个实例变量来绑定数据
def __repr__(self):
print("__repr__方法被调用")
return 'Mynumber:%d' % self.data
def __int__(self):
'''重写int(obj)函数'''
return int(self.data)
def __float__(self):
print("__float__")
return float(self.data)
n1 = Mynumber(100)
n = int(n1)
print(n) #100
f = float(n1)
print(f) #100.0
c = complex(n1) #当没有n1.__complex__()时会调用n1.__float__()
print(c)
布尔测试函数的重写
格式:
def __bool__(self):
...
作用:
用于bool(obj)函数取值
用于if 语句真值表达式
用于while语句的真值表达式
说明:
1.当自定义类内有__bool__(self)方法时,此方法返回作为bool(x)
的返回值
2.当不存在__bool__(self)方法时,返回__len__(self)
方法返回值是否为非零来测试布尔值
3.当不存在__len__(self)方法时,则直接返回True
示例:
bool.py
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):
print('__bool__方法被调用')
for x in self.data:
if x:
return True
return False
# return any(self.data)
myl = MyList([False, 0, 0.0])
print(bool(myl))
if myl:
print(myl, '的布尔值为True')
else:
print(myl, '的布尔值为False')
对象的属性管理函数:
getattr(obj, name[,defalut])
从一个对象用字符串name得到对象的属性,getattr(x, 'y')
等同于x.y;当属性不存在时,如果给定defalut参数则返回defalut,
如果没有给出defalut,则触发一个AttributeError错误
hasattr(obj, name)
用给定的name字符串返回obj是否有此属性,此种做法可以避免在getattr(obj, name)时引发错误
setattr(obj, name, value)
给对象obj的名为name的属性设置相应的值value, setattr(x, 'y', v)
等同于 x.y = v
delattr(obj, name)删除对象obj中的name属性del(x, 'y')
等同于 del x.y
示例:
class Dog:
pass
d = Dog()
setattr(d, 'color', '白色') #等同于d.color = '白色'
hasattr(d, 'kins') #False 判断有没有相应的属性
getattr(d, 'color') #'白色'
getattr(d, 'kinds') #报错
getattr(d, 'kinds', '没有这个属性') #没有这个属性
delattr(d, 'color') 等同于del d.color
dir(d)
迭代器(高级)
什么是迭代器?
由iter(x) 函数返回,可以通过next(it)函数取值的对象就是迭代器
迭代器协议:
迭代器协议是指对象能够使用next()函数获取下一项数据,在没有下一项数 据时触发一个StopIteration异常来终止迭代的约定
迭代器协议的实现方法:
def __next__(self):
...
注:此方法需要实现迭代器协议
什么是可迭代对象?
是指能用iter(obj) 函数返回迭代器的对象(实例)
可迭代对象内部要定义__iter__(self)方法来返回迭代器对象
示例见:
myiterator.py
#此示例示意将自定义的类MyList创建的对象成为可迭代对象
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return 'MyList(%s)' % self.data
def __iter__(self):
'''此方法用于返回一个能访问self对象的迭代器'''
print('__iter__被调用')
return MyListIterator(self.data) #创建迭代器并返回
class MyListIterator:
'''此类用来描述能够访问MyListIterator类型的对象的迭代器'''
def __init__(self, lst):
self.data_lst = lst
self.cur_index = 0 #迭代器访问起始位置
def __next__(self):
'''此方法用来实现迭代器协议'''
print("__next__方法被调用")
if self.cur_index >= len(self.data_lst):
raise StopIteration
r = self.data_lst[self.cur_index]
self.cur_index += 1
return r
myl = MyList([2, 3, 5, 7])
it = iter(myl) #等同于调用 it = myl.__iter__()
print(next(it))
print(next(it))
print(next(it))
print(next(it))
for x in myl:
print(x)
L = [x**2 for x in myl]
print(L)
课后练习:
1.实现原学生信息管理系统Student类的封装,让除Student实例方法
外的函数或其它方法都不能访问姓名,年龄,成绩等属性
2.写一个实现迭代器协议的类,让此类可以生成从b开始n个素数
class Prime:
def __init__(self, b, n):
...
def __iter__(self):
...
def __next__(self):
...
L = [x for x in Prime(10, 4)]
print(L) #L = [11, 13, 17, 19]
3.写一个类Fibonacci实现迭代器协议,此类的对象可以作为可迭代对象生成斐波那契数名
1 1 2 3 5 8 13 .....
class Fibonacci:
def __init__(self, n):
...
...
for x in Fibonacci(10):
print(x) #打印1 1 2 3 5 8 13....