Python快速学习——第10章:类和对象
第十章类和对象10.1 什么是类 类就像一个制造小盒子的模具你可以用这个模具制造出很多相似的小盒子对象。每个小盒子都有自己的特性属性和行为方法它们都遵循同一个设计蓝图。 我们可以理解为把数据和函数包在一起。# 定义一个简单的类classStudent:学生类# 数据def__init__(self,name,score):self.namename# 属性姓名self.scorescore# 属性成绩# 方法函数defprint_info(self):方法打印学生信息print(f学生姓名{self.name}成绩{self.score})10.2 类和对象的基本概念10.2.1 类与对象的关系类是抽象的蓝图定义了一组对象共有的属性和方法对象是类的实例具有类所定义的属性和方法# 使用类创建对象student1Student(张三,90)student2Student(李四,85)# 每个对象都有自己的属性print(student1.name)# 张三print(student2.name)# 李四# 调用对象的方法student1.print_info()# 学生姓名张三成绩90student2.print_info()# 学生姓名李四成绩8510.2.2 类的组成一个类通常包含属性对象的特征或数据方法对象的行为或功能构造函数初始化对象的方法10.3 定义类10.3.1 基本语法使用class关键字定义类classClassName:类的文档字符串def__init__(self,参数1,参数2,...):# 初始化方法用于设置对象的初始状态self.属性1参数1self.属性2参数2# ...def方法1(self,参数...):# 方法定义pass10.3.2 初始化方法__init____init__是一个特殊的方法在创建对象时自动调用用于初始化对象的属性classDog:狗类def__init__(self,name,age):self.namename self.ageage self.breed未知# 设置默认值# 创建对象时必须提供__init__中必需的参数my_dogDog(旺财,3)self参数是对当前对象的引用在类的方法中必须作为第一个参数通过self可以访问对象的属性和其他方法在调用方法时不需要手动传递selfPython会自动处理10.4 属性和方法10.4.1 实例属性实例属性属于每个对象实例每个对象都有自己的属性副本classCar:汽车类def__init__(self,brand,color):self.brandbrand# 实例属性self.colorcolor# 实例属性car1Car(丰田,白色)car2Car(本田,黑色)print(car1.brand)# 丰田print(car2.brand)# 本田10.4.2 实例方法实例方法是在类中定义的函数第一个参数是self用于定义对象的行为classCar:def__init__(self,brand,color):self.brandbrand self.colorcolor self.speed0# 初始速度defaccelerate(self,increment):加速方法self.speedincrementprint(f{self.brand}车加速到{self.speed}km/h)defbrake(self,decrement):刹车方法self.speed-decrementifself.speed0:self.speed0print(f{self.brand}车减速到{self.speed}km/h)# 使用实例方法my_carCar(宝马,蓝色)my_car.accelerate(20)# 宝马车加速到20km/hmy_car.brake(5)# 宝马车减速到15km/h10.4.3 类属性类属性属于类本身所有对象实例共享同一个类属性classCar:# 类属性wheels4# 所有汽车都有4个轮子def__init__(self,brand,color):self.brandbrand# 实例属性self.colorcolor# 实例属性# 通过类名访问类属性print(Car.wheels)# 4# 通过对象实例也可以访问类属性my_carCar(奥迪,红色)print(my_car.wheels)# 4# 修改类属性会影响所有实例Car.wheels6print(my_car.wheels)# 610.4.4 类方法类方法使用classmethod装饰器定义第一个参数是cls表示类本身classCar:wheels4count0# 记录创建的汽车数量def__init__(self,brand,color):self.brandbrand self.colorcolor Car.count1# 每次创建对象时计数增加classmethoddefget_count(cls):类方法获取汽车数量returncls.countclassmethoddefset_wheels(cls,number):类方法设置轮子数量cls.wheelsnumber# 使用类方法print(Car.get_count())# 0还没有创建对象car1Car(奔驰,黑色)car2Car(大众,白色)print(Car.get_count())# 2Car.set_wheels(6)print(car1.wheels)# 610.4.5 静态方法静态方法使用staticmethod装饰器定义不需要self或cls参数classCar:def__init__(self,brand,color):self.brandbrand self.colorcolorstaticmethoddefis_valid_brand(brand):静态方法检查品牌是否有效valid_brands[丰田,本田,宝马,奔驰,奥迪]returnbrandinvalid_brands# 使用静态方法print(Car.is_valid_brand(宝马))# Trueprint(Car.is_valid_brand(比亚迪))# False# 也可以通过对象调用my_carCar(宝马,蓝色)print(my_car.is_valid_brand(丰田))# True10.5 封装封装是将数据属性和行为方法包装在一起并控制对内部数据的访问。10.5.1 访问控制在Python中使用命名约定来控制访问公有属性和方法正常命名如name、print_info()受保护的属性和方法以单个下划线开头如_protected_var私有的属性和方法以双下划线开头如__private_varclassBankAccount:银行账户类def__init__(self,account_holder,balance):self.account_holderaccount_holder# 公有属性self._account_number123456789# 受保护属性约定上不直接访问self.__balancebalance# 私有属性无法直接访问# 公有方法defget_balance(self):获取余额公有方法returnself.__balancedefdeposit(self,amount):存款ifamount0:self.__balanceamountreturnTruereturnFalsedefwithdraw(self,amount):取款if0amountself.__balance:self.__balance-amountreturnTruereturnFalse# 使用封装accountBankAccount(张三,1000)print(account.account_holder)# 张三可以访问公有属性# print(account.__balance) # 错误无法直接访问私有属性print(account.get_balance())# 1000通过公有方法访问私有属性account.deposit(500)print(account.get_balance())# 1500account.withdraw(200)print(account.get_balance())# 130010.5.2 属性装饰器使用property装饰器可以创建只读属性或者定义getter、setter方法classCircle:圆类def__init__(self,radius):self._radiusradiuspropertydefradius(self):radius属性的getter方法returnself._radiusradius.setterdefradius(self,value):radius属性的setter方法ifvalue0:self._radiusvalueelse:raiseValueError(半径不能为负)propertydefarea(self):计算面积只读属性return3.14159*self._radius**2propertydefcircumference(self):计算周长只读属性return2*3.14159*self._radius# 使用属性装饰器circleCircle(5)print(circle.radius)# 5调用getter方法circle.radius10# 调用setter方法print(circle.radius)# 10print(circle.area)# 314.159只读属性print(circle.circumference)# 62.8318只读属性# circle.radius -5 # 会抛出ValueError10.6 继承继承允许我们定义一个类它继承另一个类的属性和方法。10.6.1 基本继承# 父类基类classAnimal:动物类def__init__(self,name,age):self.namename self.ageagedefeat(self):print(f{self.name}正在吃东西)defsleep(self):print(f{self.name}正在睡觉)# 子类派生类classDog(Animal):狗类继承自动物类def__init__(self,name,age,breed):# 调用父类的初始化方法super().__init__(name,age)self.breedbreed# 子类特有的属性# 子类特有的方法defbark(self):print(f{self.name}在汪汪叫)# 重写父类的方法defeat(self):print(f{self.name}正在吃狗粮)# 使用继承my_dogDog(旺财,3,金毛)# 调用继承的方法my_dog.eat()# 旺财正在吃狗粮重写后的方法my_dog.sleep()# 旺财正在睡觉继承的方法# 调用子类特有的方法my_dog.bark()# 旺财在汪汪叫print(my_dog.breed)# 金毛子类特有的属性10.6.2 多重继承一个类可以继承多个父类classFlyable:可飞行的类deffly(self):print(正在飞行)classSwimmable:可游泳的类defswim(self):print(正在游泳)classDuck(Flyable,Swimmable):鸭子类继承自Flyable和Swimmabledef__init__(self,name):self.namenamedefquack(self):print(f{self.name}在嘎嘎叫)# 使用多重继承duckDuck(唐老鸭)duck.quack()# 唐老鸭在嘎嘎叫duck.fly()# 正在飞行duck.swim()# 正在游泳10.6.3 方法解析顺序当使用多重继承时Python按照方法解析顺序来查找方法classA:deftest(self):print(A)classB(A):deftest(self):print(B)classC(A):deftest(self):print(C)classD(B,C):pass# 查看MROprint(D.__mro__)dD()d.test()# 输出B按照MRO顺序查找10.7 多态多态是指不同类的对象对同一消息方法调用做出不同的响应classAnimal:defspeak(self):passclassDog(Animal):defspeak(self):return汪汪classCat(Animal):defspeak(self):return喵喵classCow(Animal):defspeak(self):return哞哞# 多态的例子defanimal_speak(animal):print(animal.speak())# 传入不同的对象调用相同的方法得到不同的结果dogDog()catCat()cowCow()animal_speak(dog)# 汪汪animal_speak(cat)# 喵喵animal_speak(cow)# 哞哞10.8 特殊方法魔术方法特殊方法以双下划线开头和结尾用于实现类的特定行为10.8.1 常见特殊方法classBook:图书类def__init__(self,title,author,pages):self.titletitle self.authorauthor self.pagespages# 字符串表示def__str__(self):returnf《{self.title}》 by{self.author}def__repr__(self):returnfBook({self.title}, {self.author},{self.pages})# 长度def__len__(self):returnself.pages# 比较def__eq__(self,other):ifisinstance(other,Book):returnself.titleother.titleandself.authorother.authorreturnFalsedef__lt__(self,other):小于比较按页数比较ifisinstance(other,Book):returnself.pagesother.pagesreturnNotImplemented# 使用特殊方法book1Book(Python编程,John,300)book2Book(算法导论,Tom,500)print(book1)# 《Python编程》 by John调用__str__print(repr(book1))# Book(Python编程, John, 300)调用__repr__print(len(book1))# 300调用__len__print(book1book2)# False调用__eq__print(book1book2)# True调用__lt__10.8.2 算术运算特殊方法classVector:向量类def__init__(self,x,y):self.xx self.yydef__add__(self,other):向量加法ifisinstance(other,Vector):returnVector(self.xother.x,self.yother.y)returnNotImplementeddef__sub__(self,other):向量减法ifisinstance(other,Vector):returnVector(self.x-other.x,self.y-other.y)returnNotImplementeddef__mul__(self,scalar):向量数乘ifisinstance(scalar,(int,float)):returnVector(self.x*scalar,self.y*scalar)returnNotImplementeddef__str__(self):returnfVector({self.x},{self.y})# 使用算术运算特殊方法v1Vector(2,3)v2Vector(1,4)v3v1v2# 向量加法print(v3)# Vector(3, 7)v4v1-v2# 向量减法print(v4)# Vector(1, -1)v5v1*3# 向量数乘print(v5)# Vector(6, 9)本章笔记类是创建对象的蓝图定义了对象的属性和方法。使用class关键字定义类使用__init__方法初始化对象。类包含实例属性、实例方法、类属性和类方法。封装通过访问控制保护对象内部数据。继承允许子类继承父类的属性和方法并可以重写或扩展。多态允许不同类的对象对同一方法调用做出不同响应。特殊方法魔术方法用于实现类的特定行为。面向对象编程使代码更加模块化、可重用和易于维护。