一、第一部分
练习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)