- 封装 enclosure
封装是值隐藏类的实现细节,让使用者不关心这些细节
封装的目的是让使用者通过尽可能少的方法(或属性)操作对象
私有属性和方法
python类中,以双下划线("__")开头,不以双下划线结尾的标识符为私有成员,私有成员只能使用该类的方法来进行访问和修改
1.以__开头的属性为私有属性
2.以__开头的方法为私有方法
示例:
# enclosure.py
#此示例示意私有属性和私有方法来实现封装
class A:
def __init__(self):
self.__p1 = 100 #<=====__p1为私有属性
# self.__p2__ = 200 #这不是私有属性
def show_info(self):
print(self.__p1) # 此对象的实例方法可以访问和修改私有属性
def __m(self):
print('A类对象的__m方法被调用')
a = A()
a.show_info() #100
print(a._A__p1) #_类名__p1
print(a.__p1)
print(a.__p2__)
a.__m() #出错,除A类的实例方法外,不能调用a对象的私有方法
- 多态 polymocphic
字面意思:'多种状态'
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态
状态:
静态(编译时状态)
动态(运行时状态)
说明:
多态调用的方法和对象相关,不写类型相关
python全部对象只有'运行时状态(动态)',
没有'c++语言'里的编译时状态(静态)
示例:
class Shape:
def draw(self):
print('Shape的draw()方法被调用')
class Point(Shape):
def draw(self):
print('正在画一个点')
class Circle(Point):
def draw(self):
print('正在画一个圆')
def my_draw(s):
s.draw() #<------此处显示出多态中的'动态'
s1 = Circle()
s2 = Point()
my_draw(s1)
my_draw(s2)
面向对象编程语言的特征:
继承
封装
多态
super()函数 就是根据__mro__来调用上层的方法
练习:
写一个农民类Peasant有方法:
def farm(self,plant):
...
写一个工人类Worker
有方法如下:
def work(self,that):
...
创建一个农民工为MigrantWorker,让此类的对象拥有上面两个类的全部方法
person = MigrantWorker()
person.farm('水稻') #正在种植 水稻
person.work('汽车') #正在制造 汽车
查看各个类的__mro__属性
class Peasant:
def farm(self,plant):
print("正在种植:",plant)
class Worker:
def work(self,that):
print('正在制造:',that)
class MigrantWorker(Peasant,Worker):
pass
person = MigrantWorker()
person.farm('水稻') #正在种植 水稻
person.work('汽车') #正在制造 汽车
- 函数重写 overwrite
什么是函数重写
在自定义的类内添加相应的方法,让自定义的类创建的实例能够使用内建函数进行操作
对象转字符串函数
repr(x) 返回一个能表示python对象的表达式字符串,通常
evel(rerp(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__方法不存在,则调用object类的__repe__
实例方法显示<__main__.XXXX object at 0xXXXXXXX>格式的
字符串
示例:
class Mynumber:
def __init__(self,val):
self.data = val#在每个对象内部都创建一个实例变量来绑定数据
def __str__(self):
# print('__str__方法被调用')
return '自定义数字:%d'%self.data
def __repr__(self):
'''返回的字符串一定是能表示self对象的表达式字符串'''
return 'Mynumber(%d)'%self.data
n1 = Mynumber(100)
print('str(n1) = ',str(n1))
print('repr(n1) = ',repr(n1))
n2 = Mynumber(200)
print(str(n2))
print(n2.__str__()) #在print内部会将n2用str(x)转为字符串再写到sys.stdout
print(n2)
内建函数重写
方法名 函数名
def __abs__(self): abs(obj) 函数调用
def __len__(self): len(obj) 函数调用
def __reversed__(self): reversed(obj) 函数调用
def __round__(self): round(obj) 函数调用
示例:
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 = [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
print(abs(myl)) #Mylist([1, 2, 3, 4])
数值转换函数的重写:
def __complex__(self): complex(obj)函数调用
def __init__(self): init(obj) 函数调用
def __float__(self): float(obj) 函数调用
def __bool__(self): bool(obj) 函数调用
示例见:
class Mynumber:
def __init__(self,val):
self.data = val#在每个对象内部都创建一个实例变量来绑定数据
# def __str__(self):
# # print('__str__方法被调用')
# return '自定义数字:%d'%self.data
def __repr__(self):
'''返回的字符串一定是能表示self对象的表达式字符串'''
return 'Mynumber(%d)'%self.data
def __int__(self):
'''重写int(obj)函数'''
return int(self.data)
def __float__(self):
return float(self.data)
n1 = Mynumber(100)
n = int(n1) #出错
print(n)
f = float(n1)
print(f)
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
对象的属性管理函数:
getattr(obj,name[,default])
从一个对象用字符串name得到对象的属性,getattr(x,'y')等于同于x.y;
当属性不存在时,如果给定default参数返回default,如果没有给出default
则触发一个AttributError错误
hasattr(obj,name)
用给定的name字符串返回obj是否有此属性,此种做法可以避免在getattr(obj,name)时引发错误
setattr(obj,name,value),
给对象obj的名为name的属性设置相应的值vlaue,setattr(x,'y',v)
等同于x.y = v
delattr(obj,name) 删除对象obj中的name属性 del(x,'y') 等同于del x.y
- 迭代器(高级)
什么是迭代器
由iter(x)函数返回,可以通过next(it)函数取值的对象就是迭代器
迭代器协议:
迭代器协议是指对象能够使用next()函数获取下一项数据,在没有下一项数据时,触发一个StopIteration
异常来终止迭代的约定
迭代器协议的实现方法:
def __next__(self):
...
注:此方法需要实现迭代器协议
什么是可迭代对象
是指能用iter(obj)函数返回迭代器的对象(实例)
可迭代对象内部都要定义__iter__(self)方法来返回迭代器对象
示例:
class Mylist:
'''这是一个自定义的列表类型,此类型的对象data属性绑定的列表用来存储数据'''
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:
'''此类用来描述能够访问Mylist类型的对象的迭代器'''
print('__next__方法被调用')
def __init__(self,lst):
self.data_lst = lst
self.cur_index = 0 #迭代器访问的起始位置
def __next__(self):
'''此方法用来实现迭代器协议'''
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)) #2
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):
....
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 ...
看答案请留言