Python3 面向对象:把代码组织得像现实世界一样
我是陈默,一个正拼命上岸的码农。
你有没有想过,为什么现实世界这么好理解?
因为一切都是"对象"。狗有名字、有品种、会叫。车有品牌、有颜色、会跑。每个对象都有自己的属性和行为。
面向对象编程就是把这种思维搬进代码里。
今天我们用一个实际的例子,把 Python 面向对象的核心概念一次性讲清楚。
1. 类和对象:图纸和产品
类是图纸,对象是按图纸造出来的产品。
定义一个类
classDog:def__init__(self, name, breed): self.name = name # 属性:名字 self.breed = breed # 属性:品种defbark(self): print(f"{self.name}:汪汪!")definfo(self): print(f"我是{self.name},品种是{self.breed}")
创建对象
dog1 = Dog("旺财", "柴犬")dog2 = Dog("来福", "金毛")dog1.info() # 输出: 我是旺财,品种是柴犬dog2.info() # 输出: 我是来福,品种是金毛dog1.bark() # 输出: 旺财:汪汪!dog2.bark() # 输出: 来福:汪汪!
同一张图纸,不同的产品。每个对象有自己的数据,共享相同的方法。
__init__ 和 self
__init__ 是初始化方法,创建对象时自动调用
# 这两行做的事情一样dog1 = Dog("旺财", "柴犬")# Python 内部大概是这样:# dog1 = Dog.__new__(Dog)# Dog.__init__(dog1, "旺财", "柴犬")# self 就是 dog1
self 必须写,但调用的时候不用传。Python 自动帮你传。
2. 属性:对象的数据
实例属性:每个对象独有
classStudent:def__init__(self, name, score): self.name = name self.score = scores1 = Student("陈默", 85)s2 = Student("小明", 92)print(s1.name) # 输出: 陈默print(s2.name) # 输出: 小明
类属性:所有对象共享
classStudent: school = "Python 大学"# 类属性,所有学生共享 count = 0def__init__(self, name, score): self.name = name self.score = score Student.count += 1# 每创建一个学生,计数加1s1 = Student("陈默", 85)s2 = Student("小明", 92)print(s1.school) # 输出: Python 大学print(s2.school) # 输出: Python 大学print(Student.count) # 输出: 2
实例属性是"我的",类属性是"大家的"。
3. 方法:对象的行为
实例方法
最普通的方法,第一个参数是 self:
classCircle:def__init__(self, radius): self.radius = radiusdefarea(self):return3.14 * self.radius ** 2defperimeter(self):return2 * 3.14 * self.radiusc = Circle(5)print(c.area()) # 输出: 78.5print(c.perimeter()) # 输出: 31.400000000000002
__str__:打印对象时显示什么
classStudent:def__init__(self, name, score): self.name = name self.score = scoredef__str__(self):returnf"{self.name}({self.score}分)"s = Student("陈默", 85)print(s) # 输出: 陈默(85分)
不加 __str__,print 输出的是 <__main__.Student object at 0x...>,没人看得懂。
4. 继承:孩子继承父母的基因
子类可以继承父类的属性和方法,还能扩展自己的。
基本继承
classAnimal:def__init__(self, name): self.name = namedefeat(self): print(f"{self.name}在吃东西")defsleep(self): print(f"{self.name}在睡觉")# Dog 继承 AnimalclassDog(Animal):defbark(self): print(f"{self.name}:汪汪!")# Cat 继承 AnimalclassCat(Animal):defmeow(self): print(f"{self.name}:喵喵~")dog = Dog("旺财")cat = Cat("小花")dog.eat() # 输出: 旺财在吃东西(继承来的)dog.bark() # 输出: 旺财:汪汪!(自己的)cat.eat() # 输出: 小花在吃东西(继承来的)cat.meow() # 输出: 小花:喵喵~(自己的)
Dog 和 Cat 自动拥有 eat() 和 sleep(),不用重写。
方法重写(Override)
子类可以覆盖父类的方法:
classAnimal:defspeak(self): print("...")classDog(Animal):defspeak(self): print("汪汪!")classCat(Animal):defspeak(self): print("喵喵~")animals = [Dog(), Cat()]for a in animals: a.speak()# 输出:# 汪汪!# 喵喵~
同一个方法,不同的表现。这就是多态。
super():调用父类的方法
classStudent:def__init__(self, name, score): self.name = name self.score = scoreclassGraduateStudent(Student):def__init__(self, name, score, research): super().__init__(name, score) # 调用父类的 __init__ self.research = research # 添加自己的属性definfo(self): print(f"{self.name}:{self.score}分,研究方向:{self.research}")gs = GraduateStudent("陈默", 92, "人工智能")gs.info() # 输出: 陈默:92分,研究方向:人工智能
super() 让你不用重复写父类的初始化逻辑。
5. 封装:把细节藏起来
私有属性
用双下划线 __ 开头的属性,外面不能直接访问:
classBankAccount:def__init__(self, owner, balance): self.owner = owner self.__balance = balance # 私有属性defdeposit(self, amount):if amount > 0: self.__balance += amount print(f"存入{amount}元,余额{self.__balance}元")defwithdraw(self, amount):if amount > self.__balance: print("余额不足")elif amount > 0: self.__balance -= amount print(f"取出{amount}元,余额{self.__balance}元")defget_balance(self):return self.__balanceaccount = BankAccount("陈默", 1000)account.deposit(500) # 输出: 存入500元,余额1500元account.withdraw(200) # 输出: 取出200元,余额1300元# 不能直接改余额# account.__balance = 999999 # 不管用print(account.get_balance()) # 输出: 1300
封装的核心:数据只能通过方法修改,防止外部乱改。
用 property 更优雅
classStudent:def__init__(self, name, score): self.name = name self.__score = score @propertydefscore(self):return self.__score @score.setterdefscore(self, value):ifnot0 <= value <= 100:raise ValueError("分数必须在0-100之间") self.__score = values = Student("陈默", 85)print(s.score) # 输出: 85(像属性一样访问)s.score = 92# 调用 setter,带验证print(s.score) # 输出: 92s.score = 150# 报错!ValueError: 分数必须在0-100之间
@property 让方法用起来像属性,但背后有验证逻辑。
6. 类方法和静态方法
类方法:操作类级别的数据
classStudent: school = "Python 大学" count = 0def__init__(self, name): self.name = name Student.count += 1 @classmethoddefget_count(cls):return cls.count @classmethoddefchange_school(cls, new_name): cls.school = new_names1 = Student("陈默")s2 = Student("小明")print(Student.get_count()) # 输出: 2Student.change_school("Java 大学")print(Student.school) # 输出: Java 大学
静态方法:跟类和对象都没关系的工具
classMathTools: @staticmethoddefadd(a, b):return a + b @staticmethoddefis_even(n):return n % 2 == 0print(MathTools.add(3, 5)) # 输出: 8print(MathTools.is_even(4)) # 输出: True
三种方法怎么选?
- 需要访问类级别的数据 → 类方法(
@classmethod) - 跟类和实例都没关系 → 静态方法(
@staticmethod)
7. 魔术方法:让对象更像内置类型
classScoreList:def__init__(self, scores): self.scores = scoresdef__len__(self):return len(self.scores)def__getitem__(self, index):return self.scores[index]def__contains__(self, item):return item in self.scoresdef__str__(self):returnf"成绩列表:{self.scores}"def__add__(self, other):return ScoreList(self.scores + other.scores)scores = ScoreList([85, 92, 78])print(len(scores)) # 输出: 3print(scores[0]) # 输出: 85print(92in scores) # 输出: Trueprint(scores) # 输出: 成绩列表:[85, 92, 78]combined = scores + ScoreList([90, 88])print(combined) # 输出: 成绩列表:[85, 92, 78, 90, 88]
魔术方法让你的自定义对象用起来像列表、像数字、像字符串。
8. 实战:一个完整的类
classTodoList:"""待办事项管理器"""def__init__(self, owner): self.owner = owner self.__todos = []defadd(self, task): self.__todos.append({"task": task, "done": False}) print(f"添加:{task}")defcomplete(self, index):if0 <= index < len(self.__todos): self.__todos[index]["done"] = True print(f"完成:{self.__todos[index]['task']}")else: print("序号不存在")defshow(self): print(f"\n{self.owner} 的待办:")for i, item in enumerate(self.__todos): status = "✓"if item["done"] else"○" print(f" {i}. [{status}] {item['task']}") pending = sum(1for t in self.__todos ifnot t["done"]) print(f" 共{len(self.__todos)}项,待完成{pending}项\n")def__len__(self):return len(self.__todos)def__str__(self): pending = sum(1for t in self.__todos ifnot t["done"])returnf"{self.owner}的待办:{pending}项待完成"# 使用my_list = TodoList("陈默")my_list.add("学 Python 面向对象")my_list.add("写一篇公众号文章")my_list.add("跑步 5 公里")my_list.complete(0)my_list.show()print(my_list) # 输出: 陈默的待办:2项待完成print(len(my_list)) # 输出: 3
最后
面向对象不是什么高深的东西。它就是把现实世界的思维方式搬进代码。
记住三件事:
- 类是图纸,对象是产品。
__init__ 是初始化,self 是"我" - 先写简单的类,再慢慢加继承和封装。别一开始就想太多
我的建议:
挑一个你熟悉的东西——手机、图书、订单——用类把它描述出来。给它属性,给它方法。先跑起来,再慢慢优化。
面向对象不是学出来的,是写出来的。
今天就到这里。
我是陈默,我们下期再见。
如果你觉得这篇文章有帮助,欢迎关注我。我会持续分享 Python 学习的干货。