智泊Python–Day13 Day13 是面向对象的深水区,把 Day12 的「类与对象」往工程化方向推进。这一天的线索是封装的强化 → 属性的受控访问 → 方法的分类 → 继承与多态 → 特殊机制 。重点掌握四个:私有属性/方法 (__ 前缀做信息隐藏)、**property(把方法当属性用、还能加校验)、 类方法 / 静态方法(不建对象就能调用、省内存)、以及 继承 / 重写 / 多继承**(代码复用与行为定制)。最后用运算符重载和一套「学生」继承体系作业收尾。
1.私有属性和私有方法 在属性 / 方法名前加 双下划线 __ 就是私有成员,只能在当前类内部访问 ;类外直接访问会报错。Python 的「私有」是命名改写实现的——外部其实可通过 _类名__属性 访问到,但强烈不建议,会破坏封装。公有成员则类内外都能用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Girl : def __init__ (self,name,age ): self.name = name self.age = age def dance (self ): print (f"{self.name} 今年{self.age} 岁,会跳舞了" )class Boy : def __init__ (self,name,age ): self.__name = name self.__age = age def dance (self ): print (f"{self.__name} 今年{self.__age} 岁,会跳舞了" ) self.__run() def __run (self ): print (f"{self.__name} 正在跑" ) g1 = Girl("刘亦菲" ,18 ) g1.dance()print (g1.name)print (g1.age) b1 = Boy("吴彦祖" ,18 ) b1.dance()print (b1._Boy__age)
2.property属性 @property 让一个方法像属性一样被读取 (不用加 ()),它本质是 getter。规则:必须有返回值、不能有参数、定义在类里。搭配 @属性名.setter 还能写 setter 来赋值并做校验 (比如年龄不能负数)。没有 setter 时该属性只读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Person : def __init__ (self, name, age ): self.name = name self.__age = age @property def age (self ): return self.__age @age.setter def age (self, new_age ): if new_age >= 0 : self.__age = new_age p = Person('张三' , 18 )print (p._Person__age)print (p.age) p.age = 33 print (p.age)print (p._Person__age)
3.类方法和静态方法 方法按归属分三类:
对象方法 (带 self):最常见,操作对象
类方法 @classmethod(带 cls):可用 类名.方法() 直接调,不创建对象 ,省内存;能访问类属性 / 类方法,但访问不了对象属性
静态方法 @staticmethod(无 self 也无 cls):纯工具函数,和类 / 对象都松耦合,推荐用 类名.方法() 调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Person : class_name = "人" def __init__ (self, name, age ): self.name = name self.__age = age def run (self ): print (f"作为一个{Person.class_name} ,{self.name} 正在跑,跑完后就会{self.__sleep()} " ) def __sleep (self ): return "睡觉" @classmethod def eat (cls ): print (cls.class_name) print ("吃饭" ) return "吃饭" @staticmethod def game (): print ("玩游戏" ) return "玩游戏" p1 = Person("张三" , 18 ) p1.run()print ("-----------------" ) Person.eat()print ("-----------------" ) Person.game()print ("-----------------" )
4.练习 用一个 Number 工具类把类方法 / 静态方法练熟:add_num/sub_num/mul_num/div_num 是类方法,直接操作类属性 num;add/sub 是静态方法,纯粹的二元运算。注意类方法通过 cls.num 读写类属性,静态方法不依赖任何状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Number : num = 10 @classmethod def add_num (cls ): return cls.num + 1 @classmethod def sub_num (cls ): return cls.num - 1 @classmethod def mul_num (cls,n ): return cls.num * n @classmethod def div_num (cls,n ): return cls.num / n @staticmethod def add (x,y ): return x + y @staticmethod def sub (x,y ): return x - y n = Number()print (n.add_num)print (n.sub_num)print (n.mul_num(2 ))print (n.div_num(2 ))print (Number.add(1 ,2 ))print (Number.sub(1 ,2 ))
5.继承 面向对象的四大特征:封装、继承、多态、抽象 。继承让子类直接获得父类的属性和方法,实现代码复用。单继承(一个父类)最常见:子类 __init__ 里用 super().__init__(...) 调父类构造来初始化共有部分,再追加自己的属性。Dog/Cat 都继承自 Animal 就是典型场景——公共的 name/age/run/sleep 提到父类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 class IPad : def __init__ (self, color, price ): self.color = color self.price = price def movie (self ): print ("看电影" )class IPhone (IPad ): def __init__ (self, color, price, size ): super ().__init__(color, price) self.model = "iPhone" self.size = size def call (self ): print ("打电话" ) phone16 = IPhone("白色" , 9999 , "6" )print (phone16.color)print (phone16.price)print (phone16.model)print (phone16.size) phone16.call() phone16.movie()print ("-----------------" )class Animal : def __init__ (self, name, age ): self.name = name self.age = age def run (self ): print (f"{self.name} 正在跑" ) def sleep (self ): print (f"{self.name} 正在睡觉" )class Dog (Animal ): def __init__ (self, name, age ): super ().__init__(name, age) self.kind = "狗" def bark (self ): print (f"{self.name} 正在汪汪叫" )class Cat (Animal ): def __init__ (self, name, age ): super ().__init__(name, age) self.kind = "猫" def meow (self ): print (f"{self.name} 正在喵喵叫" ) Dog1 = Dog("旺财" , 1 ) Dog1.run() Dog1.sleep() Dog1.bark()print ("-----------------" ) Cat1 = Cat("小白" , 1 ) Cat1.run() Cat1.sleep() Cat1.meow()
6.多继承 多继承是「一个子类继承多个父类」,把多个父类的特性合并。Python 用 MRO(方法解析顺序) 决定属性 / 方法按什么顺序查找,可用 类名.__mro__ 查看继承链。下面的 Daughter(Father, Mother) 通过 super() 链式调用分别初始化父亲给的 name 和母亲给的 sex。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Father : def __init__ (self, name ): self.name = name def smoke (self ): return "吸烟" class Mother : def __init__ (self, sex ): self.sex = sex def cook (self ): return "做饭" class Daughter (Father, Mother): def __init__ (self, name, age, sex ): super (Daughter, self).__init__(name) super (Father, self).__init__(sex) self.age = age self.kind = "女儿" def play (self ): return "正在玩" d1 = Daughter("小红" , 18 , "女" )print (d1.name)print (d1.age)print (d1.sex)print (d1.kind)print (d1.play())print (d1.smoke())print (d1.cook())print (Daughter.__mro__)
7.重写 重写发生在继承基础上:子类和父类有同名方法 时,子类的方法会覆盖 父类。这正是「多态」的体现——同样是 run(),父类返回「正在跑」、子类 Boy 返回「正在跑快」。外部调用时看对象的实际类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Person : def __init__ (self, name, age ): self.name = name self.age = age def run (self ): return "正在跑" class Boy (Person ): def __init__ (self, name, age ): super ().__init__(name, age) def run (self ): return "正在跑快" b1 = Boy("小明" , 18 )print (b1.run())print (b1.name)print (b1.age)print ("=" *20 ) b2 = Person("小红" , 18 )print (b2.run())print (b2.name)print (b2.age)
8.私有属性不能继承 再强调一遍封装边界:父类的私有属性(如 __age)只在父类内部可见,子类访问不到 ——即使通过继承拿到了父类的方法,方法内部能用自己的 __age,但子类自己无法直接 对象.__age。非私有的 name、sex、方法都能正常继承使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Person : def __init__ (self, name, age ): self.name = name self.__age = age def eat (self ): return "正在吃" class Boy (Person ): def __init__ (self, name, age, sex ): super ().__init__(name, age) self.sex = sex def sleep (self ): return "正在睡" b1 = Boy("小明" , 18 , "男" )print (b1.name)print (b1.sex)print (b1.eat())print (b1.sleep())
9.特殊属性和运算符重载 (本节了解即可)Python 里大量以双下划线包裹的成员叫「特殊属性 / 魔法方法」,通常由解释器自动调用。__slots__ 可限制实例能有哪些属性;__class__ / __dict__ 用于自省;__str__ / __repr__ 控制打印样式;__add__ 等则实现运算符重载 ——让自定义对象支持 +、直接 print 等原生语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 class Person : __slots__ = ["name" , "age" , "sex" ] def __init__ (self, name, age ): self.name = name self.age = age p = Person("张三" , 18 ) p.sex = "男" print (p.name, p.age, p.sex)class Dog : def __init__ (self, name, age ): self.name = name self.age = age d = Dog("旺财" , 1 )print (d)print ("=" *50 )print (d.__class__) print (Dog.__class__) print (d.__dict__) print ("=" *50 ) d2 = Dog(**{"name" : "旺财" , "age" : 1 })print (d2) d2 = Dog(name="旺财" , age=1 ) print (d2)print ("=" *50 )class Number : def __init__ (self, num ): self.num = num def __add__ (self, other ): return Number(self.num + other.num) def __str__ (self ): return f"--{self.num} --" def __repr__ (self ): print ("repr__方法" ) return f"**{self.num} **" n1 = Number(10 ) n2 = Number(20 )print (n1 + n2)print (n1)print ([n1, n2])
10.作业 综合作业:用封装 + 继承 + 重写 实现「学生」体系。student 作为父类,带着 name/id/age/sex 和 learn();Pupil(小学生)、Middle_student(中学生)、College(大学生)各自继承并**重写 learn()**,打印不同的学习内容。这个结构正是 Day12 封装与本节继承 / 多态的完整串联。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class student : def __init__ (self, name, id , age, sex ): self.name = name self.id = id self.age = age self.sex = sex def learn (self ): print (f"{self.name} 正在学习" )class Pupil (student ): def __init__ (self, name, id , age, sex ): super ().__init__(name, id , age, sex) def learn (self ): print (f"{self.name} 正在学习语文 数学 英语" )class Middle_student (student ): def __init__ (self, name, id , age, sex ): super ().__init__(name, id , age, sex) def learn (self ): print (f"{self.name} 正在学习语数外 生物化 史地政" )class College (student ): def __init__ (self, name, id , age, sex ): super ().__init__(name, id , age, sex) def learn (self ): print (f"{self.name} 正在逃课中.." )