1 概述
- 『对象』是一个拥有属性和行为的个体,它是构成现实世界和程序世界的基本单位。
- 『面向对象』是一种以对象为中心,去思考和组织代码的方式,它更关注"谁来做这件事"。
- 『类』是用来描述一类事物的"模板",它规定了了一类事物所具有的属性和行为。『实例』是根据『类』创建出来的一个具体的『对象』。
2 基本使用
- 类的定义与创建
-
类名通常采用大驼峰命名法。
-
类中所定义的函数,通常又称为方法。
-
__init__方法叫初始化方法,当我们对类进行实例化时,Python会自动调用__init__方法。 -
__init__方法的名字不能更改,否则 Python 无法自动调用。 -
__init__收到的第一个参数是当前正在创建的实例对象,形参通常用self。 -
__init__方法收到的除self以外的参数,通常用来设置实例的属性值,通过"点"语法实现:self.属性名 = 属性值 -
代码示例
*python# 定义一个Person类 class Person: # __init__: 初始化方法 # self: 实例对象 # __init__不需要手动调用,创建对象时会自动调用 def __init__(self, name, age): # 给实例对象添加属性 self.name = name self.age = age # 创建实例对象 p1 = Person('张三', 26) p2 = Person('李四', 28) # 访问属性 print(p1.name, p1.age) print(p2.name, p2.age) # 修改属性 p1.name = '王五' print(p1.name, p1.age) # 查看实例的所有属性 print(p1.__dict__) # 给实例追加属性 p1.address='北京' print(p1.__dict__) # 通过type函数可以查看实例对象是哪个类创建出来的 print(type(p1))
-
- 自定义方法
-
要想让对象具备相应的『行为』,就需要通过『自定义方法』来实现。
-
代码示例
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 自定义方法 # speak方法只有一份,属于类 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') # 创建实例对象 p1 = Person('张三', 26) p2 = Person('李四', 28) print(p1.__dict__) print(p2.__dict__) # 执行p1.speak()时,先查找p1自身有没有speak方法,没有的话再查看类有没有speak方法 p1.speak('我今天要加班') p2.speak('我今天要去看电影') def speak(msg): print(f'这个不是类的speak方法 {msg}') p1.speak = speak print(p1.__dict__) print(p2.__dict__) p1.speak('p1 hello world') p2.speak('p2 hello world')
-
3 实例属性和类属性
-
实例属性
-
通过
实例.属性名 = 值定义在实例身上的属性,称为:实例属性。 -
每个实例都有自己『独立的一份』实例属性,各个实例之间是互不影响的。
-
实例属性只能通过
实例.xxxx访问和修改,不能通过『类名』访问或修改。 -
代码示例
*python# 定义一个Person类 class Person: # 通过 实例名.属性名 = 值 给实例添加的属性,叫实例属性 # 实例属性只能通过实例访问,不能通过类访问 # 每个实例都有自己独有的实例属性 def __init__(self, name, age): # 给实例对象添加属性 self.name = name self.age = age p1 = Person('张三', 26) print(p1.name) # print(Person.name) # 不能访问
-
-
类属性
-
在类中直接写赋值语句(例如:a = 100),就会在类身上添加一个a属性,值为 100,此时的a就是『类属性』,它属于类本身,由类所拥有,并且该类创建出来的所有实例对象,都能去访问a属性。
-
所有实例访问的,都是同一个类属性,所以类属性通常用于:存放公共数据。
-
类属性即可以通过『类』访问,也可以『实例』访问。
-
代码示例
*python# 定义一个Person类 class Person: # 类属性, 属于类 # 类属性可以通过类访问,也可以通过实例访问 # 类属性通常用于保存公共数据 max_age = 120 # 给实例添加属性 def __init__(self, name, age): # 给实例对象添加属性 self.name = name # 限制age最大值 if age <= Person.max_age: self.age = age else: print(f'年龄超出最大范围,已将年龄设置为最大值: {Person.max_age}') self.age = Person.max_age p1 = Person('张三', 26) p2 = Person('李四', 28) # 类属性可以通过类访问,也可以通过实例访问 print(p1.max_age) print(Person.max_age) p3 = Person('王五', 270)
-
4 实例方法、类方法、静态方法
- 实例方法
-
类中所定义的方法,最终会保存在类身上,并且主要是通过实例调用,所以叫:实例方法。
-
实例方法虽然最终会保存在类身上,但它主要是供实例使用的,所以才叫实例方法。
-
因为收到了self参数,所以其内部可以:访问实例属性,调用实例方法。
-
实例方法的主要作用:定义实例对象的具体行为。
-
代码示例
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') # 供实例调用,实例方法 def run(self, distance): print(f'{self.name}奔跑了{distance}米') p1 = Person('张三', 26) p2 = Person('李四', 28) # 通过实例调用实例方法 p1.speak('你好') p1.run(2000) # 通过类调用实例方法(不推荐) Person.run(p2, 3000)
-
- 类方法
-
使用
@classmethod装饰器修饰,第一个参数是类本身,通常用形参cls接收。 -
可通过『类名』或『实例名』调用,但强烈推荐通过类名调用以体现语义。
-
因为收到了
cls参数,所以内部可以访问类属性。 -
一般用于:实现与类相关的逻辑,如:操作类级别的信息、工厂方法等。
-
代码示例
*pythonfrom datetime import datetime # 定义一个Person类 class Person: # 类属性 max_age = 120 def __init__(self, name, age): self.name = name # 限制age最大值 if age <= Person.max_age: self.age = age else: print(f'年龄超出最大范围,已将年龄设置为最大值: {Person.max_age}') self.age = Person.max_age # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') # 类方法。使用@classmethod装饰过的方法叫类方法。 @classmethod def change_max_age(cls, value): cls.max_age = value @classmethod def create(cls, value): name, year = value.split('-') # 获取当前年份 cur_year = datetime.now().year age = cur_year - int(year) # 创建并返回Person类的实例对象 return cls(name, age) p1 = Person('张三', 135) # 调用类方法,修改类属性 Person.change_max_age(150) p2 = Person('李四', 135) print(p1.__dict__) print(p2.__dict__) # 调用类方法,创建实例对象 p3 = Person.create('王五-1994') print(p3.__dict__)
-
- 静态方法
-
使用
@staticmethod装饰器修饰,方法没有self或cls参数,只是单纯的定义在类中。 -
可通过『类名』或『实例名』调用,但强烈推荐通过类名调用以体现语义。
-
由于没有
self或cls参数,所以静态方法中通常:不访问类属性,也不访问实例属性。 -
一般用于:定义与类相关,但可以独立使用的工具方法。
-
代码示例
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 静态方法 # 使用@staticmethod装饰过的方法叫静态方法 @staticmethod # 判断是否为成年人 def is_adult(age): if age >= 18: return True else: return False # 静态方法通过类调用 print(Person.is_adult(20))
-
5 继承
5.1 基本语法
-
概念:是指一个类,可以继承另一个类的属性和方法。
-
作用:可以实现代码的复用与扩展,避免重复编写相同的代码,让程序结构更简洁、更高效。
-
示例1
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') # 定义一个Student类(子类、派生类),继承自Person类(父类、基类) class Student(Person): pass # 创建Student实例对象 s1 = Student('小明', 18) print(s1.__dict__) print(type(s1)) # 查找speak方法的过程:先找s1实例自身,再找Student类,再找基类Person类 s1.speak('你好') -
示例2
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') # 定义一个Student类(子类、派生类),继承自Person类(父类、基类) class Student(Person): def __init__(self, name, age, code, grade): # 调用父类方法初始化,对继承属性进行初始化。方式1(推荐) super().__init__(name, age) # 调用父类方法初始化,对继承属性进行初始化。方式2 # Person.__init__(self, name, age) # 子类属性单独初始化 self.code = code self.grade = grade def study(self, msg): print(f'我叫{self.name}, 年级是{self.grade} 我想说: {msg}') # 创建Student实例对象 s1 = Student('小明', 18, 10030, '高三') s1.study('好好学习')
5.2 方法重写
-
如果子类中定义了与父类同名的方法,则会子类会"覆盖"父类中的方法,又称:"重写"。
-
示例
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') # 定义一个Student类,继承自Person类 class Student(Person): def __init__(self, name, age, code, grade): super().__init__(name, age) self.code = code self.grade = grade # 方法重写:当子类中定义了一个与父类中相同的方法,那么子类中的方法就会"覆盖"父类的方法 def speak(self, msg): print(f'我是学生, 我叫{self.name}, 年级是{self.grade}, 学号是{self.code}, 我想说: {msg}') s1 = Student('小明', 18, '高三', 10030) s1.speak('好好学习')
5.3 两个常用方法
-
isinstance(obj, Class):判断对象是否为指定类或其子类的实例。 -
issubclass(Sub, Super):判断一个类是否是另一个类的子类。 -
示例
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 定义一个Student类,继承自Person类 class Student(Person): def __init__(self, name, age, code, grade): super().__init__(name, age) self.code = code self.grade = grade p1 = Person('张三', 35) s1 = Student('小明', 18, 10010, '高三') # 判断对象是否为指定类或其子类的实例 print(isinstance(p1, Person)) print(isinstance(s1, Student)) print(isinstance(s1, Person)) print(isinstance(p1, Student)) # 判断某个类是否是另一个类的子类 print(issubclass(Person, Student)) print(issubclass(Student, Person))
5.4 多重继承
-
多重继承指一个类同时继承多个父类,从而拥有多个父类的属性和方法。
-
示例
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 供实例调用,实例方法 def speak(self): print(f'我叫{self.name}, 年龄是{self.age}') class Worker: def __init__(self, company): self.company = company def do_work(self): print(f'我在{self.company}做兼职') class Student(Person, Worker): def __init__(self, name, age, company, code, grade): Person.__init__(self, name, age) Worker.__init__(self, company) self.code = code self.grade = grade def study(self): print(f'我在努力学习,争取考进{self.grade}前十') s1 = Student('小明', 18, '顺丰快递', 10010, '高三') s1.speak() s1.do_work() s1.study() print(s1.__dict__) # 类的__mro__属性:用于记录属性和方法的查找顺序 print(Student.__mro__)
6 访问控制
6.1 三种访问权限
| 权限类型 | 定义方式 | 在当前类内部访问 | 在子类内部访问 | 在类外部访问 |
|---|---|---|---|---|
| 公有属性 | 属性名 | ✅ 能 | ✅ 能 | ✅ 能 |
| 受保护属性 | _属性名 | ✅ 能 | ✅ 能 | ⚠️ 能 (但不推荐) |
| 私有属性 | __属性名 | ✅ 能 | ❌ 不能 | ❌ 不能 |
-
示例代码
*python# 定义一个Person类 class Person: def __init__(self, name, age, idcard): self.name = name # 公有属性: 类中、子类中、类外部都可以访问 self._age = age # 受保护属性:类中、子类中可以访问,类外不可以访问 self.__idcard = idcard # 私有属性: 仅可以在类中访问 # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self._age}, 身份证号{self.__idcard}, 我想说: {msg}') class Student(Person): def hello(self): # 可以访问公有属性name和受保护属性age # 不能访问私有属性idcard print(f'我是学生, 我叫是{self.name}, 年龄是{self._age}, 我想说 hello') p1 = Person('张三', 35, '610323********8820') p1.speak('你好')
6.2 getter与setter
-
在面向对象编程中,我们会把一些内部数据保护起来,但同时还想提供一个"安全的通道"让外部访问。这时候我们就用到:
getter:读取属性的方法setter:修改属性的方法
-
在 Python 中:通过
@property和@xxx.setter语法,把普通方法变成像属性一样使用的方法。 -
示例代码
*python# 定义一个Person类 class Person: def __init__(self, name, age, idcard): self.name = name # 公有属性: 类中、子类中、类外部都可以访问 self._age = age # 受保护属性:类中、子类中可以访问,类外不可以访问 self.__idcard = idcard # 私有属性: 仅可以在类中访问 # 注册age属性的getter方法,当访问Person实例的age属性时,下面的age方法就会被自动调用 @property def age(self): return self._age # 注册age属性的setter方法,当修改Person实例的age属性时,下面的age方法就会被自动调用 @age.setter def age(self, age): self._age = age # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self._age}, 身份证号{self.__idcard}, 我想说: {msg}') p1 = Person('张三', 18, '610323********3657') print(p1.name) # 既可以在类外访问age,也可以在类外修改age print(p1.age) p1.age = 20
7 魔法方法
-
概念:以
__xxx__命名的特殊方法(双下划线开头和结尾)。 -
特点:不需要手动调,在特定场景由 Python 自动调用。
__str__:当调用print(对象)或str(对象)时__len__:当调用len(对象)时__lt__:当执行对象1 < 对象2时__gt__:当执行对象1 > 对象2时__eq__:当执行对象1 == 对象2时__getattr__:当访问不存在的属性时
-
示例代码
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 执行print(Person实例对象) 或 str(Person实例对象) 时调用 def __str__(self): return f'{self.name}, {self.age}' # 执行len(Person实例对象)时调用 def __len__(self): return len(self.__dict__) # 执行 Person实例对象1 < Person实例对象2 时调用 def __lt__(self, other): return self.age < other.age # 执行 Person实例对象1 == Person实例对象2 时调用 def __eq__(self, other): return self.__dict__ == other.__dict__ # 访问Person实例对象不存在的属性时调用 def __getattr__(self, item): return f'您访问的{item}属性不存在' # 供实例调用,实例方法 def speak(self, msg): print(f'我叫{self.name}, 年龄是{self.age}, 我想说: {msg}') p1 = Person('张三', 35) p2 = Person('李四', 40) # 底层调用的是__str__方法 print(p1) # 底层调用的是__len__方法 l1 = len(p1) print(l1) # 底层调用的是__lt__方法 print(p1 < p2) # 底层调用的是__eq__方法 print(p1 == p2) print(p1.address)
8 object类
-
object是所有类的最终祖先,所有的类,无论写与不写,都继承自object。
-
object提供了所有对象都会有的一组最基本方法,例如
__init__(self):在对实例对象初始化时调用__str__(self):print(obj)或int(obj)时调用__class__:返回对象所属的类
-
示例代码
*python# 定义一个Person类 class Person: def __init__(self, name, age): self.name = name self.age = age # 验证Person类继承了object类 print('Person类是否继承自object类', issubclass(Person, object)) print('int类是否继承自object类', issubclass(int, object)) print('str类是否继承自object类', issubclass(str, object)) print('list类是否继承自object类', issubclass(list, object)) p1 = Person('张三', 19) print('p1是否为object类的实例', isinstance(p1, object)) print('[1, 2, 3]是否为object类的实例', isinstance([1, 2, 3], object)) print('10086是否为object类的实例', isinstance(10086, object)) print(p1.__dict__) # 打印p1自身的属性 print(dir(p1)) # 打印p1可以访问到的属性 # 打印object类的所有属性 # for key in object.__dict__: # print(key)
9 多态
- 多态就是"多种形态",即:不同的对象调使用同一个方法名调用方法时,会表现出不同的行为。
9.1 标准多态
-
基于继承实现多态,又叫:『传统多态』或『标准多态』。
-
常见于Java、C++ 这样的强类型语言中,Python支持『标准多态』。
-
代码示例
*pythonclass Animal: def speak(self): print('动物正在发出声音') class Dog(Animal): def speak(self): print('汪汪汪') class Cat(Animal): def speak(self): print('喵喵喵') def make_sound(animal:Animal): # 多态的体现 animal.speak() # 创建实例对象 a1 = Animal() d1 = Dog() c1 = Cat() make_sound(a1) make_sound(d1) make_sound(c1)
9.2 鸭子多态
-
鸭子类型:如果一个东西看起来像鸭子,叫起来也像鸭子,那它就是鸭子,鸭子类型指一种编程风格,它并不依靠查找对象类型,来确定其是否具有正确的实现,而是直接调用或使用其方法或属性。
-
特点:不需要继承,只要传进来的对象,有对应实现就可以。
-
Python 中支持"鸭子多态"。
-
示例
*pythonclass Dog: def speak(self): print('汪汪汪') class Cat: def speak(self): print('喵喵喵') class Pig: def speak(self): print('哼哼哼') def make_sound(animal): # 多态的体现 animal.speak() # 创建实例对象 d1 = Dog() c1 = Cat() p1 = Pig() make_sound(d1) make_sound(c1) make_sound(p1)
10 抽象类
-
抽象类(Abstract Class) 是一种 不能被直接实例化 的类,通常作为"规范",让子类去继承并实现其中定义的抽象方法,本身只定义规范,不需要提供完整实现。
-
示例代码
*pythonfrom abc import ABC, abstractmethod # 继承了ABC的类是抽象类 class MustRun(ABC): # 抽象方法 @abstractmethod def run(self): pass # 也可以写普通方法 def speak(self): print(f"我叫{self.name}") class Person(MustRun): def __init__(self, name, age): self.name = name self.age = age def run(self): print(f'我叫{self.name}, 年龄{self.age}, 正在奔跑') # 不能实例化对象 # m1 = MustRun() p1 = Person('张三', 30) p1.run() p1.speak()
11 内存分析
- 内存分为两个部分:栈内存、堆内存;变量在栈内存中,对象在堆内存中。
- Python 中变量里保存的不是存数据,而是指向堆中对象的引用(内存地址)。
- 不可变对象:重新赋值会创建新对象
- int 类的实例对象,是不可变对象,所以修改变量 a 时,会创建新对象,不会影响其他引用(b)
- Python 中常见的不可变对象有:int 、float 、bool 、str 、tuple 、frozenset 、None。
- Python 中常见的可变对象有:list 、dict 、set 、自定义类的实例对象。

- 可变对象:修改内容不改变地址
- 自定义类对象的内存表示

















