Python 类和对象:别背语法,先理解”模板”和”实例”的关系
面向对象编程,听起来很唬人,其实核心就两个概念:类和对象。
类就是模板,对象就是根据模板造出来的具体东西。打个比方:类是一张”员工入职登记表”的模板,对象就是你拿着这个模板给每个新员工填出来的那张具体表格。
Python 里万物皆对象,但你自己也能定义类。
定义一个类:从空壳子开始
用 class 关键字定义一个类,类名用帕斯卡命名法(首字母大写):
1 | class Person: |
目前这个 Person 是个空壳子,啥用没有。我们需要给它加东西。
构造方法 __init__:对象出生时该干的事
__init__ 是 Python 的构造方法,对象被创建的时候自动调用。它的作用就是给对象初始化——设置初始状态、存一些基础数据。
1 | class Person: |
关键点:
self就是对象本身,相当于 Java 里的thisself.name是对象的属性,每个对象有自己的独立副本__init__可以有默认参数,让某些属性可选
1 | class Student: |
类变量 vs 实例变量:共享的和独享的
这是刚学 Python 类的时候最容易搞混的地方。
实例变量:每个对象各有一份,互不影响。用 self.xxx 定义。
类变量:所有对象共享一份,属于类本身。直接在类下面定义,不在任何方法里面。
1 | class Employee: |
什么时候用类变量? 统计总数、全局配置、默认值等所有对象共用的东西。
什么时候用实例变量? 每个对象各自不同的数据,比如名字、年龄、分数。
三种方法:实例方法、类方法、静态方法
1. 实例方法:最常用的,第一个参数是 self
1 | class Person: |
实例方法能访问实例变量和类变量,是日常写代码最常用的一种。
2. 类方法:用 @classmethod,第一个参数是 cls(类本身)
1 | class Person: |
类方法通常用来操作类变量,或者作为工厂方法——用不同方式创建对象。
1 | class Person: |
3. 静态方法:用 @staticmethod,不需要 self 或 cls
静态方法跟类本身没有直接关系,只是因为逻辑上属于这个类,所以放在里面。它不访问任何实例或类属性。
1 | class MathUtils: |
继承:子类继承父类的东西
单继承:一个子类只有一个父类
1 | class Animal: |
重写父类方法:子类把父类的方法覆盖掉
1 | class Cat(Animal): |
调用父类的方法:用 super()
1 | class Bird(Animal): |
super() 的作用是”调用父类的同名方法”,避免硬编码父类名,代码更好维护。
多继承:一个子类有多个父类
1 | class Flyable: |
多继承的问题在于:如果多个父类有同名方法,Python 按什么顺序找?答案是 MRO(方法解析顺序),从左到右。Duck(Flyable, Swimmable) 先找 Flyable,再找 Swimmable。
私有属性:名字前面加两个下划线
Python 没有真正的私有,但用双下划线开头可以”隐藏”属性:
1 | class Person: |
其实 Python 只是把 __age 改名叫 _Person__age 了,你非要访问也能 p._Person__age,但强烈不推荐。私有属性的意义是”约定”而不是”强制”——告诉使用这个类的人:别碰这个属性。
几个特殊方法:让对象更像对象
| 方法 | 作用 | 什么时候触发 |
|---|---|---|
__init__ |
初始化对象 | 创建对象时 |
__str__ |
对象的字符串表示 | print(obj) 或 str(obj) |
__repr__ |
对象的官方字符串表示 | 调试时,或在交互式环境直接输入对象名 |
__len__ |
对象的长度 | len(obj) |
__str__ 最常用:
1 | class Book: |
不定义 __str__ 的话,print(book) 会打印一串看不懂的内存地址。
类比java的toString方法