19.5 描述符
当一个类中,包含了三个魔术方法(__get__、__set__、__del__
)之一,或者全部时,那么这个类就称为 描述符类
19.5.1 描述符的基本语法
-
作用:
对一个类中的某个成员进行一个详细的管理操作(获取、赋值、删除)
描述符就是代理了一个类中成员的操作,只能定义为类的属性,属于类 -
使用格式:
把描述符类赋值给一个需要代理的类中的成员属性
一个类中的成员是一个描述符类的对象
当对这个类中的成员进行操作时,可以理解为就是对另一个对象的操作
# 定义描述符类
class Personname():
__name = 'name1'
def __get__(self, instance, owner):
return self.__name
def __set__(self, instance, value):
self.__name = value # 注意 !
def __del__(self):
# del self.__name
print('不允许删除')
class Person():
# 把类中的一个属性,交给描述符类来实现
name = Personname()
z = Person()
z.name = 'zhangsan'
print(z.name)
19.5.2 描述符的应用案例
- 定义一个学生类,记录学生的ID,名字,分数
- 要求学员的分数只能在0-100
# 限制分数范围
'''
方法1:__init__中判断
if score in range(0,101):
self.score = score
该方法只在对象初始化时有效!!
方法2:__setattr__
def __setattr__(self, key, value):
# 检测是否是给score进行赋值操作
if key == 'score':
if value in range(0, 101):
object.__setattr__(self, key, value)
else:
print('wrong')
else:
object.__setattr__(self,key,value)
假如学生分数不止一个,且代码是否简练?
方法3:使用描述符类代理
1,定义score描述符类
2,把学生类中score这个成员交给描述符类进行代理
3,只要在代理的描述符类中对分数进行赋值和获取
'''
# 使用描述符类代理score属性
class Score():
__score = 0
def __get__(self, instance, owner):
return self.__score
def __set__(self, instance, value):
if value in range(101):
self.__score = value
else:
print('wrong score')
class Student():
score = Score()
def __init__(self,id,name,score):
self.id = id
self.name = name
self.score = score
def Returnme(self):
info = f'''
Student ID : {self.id}
Student Name : {self.name}
Student Score : {self.score}
'''
print(info)
# 实例化对象
one = Student('20211001','wangwu',99)
one.Returnme()
one.score = 120
one.score = 100
one.Returnme()
19.5.3 描述符的三种定义方式
1.格式一:通过定义描述符来实现, 推荐
class ScoreManage():
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass
class Student():
score = ScoreManage()
2.格式二:使用property 函数实现
class Student():
def getscore(self):
print('getscore')
def setscore(self,value):
print('setscore',value)
def delscore(self):
print('delscore')
# 在 property 函数中指定对应的三个方法(固定顺序对应!),1__get__2,__set__3,__del__
score = property(getscore,setscore,delscore)
zz = Student()
print(zz.score) # getscore /n None
zz.score = 200
del zz.score
3.格式三:使用 @property 装饰器语法实现
class Student():
__score = 0
@property
def score(self):
print('getscore')
return self.__score
@score.setter
def score(self,value):
print('setscore',value)
self.__score = value
@score.deleter
def score(self):
print('delscore')
del self.__score
zs = Student()
zs.score
print(zs.score)
zs.score = 122
print(zs.score)
del zs.score
19.6 设计模式
前人为完成某个功能或需求,根据经验和总结,对实现的代码步骤和代码设计进行了总结和归纳,成为了实现某个需求的经典模式。
设计模式并不是固定的代码格式,而是一种面向对象编程的设计
19.6.1 单例(单态)设计模式
当前脚本中,同一个类只能创建出一个对象去使用
'''
干扰对类的无限使用
实现单例的案例,思考:
单例和婚姻法,特别像,一个人只能有一个合法的结婚对象:
在社会中如何完成?
到民政局登记,需要检查户口本,看是否属于已婚状态,若未婚,可以登记
1.需要有一个方法,可以控制对象的创建
构造方法 __new__
2.在此方法中,需要检测是否有对象 , 构造方法在,需要加判断条件
需要有一个标识来存储和表示是否有对象
创建一个属性,进行存储,默认值为None
3.在创建对象的方法中就可以检测和判断
若无对象,则创建对象,并存储,返回对象
若有,则直接返回对象,不需创建新对象
'''
class Demo():
# 2.定义私有属性存储对象
__obj = None
# 1.定义构造方法
def __new__(cls, *args, **kwargs):
# 3.创建对象过程,判断是否有对象
if not cls.__obj:
# 判断若没有对象,则创建并存储
cls.__obj = object.__new__(cls)
return cls.__obj
a = Demo()
b = Demo()
print(a)
print(b)
注意:要背下来!!
19.6.2 Mix-in混合设计模式
'''
交通工具类中包含汽车,飞机,直升机等,如何定义飞行功能
交通工具类和飞行器类
但是 1.出现类多继承,违背‘is-a’ 2.飞行器这个类容易造成误解
解决方案:将飞行器类定义为一个Mixin混合类
相当于把飞行器类,作为一个扩展的功能,来扩展其他类
'''
class Vehicle():
def carry(self):
print('transfer the groceries')
def carry2(self):
print('transfer passengers')
class FlyingMixin():
def fly(self):
print('fly in the sky')
class Car(Vehicle):
pass
class Airplane(Vehicle,FlyingMixin):
pass
class Helicopter(Vehicle,FlyingMixin):
pass
- python中的Mixin是通过多继承实现的
- Mixin 必须是表示一种功能,而不是一个对象
- Mixin 的功能必须是单一的,如果多个功能,就多定义几个Mixin类
- Mixin类通常不单独使用,而是混合到其他类中,去增加功能
- Mixin类不依赖子类的实现,即便子类不继承Mixin,也能正常运行,就是少了一些功能
使用Mixin类的好处
1.Mixin混合类的设计模式,在部队类的内容修改的前提下,扩展了类的功能
2.提高代码的重用性,使得代码结构更加简单清晰
3.可以根据开发需要任意调整功能
4.避免涉及多层次的复杂的继承关系
19.6.3 设计模式的抽象类(了解)
抽象类是一个特殊的类:
1.抽象类不能用,不能直接实例化成为一个对象
2.抽象类中包含抽象方法,抽象方法就是没有实现代码的方法
3.抽象类需要子类继承,并重写父类的抽象方法,才可以使用
抽象类一般应用在程序设计,程序设计中一般是要对功能和需求进行规划,其中有一些需求是明确并且可以完成的,但是也可能会有些是不明确的,不确定需要怎样实现
此时就可以把这个不确定怎么实现或者需要后面再去实现的方法,定义为抽象方法(只定义方法名,不写具体代码)
举例:
公司有一项新的产品需要开发,交给开发部门boss
boss开始设计如何完成产品开发
需要不同的技术,不同的人来完成
boss完成了部分功能,还有一部分定义了需求,但没有具体实现,需要其他人
已完成部分就是 普通方法,未完成的就可以理解为抽象方法
import abc
# 定义为抽象类,这个类的metaclass的属性必须为 metaclass=abc.ABCmeta
class Writecode (metaclass=abc.ABCmeta):
# 需要抽象的方法,需要使用装饰器
@abc.abstractmethod
def write_php(self):
pass
def write_java(self):
print('finished java')
def write_python(self):
print('completed python')
# 定义后,抽象类不能直接实例化对象
# ob = Writecode()
# TypeError:
# 定义子类,继承抽象类,并实现抽象类中的抽象方法
class Demo(Writecode):
def write_php(self):
print('achieve php')
a = Demo()
print(a)