一、第一部分
练习1:对象可以直接添加实例
#第一个类对象的测试
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def get_score(self):
print("{0}分数是:{1}".format(self.name,self.age))
s1 = Student("Clichong",18)
s1.get_score()
s1.salary = 100000 #直接添加实例salary与score
s1.score = 41
print(s1.salary)
s2 = Student("Xioaqi",41)
print(s2.age)
练习2:实例对象
#以下两行代码运行得出的结果是相同的
a.say_score()
Student.say_score(a)
print(dir(s2))
print(type(s2))
print(s2.__dict__)
print(isinstance(s2,Student))
练习3:类属性
#第一个类对象的测试
class Student:
company = "sxt" #类属性
pname = "aic"
def __init__(self,name,age):
self.name = name
self.age = age
def get_score(self):
print("{0}分数是:{1}".format(self.name,self.age))
print(Student.company)
print(Student.pname)
练习4:类方法
#第一个类对象的测试
class Student:
company = "sxt" #类属性
pname = "aic"
@classmethod #类方法
def PrintCompany(cls):
print(Student.company)
def __init__(self,name,age):
self.name = name #实例属性
self.age = age
def get_score(self): #实例方法
print("{0}分数是:{1}".format(self.name,self.age))
Student.PrintCompany()
练习5:静态方法
#第一个类对象的测试
class Student:
company = "sxt" #类属性
pname = "aic"
@staticmethod
def reback(n): #静态方法,但是无法实现递归
if n == 0:
return 1
else:
return n
@classmethod #类方法
def PrintCompany(cls):
print(Student.company)
def __init__(self,name,age): #构造函数
self.name = name #实例属性
self.age = age
def get_score(self): #实例方法
print("{0}分数是:{1}".format(self.name,self.age))
Student.PrintCompany()
print(Student.reback(5))
练习6:可调用对象
定义了__call__方法的对象,称为“可调用对象”,即该对象可以像函数一样被调用
#测试可调用方法_call__()
class SalaryAccount:
'''工资计算类'''
def __call__(self, Salary):
print("算工资啦....")
yearSalary = Salary*12
daySalary = Salary//22.5
hourSarlay = Salary//8
monthSalary = Salary
return dict(yearSalary = yearSalary,monthSalary = monthSalary,daySalary = daySalary,hourSarlay = hourSarlay)
def __init__(self,name,salary):
self.name = name
self.salary = salary
def Print(self):
print("hello world")
print(help(SalaryAccount)) #打印出此文档的介绍
s1 = SalaryAccount("aa",2131)
s1.Print()
s2 = SalaryAccount("21",131)
s2.Print()
print(s2(10000))
s3 = SalaryAccount("Clichong",3000)
print(s3.salary)
print(s2.salary)
print(s1.name)
class SalaryAccount:
def __call__(self): #可调用对象设置
return 100
def __init__(self,salary): #构造函数
self.salary = salary
def Print(self): #实例方法
print(self.salary)
s1 = SalaryAccount(1)
s1.Print()
s2 = SalaryAccount(2)
s2.Print()
print(s2()) #调用可调用对象,打印100
练习7:动态的改变函数
#测试可调用方法_call__()
class SalaryAccount:
def __call__(self):
return 100
def __init__(self,salary):
self.salary = salary
def Print(self):
print(self.salary)
def Print01(self):
#要注意,此处要带一个参数,否则会报错,因为SalaryAccount累中的Print函数也是带一个参数的
print("好好学习,天天向上")
s1 = SalaryAccount(1)
s1.Print()
s2 = SalaryAccount(2)
s2.Print()
print(s2())
SalaryAccount.Print = Print01
s2.Print() #要注意,此处不可以加参数,因为本来已经存在一个隐含的参数self
补充:
class Myfunction:
pass
class MyAddfunction:
mynum = None
def __call__(self, num): #使得对象可以像函数一样被调用
self.mynum = num
return self.mynum
def __init__(self,num): #构造函数,需要初始化的时候需要使用这个函数
self.mynum = num
def __add__(self, other): #重载+运算符
if isinstance(other,MyAddfunction):
print("myadd_function...")
return self.mynum*other.mynum
else:
print("不是同类,不能相加")
def __mul__(self, other): #重载*运算符
if isinstance(other,MyAddfunction):
print("mymul_function...")
return self.mynum+other.mynum
else:
print("不是同类,不能相乘")
def mywork(s): #在类之外定义两个方法
print("mywork")
def mygame(s):
print("myganme")
MyAddfunction.work = mywork #动态的增加类方法
MyAddfunction.game = mygame
p = MyAddfunction(20)
p.work() #可以正常进行工作
p.game()
练习8:私有属性
- 测试1
class Clichong:
def __init__(self,name,salary):
self.name = name
self.salary = salary
def Print(self):
print(self.name)
print(self.salary)
a = Clichong("Tom",10000)
a.Print()
print(dir(a))
2. 测试2
class Clichong:
def __init__(self,name,salary):
self.__name = name #定义私有属性
self.__salary = salary #定义私有属性
def Print(self):
pass
# print(self.name)
# print(self.salary)
a = Clichong("Tom",10000)
#a.Print()
print(dir(a))
3. 测试三
class Clichong:
def __init__(self,name,salary):
self.__name = name #定义私有属性
self.__salary = salary #定义私有属性
def Print(self):
print(self.name)
print(self.salary)
a = Clichong("Tom",10000)
a.Print()
print(dir(a))
4. 测试4
class Clichong:
def __init__(self,name,salary):
self.__name = name #定义私有属性
self.__salary = salary #定义私有属性
def Print(self):
print(self._Clichong__name) #由于已经转变为私有属性,改为指定格式才可以打印
print(self._Clichong__salary)
a = Clichong("Tom",10000)
a.Print()
print(dir(a))
练习9:私有办法,私有类变量,私有属性
class Clichong:
__myvar = "今年是2020年" #定义私有类变量
def __init__(self,name,salary):
self.__name = name #定义私有属性
self.__salary = salary #定义私有属性
def Print(self):
print(self._Clichong__name) #由于已经转变为私有属性,改为指定格式才可以打印
print(self._Clichong__salary)
def __myprivate(self): #定义私有方法
print("hello Clichong")
def PrintMyvar(self):
print("__myvar:",Clichong.__myvar) #内部调用私有类变量,不需要写成_Clichong__myvar的形式,只需要Clichong.__myvar便可
a = Clichong("Tom",10000)
#私有属性的测试
a._Clichong__salary = 200000 #可以直接修改室友属性
print("a._Clichong__salary:",a._Clichong__salary) #还可以打印出来
#私有类变量的测试
print("a._Clichong__myvar:",a._Clichong__myvar)
a.PrintMyvar()
a._Clichong__myvar = "今年是2021年" #外部直接调用私有的类变量,需要写成_Clichong__myvar的形式,与私有属性一样,与私有方法也一样
print("a._Clichong__myvar:",a._Clichong__myvar)
a.PrintMyvar()
#打印私有属性测试
a.Print()
print(dir(a))
#使用私有方法测试
# a.__myprivate() #会失败
a._Clichong__myprivate() #成功打印
总结:
- 在外部调用私有属性,私有类变量和私有方法的操作都是一样的,均是增添为_Clichong__myvar = " "的形式,然后直接p._Clichong__myvar直接调用就可以了。
- 在内部调用私有类变量,只需要Clichong.__myvar = “”便可
练习10:property修饰器的使用
#property装饰器的使用
# @property 修饰的属性,如果没有加 setter 方法,则为只读属性。此处修改报错
#@property 主要用于帮助我们处理属性的读操作、写操作。
class Employee:
def __init__(self,name,salary):
self.name = name
self.__salary = salary
@property
def salary(self):
print("salary:",self.__salary)
return self.__salary
@salary.setter
def salary(self,salary):
if(0 < salary < 100000):
self.__salary = salary
else:
print("录入错误")
a = Employee("Clichong",1000)
print(a.salary)
a.salary = -1433
print(a.salary)
练习11:重写object类中的__str__()函数
class Person:
"Class name is Person"
def __init__(self,name):
self.name = name
def __str__(self):
return "Today is 2020/11/15"
a = Person("Clichong")
print(a)
作业1:类方法的小测试
设计一个名为 MyRectangle 的矩形类来表示矩形。这个类包含:
(1) 左上角顶点的坐标:x,y
(2) 宽度和高度:width、height
(3) 构造方法:传入 x,y,width,height。如果(x,y)不传则默认是 0,如果 width
和 height 不传,则默认是 100.
(4) 定义一个 getArea() 计算面积的方法
(5) 定义一个 getPerimeter(),计算周长的方法
(6) 定义一个 draw()方法,使用海龟绘图绘制出这个矩形
import turtle
pen = turtle.Pen()
pen.width(5)
pen.color("blue")
pen.showturtle()
class MyRectangle:
def __init__(self,x = 0,y = 0,width = 100,height = 100):
self.x = x
self.y = y
self.width = width
self.height = height
def getData(self):
print("x:",self.x)
print("y:",self.y)
print("width:",self.width)
print("height:",self.height)
def getArea(self):
area = self.height*self.width
print("are:",area)
def getPerimeter(self):
perimeter = 2*(self.width+self.height)
print("perimeter:",perimeter)
def draw(self):
pen.penup()
pen.goto(self.x,self.y)
pen.pendown()
pen.goto(self.x+self.width,self.y)
pen.goto(self.x+self.width,self.y-self.height)
pen.goto(self.x,self.y-self.height)
pen.goto(self.x,self.y)
pen.penup()
#a = MyRectangle(width = 100,height = 200,x = 20,y = 10)
a = MyRectangle(width = 100,height = 200) #直接命名参数
a.getData()
a.getArea()
a.getPerimeter()
a.draw()
while True:
pass
测试结果:
二、第二部分
练习1:多重继承与多态的实现,super函数的使用
#测试多态的实现
class Animal:
def shout(self):
print("动物叫")
class Dog(Animal):
def shout(self):
print("动物叫,狗也叫")
class Cat(Animal):
def shout(self):
print("动物叫,猫也叫")
class Man(Animal):
def shout(self):
super().shout() #调用父类的shout方法
print("动物叫,人也叫")
class Kid(Dog,Cat,Man): #python语言中额可以一次性继承多个父类
def shout(self):
print("动物叫,小孩叫")
class Child:
def shout(self):
print("小屁孩叫,全都叫")
def DefWhoScout(myobject): #多态的实现
if isinstance(myobject,Animal):
myobject.shout()
else:
print("原来是个小孩叫")
print(Man.mro()) #由于super函数,会打印父类的方法;还会打印自己的方法
print(Dog.mro())
print(Kid.mro()) #验证python中的多重继承
DefWhoScout(Man()) #注意,此处的类对象Man是有括号的Man()
DefWhoScout(Dog()) #注意,此处的类对象Dog是有括号的Dog()
DefWhoScout(Kid())
DefWhoScout(Child()) #因为其没有继承Animal类,故其会执行else语句,而不是自己的shout函数
练习2:重载运算符的简单探讨
#重载运算符的实现
#原本的+运算符的用法
num1 = 10
num2 = 20
result = num1 + num2
print("[+]no change result:",result)
class Myfunction:
pass
class MyAddfunction:
def __init__(self,num):
self.num = num
def __add__(self, other): #重载+运算符
if isinstance(other,MyAddfunction):
return self.num*other.num #[+]的运算规则是相乘
else:
print("不是同类,不能相加")
def __mul__(self, other): #重载*运算符
if isinstance(other, MyAddfunction):
return self.num + other.num # [*]的运算规则是相加
else:
print("不是同类,不能相加")
t0 = Myfunction()
t1 = MyAddfunction(10)
t2 = MyAddfunction(20)
print("t1:",t1.num," t2:",t2.num)
#测试重载后的+运算符
t = t1+t2
print("{0}+{1}={2}".format("t1","t2",t))
#测试重载后的*运算符
t = t1*t2
print("{0}*{1}={2}".format("t1","t2",t))
补充:想法是让类变成一个对象然后使用重载运算符去调用,但是结果失败了。
#重载运算符的实现
class Myfunction:
pass
class MyAddfunction:
mynum = None
def __call__(self, num): #使得对象可以像函数一样被调用
self.mynum = num
return self.mynum
def __init__(self,num): #构造函数,需要初始化的时候需要使用这个函数
self.mynum = num
def __add__(self, other): #重载+运算符
if isinstance(other,MyAddfunction):
print("myadd_function...")
return self.mynum*other.mynum
else:
print("不是同类,不能相加")
def __mul__(self, other): #重载*运算符
if isinstance(other,MyAddfunction):
print("mymul_function...")
return self.mynum+other.mynum
else:
print("不是同类,不能相乘")
'''''''''
t1 = MyAddfunction()
t2 = MyAddfunction()
t = t1(10)+t2(20) #由于运算符是返回之后再相加,所以没有使用重载的功能
print(t)
'''''''''
t1 = MyAddfunction(10)
t2 = MyAddfunction(20)
t = t1 + t2 #使用了重载的功能
print(t)
总结:表明了__call__函数是无法与重载运算符一起使用的。
练习3:浅拷贝与深拷贝的探讨
- 变量的赋值操作
只是形成两个变量,实际还是指向同一个对象。 - 浅拷贝
Python 拷贝一般都是浅拷贝。拷贝时,对象包含的子对象内容不拷贝。因此,源对象
和拷贝对象会引用同一个子对象。 - 深拷贝
使用 copy 模块的 deepcopy 函数,递归拷贝对象中包含的子对象。源对象和拷贝对象
所有的子对象也不同。
总结:
复制操作没有拷贝任何的内容,只是进行地质的赋值也就是指向了同一个的内容。而浅拷贝是拷贝了对象,但是对象的子对象内容不拷贝,只是指向了相同的内容。而深拷贝既拷贝了对象,还拷贝了对象的子对象。
import copy
class MobilePhone:
def __init__(self,cpu,screen):
self.cpu = cpu
self.screen = screen
class CPU:
def calculate(self):
print("CPU对象",self)
class Screen:
def show(self):
print("屏幕对象",self)
c = CPU()
s = Screen()
m = MobilePhone(c,s)
m.cpu.calculate()
m.screen.show()
#赋值操作
p1 = m
print("p1:",p1," m:",m) #对象地址没有改变
p1.cpu.calculate() #对象的子对象地址也没有改变,说明还是同一个地址
p1.screen.show()
#浅拷贝操作
p2 = copy.copy(m)
print("p2:",p2," m:",m) #对象地址发生变化,说明拷贝了一个对象
p2.cpu.calculate() #对象的子对象没有改变,说明还是指向统一而个地址
p2.screen.show()
#深拷贝操作
p3 = copy.deepcopy(m)
print("p3:",p3," m:",m) #对象地址改变
p3.cpu.calculate() #子对象的地址也改变,说明是完全拷贝了一个新的
p3.screen.show()
练习4:工厂模式简单例子
工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进
行统一的管理和控制。
# 工程设计模式
class CarFactroy:
def createCar(self,brand):
if brand == "Benz":
return Benz()
elif brand == "BWM":
return BMW()
elif brand == "BYD":
return BYD()
else:
return "Error! Unknowd Brand!"
class Benz:
pass
class BMW:
pass
class BYD:
pass
factory = CarFactroy()
c1 = factory.createCar("Benz")
c2 = factory.createCar("BYD")
print(c1)
print(c2)
练习5:单例模式简单例子
单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大的降低开销。
单例模式有多种实现的方式,我们这里推荐重写__new__()的方法。new()方法: 用于创建对象,但我们一般无需重定义该方法。
#单例模式的其中一种实现方法
class MySingleton:
__obj = None
__init_flag = True #设置一个标志,指允许构造一次
def __new__(cls, *args, **kwargs):
if cls.__obj == None: #如果是空对象,则构建一个对象
cls.__obj = object.__new__(cls) #创建一个新对象
return cls.__obj
def __init__(self,name): #构造函数,希望只构造一次,所以再定义一个标志
if MySingleton.__init_flag:
print("init...")
self.name = name
MySingleton.__init_flag = False #之后永远不会再定义第二个标志
#可以看出,两个是同一个对象
a = MySingleton("Clichong")
print(a)
b = MySingleton("Kacura")
print(b)
class MySingle:
object_flag = None
def __new__(cls, *args, **kwargs):
if cls.object_flag == None:
cls.object_flag = object.__new__(cls)
return cls.object_flag
def __init__(self,number): #不对构造函数作出限定,则其会不断地进行构造然后覆盖,不符合意思
self.number = number
p3 = MySingle(10)
p4 = MySingle(20)
print(p3.number)
print(p4.number)
ps:
· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访 问这些成员。 ·
·xxx:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外 部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)
作业2:组合的使用
定义发动机类 Motor、底盘类 Chassis、座椅类 Seat,车辆外壳类 Shell,并使用组合
关系定义汽车类。其他要求如下:
定义汽车的 run()方法,里面需要调用 Motor 类的 work()方法,也需要调用座椅
类 Seat 的 work()方法,也需要调用底盘类 Chassis 的 work()方法。
class Motor:
def work(self):
print("In Motor Work...")
class Chassis:
def work(self):
print("In Chassis Work...")
class Seat:
def work(self):
print("In Seat Work...")
class Shell:
def work(self):
print("In Shell Work...")
class Car:
def __init__(self,motor,chassis,seat,shell):
self.motor = motor
self.chassis = chassis
self.seat = seat
self.shell = shell
def run(self):
self.motor.work()
self.shell.work()
self.seat.work()
self.chassis.work()
Mo = Motor()
Sh = Shell()
Se = Seat()
Ch = Chassis()
mycar = Car(Mo,Sh,Se,Ch)
mycar.run()
作业3:使用工厂模式、单例模式实现如下需求
(1) 电脑工厂类 ComputerFactory 用于生产电脑 Computer。工厂类使用单例模式,
也就是说只能有一个工厂对象。
(2) 工厂类中可以生产各种品牌的电脑:联想、华硕、神舟
(3) 各种品牌的电脑使用继承实现:
(4) 父类是 Computer 类,定义了 calculate 方法
(5) 各品牌电脑类需要重写父类的 calculate 方法
class ComputerFactory:
__single_flag = None
def __new__(cls, *args, **kwargs): #设置成单例模式
if cls.__single_flag == None:
cls.__single_flag = object.__new__(cls)
return cls.__single_flag
def ProtectComputer(self,brand): #工程模式,没有写构造函数
if brand == "联想":
return Lenovo()
elif brand == "华硕":
return HuaShuo()
elif brand == "神舟":
return ShenZhou()
else:
print("Error! Unknowed Brand!!!")
class Computer: #父类
Flag = 111200
def calculate(self):
pass
#定义三个子类继承父类
class ShenZhou(Computer):
def calculate(self):
print("Produce Shenzhou computer...:",self.Flag)
class Lenovo(Computer):
def calculate(self):
print("Produce Lenovo computer...:",self.Flag)
class HuaShuo(Computer):
def calculate(self):
print("Produce Huashuo computer...:",self.Flag)
#定义两个对象来测试单例模式
myfacture = ComputerFactory()
myotherfacture = ComputerFactory()
print(myfacture)
print(myotherfacture)
#生产不同的电脑测试工厂模式
c1 = myfacture.ProtectComputer("联想") #更换了对象也是无所谓的,因为是同一个对象
c2 = myotherfacture.ProtectComputer("华硕")
c3 = myfacture.ProtectComputer("神舟")
#调用各自改写父类的方法
c1.calculate()
c2.calculate()
c3.calculate()
练习4:property 设置属性的 get 和 set 方法与重载的混合使用
定义一个 Employee 雇员类,要求如下:
(1) 属性有:id、name、salary
(2) 运算符重载+:实现两个对象相加时,默认返回他们的薪水和
(3) 构造方法要求:输入 name、salary,不输入 id。id 采用自增的方式,从 1000 开
始自增,第一个新增对象是 1001,第二个新增对象是 1002。
(4) 根据 salary 属性,使用@property 设置属性的 get 和 set 方法。set 方法要求输
入:1000-50000 范围的数字。
class Employee:
employee_id = 1000
def __init__(self,name,salary): #构造函数
self.name = name
self.__salary = salary
self.id = self.employee_id
Employee.employee_id += 1 #实现id自增
def __add__(self, other): #重载+运算符,对象相加返回的是工资相加
if isinstance(other,Employee):
return self.__salary+other.__salary
else:
print("Error! 不是同一种类型")
@property #将函数salary修饰为一个对象,返回的工资金额,也就是赋值与工资保存
def salary(self):
return self.__salary
@salary.setter #限制工资的录入范围
def salary(self,salary):
if(1000 < salary < 50000):
self.__salary = salary
else:
print("Error! Salery Info Error!!!")
#定义了3个对象
emp1 = Employee("Clichong",35000)
emp2 = Employee("Kacura",15000)
emp3 = Employee("Lawrence",25000)
#id自增测试
print("id = {0} name = {1} salary = {2}".format(emp1.id,emp1.name,emp1.salary))
print("id = {0} name = {1} salary = {2}".format(emp2.id,emp2.name,emp2.salary))
print("id = {0} name = {1} salary = {2}".format(emp3.id,emp3.name,emp3.salary))
#重载了+运算符测试
emp = emp1+emp2
print("emp1+emp2=",emp)
emp = emp2+emp3
print("emp2+emp3=",emp)
#property 设置属性的 get 和 set 方法测试
print(dir(emp1))
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)
emp1.salary = 10500 #property修饰器使得salary函数变成了一个对象去使用
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)
emp1.salary = -1000 #会报错,因为超出了范围
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)
emp1.salary = 45000 #emp1的salary又重新被修改为45000
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)