内容正文:
筐鱼梧领凤峡匪跑脚凡辅乒踪勿久褂舟婴袭剪肚爹伦甄啸镣娟附卉态再骂广东农工商职业技术学院PPT模板-精美原创毕业论文答辩广东农工商职业技术学院PPT模板-精美原创毕业论文答辩
项目10 类与对象高级应用
目录 | CONTENT
1
项目介绍
2
项目目标
3
项目准备
4
项目实施
项目介绍
项目背景
本项目在前两个项目的基础上,介绍Python类中所提供的高级面向对象设计方法。这些方法能在类设计、编码效率和程序执行效率等方面提供更好的实现方法。
项目介绍
项目规划
01
熟悉类方法、静态方法等类设计的高级方法
02
了解动态扩展类、__slot__、@property、元类(metaclass)等概念和使用方法
03
能使用上述方法运解决相关问题
目录 | CONTENT
1
项目介绍
2
项目目标
3
项目准备
4
项目实施
项目目标
知识目标
1
熟悉类方法、静态方法的概念
2
解动态扩展类、__slot__、@property、元类(metaclass)、鸭子类型等概念
3
了解Python类设计的性能的相关概念
项目目标
能力目标
1
熟练运用类方法、静态方法
2
会运用动态扩展类、__slot__、@property、元类(metaclass)、鸭子类型等方法
3
能运用Python类的一些高级方法进行类的设计
目录 | CONTENT
1
项目介绍
2
项目目标
3
项目准备
4
项目实施
项目准备
1. 静态方法
静态方法的定义之前需要添加“@staticmethod”。静态方法定义时,不需要表示访问对象的self参数,形式上与普通函数的定义类似。静态方法只能访问属于类的成员,不能访问属于对象的成员。一个类的所有实例对象共享静态方法。使用静态方法时,既可以通过“对象名.静态方法名”来访问,也可以通过“类名.静态方法名”来访问。
项目准备
1. 静态方法
class Person:
number=0
def __init__(self,name):
self.name = name
Person.number+=1
def getName(self):
print('My name is ',self.name)
@staticmethod # 声明静态,去掉则编译报错
def getNumber(): # 静态方法没有self
print("总人数为:",Person.number)
# 主程序
p_lily = Person("Lily")
p_lily.getName()
p_lily.getNumber()
Person.getNumber()
p_david=Person('David')
p_david.getName()
p_david.getNumber()
Person.getNumber()
p_lily.getNumber()
My name is Lily
总人数为: 1
总人数为: 1
My name is David
总人数为: 2
总人数为: 2
总人数为: 2
项目准备
2. 类方法
方法定义之前由“@classmethod”语句引导,第一个形参通常被命名为 cls。类方法既可以通过类名,也可以通过对象名来调用。
项目准备
2. 类方法
class Person(object):
__number = 0
def __init__(self):
Person.__number += 1
@classmethod
def getNumber(cls):
return cls.__number
class Teacher(Person):
def __init__(self, name):
self.name = name
super().__init__()
#主程序
t_mike = Teacher('Mike')
print(t_mike.getNumber())
print(Person.getNumber())
t_lucy = Teacher("Lucy")
print(t_lucy.getNumber())
print(Person.getNumber())
print(t_mike.getNumber())
1
1
2
2
2
项目准备
3. 动态扩展类
Python作为一种动态语言,除了可以在定义类时定义属性和方法外,还可以动态地为已经创建的对象绑定新的属性和方法。
项目准备
3. 动态扩展类
from types import MethodType # 从types模块中导入MethodType方法
class Student: # 定义学生类,没有定义任何方法
pass
def SetName(self,name): # 定义SetName函数
self.name=name
def SetSno(self,sno): # 定义SetSno函数
self.sno=sno
if __name__=='__main__':
stu1=Student() # 定义Student类实例stu1
stu2=Student() # 定义Student类实例stu2
stu1.SetName=MethodType(SetName,stu1) # 为stu1对象绑定SetName方法
Student.SetSno=SetSno # 为Student类绑定SetSno方法
stu1.SetName('李晓明')
stu1.SetSno('1810100')
#stu2.SetName('张刚') # 由于SetName只是绑定给了实例stu1,所以stu2
实例无法使用该方法
stu2.SetSno('1810101')
通过方法MethodType()将方法SetName绑定给了实例stu1。通过语句Student.SetSno=SetSno将方法SetSno()绑定给了类Student,从而实现了类的动态扩展。动态绑定虽然增加了类定义的灵活性,但是也破坏了面向对象的封装性原则,在实际中一般不建议使用。
项目准备
4. __slot__属性
Python在类中定义__slot__属性来限制实例的属性字段,在创建大量对象的场合可以减少内存占用。正如slot单词的含义,槽,相当于在类的设计中预留好了固定的槽。__slot__限制了属性值,添加__slot__元组之外的属性会报错。__slot__限制的是实例属性的添加,不限制类属性的添加。
class Person: # 定义Person类
__slots__ = ('name') # 定义允许动态扩展的属性
class Student(Person): #以Person类作为父类定义子类Student类
__slots__ = ('sno') # 定义允许动态扩展的属性
class Postgraduate(Student): # 以Student类作为父类定义子类Postgraduate类
pass
if __name__=='__main__':
stu=Student() # 定义Student类对象stu
stu.sno='1810100' # 为stu对象动态扩展属性sno
stu.name='李晓明' # 为stu对象动态扩展属性name
#stu.tutor='马红' # 扩展tutor属性,在__slots__中并未定义,所以报错
pg=Postgraduate() # 定义Postgraduate类对象pg
pg.sno='1810101' # 为pg对象动态扩展属性sno
pg.name='张刚' # 为pg对象动态扩展属性name
pg.tutor='马红' # 为pg对象动态扩展属性tutor
项目准备
5. @property装饰器和@setter装饰器
@property装饰器,可以将类中属性的访问和赋值操作自动转为方法调用,这样可以在方法中对属性值的取值范围做一些条件限定。
如果类中只对属性使用了@property,则对应属性会变为只读,无法更改属性值。
项目准备
5. @property装饰器和@setter装饰器
为了能够修改@property修饰的属性,需要为属性添加 setter 方法,就需要用到 setter 装饰器,其语法为:
@方法名.setter
def 方法名(self, value):
代码块
项目准备
6. 元类(metaclass)
所有的对象都是实例化或者说是通过调用类而得到的,python中一切皆对象,通过class关键字定义的类本质也是对象,对象又是通过调用类得到的,因此通过class关键字定义的类肯定也是调用了一个类得到的,这个类就是元类。
元类就是用来实例化产生类的类。
项目准备
6. 元类(metaclass)
class Student: # 定义Student类
pass
stu=Student() # 定义Student类的对象stu
print('stu所属的类是:',stu.__class__) # 使用__class__属性获取所属的类
print('Student所属的类是:',Student.__class__)
stu所属的类是: <class '__main__.Student'>
Student所属的类是: <class 'type'>
项目准备
7. 单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是指在程序运行时确保某个类最多只有一个实例对象。例如A类采用单例模式,则当创建A类对象时需要判断是否已存在A类对象:如果不存在,则创建一个A类对象;如果已存在,则直接使用已有的A类对象。
项目准备
7. 单例模式(Singleton Pattern)
当一个类对象用于存储程序中多个线程的共享信息时,就要求该类对象只有一份,以避免空间浪费以及信息不一致等问题。
__call__是Python类的一个内置方法,能够让类的实例对象,像函数一样被调用。一个类实例要变成一个可调用对象,只需要实现一个特殊方法__call__()
项目准备
7. 单例模式(Singleton Pattern)
class MyMetaclass(type): # 以type作为父类创建子类MyMetaclass
def __new__(cls, *args, **kwargs):
print('MyMetaclass中的__new__被执行!')
return super().__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs): #定义__init__方法
print('MyMetaclass中的__init__被执行!')
self._instance=None
return super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
print('MyMetaclass中的__call__被执行!')
if self._instance is None:
self._instance = super().__call__(*args, **kwargs)
return self._instance
class WebData(metaclass=MyMetaclass): # MyMetaclass作元类定义WebData类
def __new__(cls, *args, **kwargs):
print('WebData类中的__new__被执行!')
return super().__new__(cls)
def __init__(self):
print('WebData类中的__init__被执行!')
def __call__(self, timeout):
print('WebData类中的__call__被执行!')
self.timeout=timeout
if __name__=='__main__':
wb1=WebData() # 定义WebData类对象wb1
wb2=WebData() # 定义WebData类对象wb2
wb1(60) # 等价于wb1.__call__(60)
print(wb1.timeout)
wb1.timeout=30
print(wb1.timeout)
wb2.timeout=15
print(wb1.timeout, wb2.timeout)
MyMetaclass中的__new__被执行!
MyMetaclass中的__init__被执行!
MyMetaclass中的__call__被执行!
WebData类中的__new__被执行!
WebData类中的__init__被执行!
MyMetaclass中的__call__被执行!
WebData类中的__call__被执行!
60
30
15 15
项目准备
8. 鸭子类型(Duck Typing)
鸭子类型(Duck Typing)的含义是“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。
在鸭子类型中,关注的不是对象所属的类,而是一个对象能够如何使用。在Python中编写一个函数,传递实参前其参数的类型并不确定,在函数中使用形参进行操作时只要传入的对象能够支持该操作程序就能正常执行。
项目准备
8. 鸭子类型(Duck Typing)
class Person: #定义Person类
def CaptureImage(self): #定义CaptureImage方法
print('Person类中的CaptureImage方法被调用!')
class Camera: #定义Camera类
def CaptureImage(self): #定义CaptureImage方法
print('Camera类中的CaptureImage方法被调用!')
def CaptureImageTest(arg): #定义CaptureImageTest方法
arg.CaptureImage() #通过arg调用CaptureImage方法
if __name__=='__main__':
p=Person() #定义Person类对象p
c=Camera() #定义Camera类对象c
CaptureImageTest(p)
CaptureImageTest(c)
Person类中的CaptureImage方法被调用!
Camera类中的CaptureImage方法被调用!
目录 | CONTENT
1
项目介绍
2
项目目标
3
项目准备
4
项目实施
项目实施
任务10.1 getter、setter、deleter方法与装饰器
数据封装、继承和多态只是面向对象程序设计中最基础的3个概念。在Python中,面向对象还有很多高级特性。
在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改。Python内置的@property装饰器可以把一个方法变成属性调用。
本任务要求定义一个Person类,包含属性first_name。定义该属性的setter、getter与deleter方法,使得通过Person类实例访问first_name属性时,能够自动调用相应方法。
项目实施
任务10.1 getter、setter、deleter方法与装饰器
建立 “getter、setter、deleter.py”文件,用于编写Python实验程序
编写任务代码
# 定义一个Person类,该类有一个first_name属性
class Person:
def __init__(self, first_name):
self.first_name = first_name
@property # 定义first_name属性的getter方法
def first_name(self):
print('getter')
return self._first_name
@first_name.setter # 定义first_name属性的setter方法
def first_name(self, value):
print('setter')
if not isinstance(value, str):
print('请输入正确的名字')
self._first_name = value
@first_name.deleter # 定义first_name属性的deleter方法
def first_name(self):
print('deleter')
# 创建Person类的实例,并调用相应的方法
if __name__ == '__main__':
person = Person('Tom')
print(person.first_name)
person.first_name = 'Jerry'
del person.first_name
项目实施
任务10.1 getter、setter、deleter方法与装饰器
执行程序
①用鼠标右键单击右侧编辑窗口,在菜单中选择“Run ‘python主程序所在文件名’”一项执行编写好的Python程序,本次实验文件名为“getter、setter、deleter”
②在IDE下方控制台查看输出结果
课后练习与技能训练
一、填空题
练习
1.Python提供了 变量以限制可动态扩展的属性。
2.Python提供了 装饰器,可以将类中属性的访问和赋值操作自动转为方法调用,这样可以在方法中对属性值的取值范围做一些条件限定。
3.直接使用@property可以定义一个用于获取属性值的方法(即getter)。如果需要对属性score定义一个设置属性值的方法(setter),需要用到的装饰器为 。
课后练习与技能训练
一、填空题
练习
4. 可以看成是创建类时所使用的模板,也可以理解为是用于创建类的类。
5. 是指在程序运行时确保某个类最多只有一个实例对象。
6.在执行__init__前,还会执行类的一个内置的类方法 ,其作用是创建对象并返回。
课后练习与技能训练
二、选择题
练习
1.关于类方法的说法错误的是()
类方法是指使用@classmethod修饰的方法
类方法的第一个参数是类本身(而不是类的实例对象)
类方法既可以通过类名直接调用,也可以通过类的实例对象调用。
类方法只能通过类名直接调用
课后练习与技能训练
二、选择题
练习
2.关于静态方法的说法错误的是()
静态方法是指使用@staticmethod修饰的方法
静态方法的第一个参数是类本身(而不是类的实例对象)
静态方法既可以通过类名直接调用,也可以通过类的实例对象调用。
静态方法中没有类方法中的第一个类参数
课后练习与技能训练
二、选择题
练习
3.已知Complex类的类方法add(cls,c1,c2)实现两个复数的相加运算,程序可以使用不同的方式调用该方法,下面错误的调用方式是()
A.c3=Complex.add(c1,c2)
B.c3=c1.add(c1,c2)
C.c3.add(Complex,c1,c2)
D.c3=Complex().add(c1,c2)
课后练习与技能训练
二、选择题
练习
4.关于动态扩展类的说法正确的是()
A.Python除了可以在定义类时定义属性和方法外,还可以动态地为已经创建的对象绑定新的属性和方法
B.Python只能在定义类时定义属性和方法,不能动态扩展
C.Python只能动态扩展属性,不能动态扩展方法
D.Python只能动态扩展方法,不能动态扩展属性
课后练习与技能训练
三、简答题
练习
1.下面程序对圆柱体类Cylinder实现动态绑定方法,请将程序填写完整。
from types import MethodType #从types模块导入MethodType方法
class Cylinder:
pass
def SetRadius(self,r):
self.Radius=r
def SetHeight(self,h):
self.Height=h
if __name__=='__main__':
c1=Cylinder()
c2=Cylinder()
#为c1对象绑定SetRadius方法
c1.SetRadius= (SetRadius,c1)
#为Cylinder类绑定SetHeight方法
Cylinder.SetHeight=
c1.SetRadius(10)
c2.SetRadius(20) #c2对象未绑定SetRadius方法,此语句有误
c1.SetHeight(30)
c2.SetHeight(40)
课后练习与技能训练
三、简答题
练习
2.写出下面程序的运行结果。
class Cylinder:
Radius=5
Height=10
def Display(self):
print("圆柱体半径为",self.Radius)
class Circle:
Radius=50
def Display(self):
print("圆半径为",self.Radius)
if __name__=='__main__':
c1=Cylinder()
c2=Circle()
c1.Display()
c2.Display()
$$