1. 面向对象编程简介
面向对象编程的英文是:Object Oriented Programming,简称 OOP。 在实际开发过程中,我们经常需要将现实生活中的事物映射成编程中的对象,即用代码来描述、模拟现实生活中的事物。
2. 类 (Class) 与实例化
- 类:用来描述、模拟某一事物类型。类名通常采用大驼峰格式(如
Student,IceCream)。 - 对象:通过类创建出来的实例(instance)。
- 实例化:通过类创建对象的过程。
# 定义类
class Dog:
"""狗类"""
pass
# 实例化对象
d1 = Dog()
d2 = Dog()
print(type(d1)) # <class '__main__.Dog'>
3. 方法 (Method) 与属性
方法可以理解为一种需要通过对象来调用的特殊函数,代表对象的能力或行为。
3.1 方法的定义与调用
- 方法必须定义在类的内部。
- 方法的第1个参数固定是
self,指向当前正在调用方法的对象(类似 Java 的this)。 - 调用时不需要显式传递
self。
class Dog:
def run(self):
print(f'【{self.name}】跑起来了!')
d1 = Dog()
d1.name = '旺财' # 动态添加对象属性
d1.run()
3.2 构造方法 __init__
构造方法是一种特殊的方法,对象在创建完毕时会自动调用。一般用于声明和初始化属性。
class Dog:
# 带有默认参数的构造方法
def __init__(self, name=None, age=1):
self.name = name # 对象属性
self.age = age
d1 = Dog('宝哥', 5)
4. 对象属性 vs 类属性 vs 局部变量
- 局部变量:定义在方法内部,不带
self。依赖于方法调用存在,调用完销毁。 - 对象属性(实例属性):挂载在
self上,如self.name。每个实例对象独立拥有一份。 - 类属性(类变量):直接写在类里面的变量,不带
self。所有实例对象共享这一份数据(类似全局变量)。
class Dog:
count = 0 # 类属性
def __init__(self, name):
self.name = name # 对象属性
Dog.count += 1 # 修改类属性
d1 = Dog('旺财')
d2 = Dog('宝哥')
print(Dog.count) # 2
建议:通过对象访问对象属性,通过类访问类属性。如果同名,通过对象访问会优先找到对象属性。
5. 对象方法、类方法、静态方法
| 方法类型 | 装饰器 | 首个固定参数 | 调用方式推荐 | 适用场景 |
|---|---|---|---|---|
| 对象方法 | 无 | self (代表对象) | 对象.方法() | 行为的执行者是对象本身 |
| 类方法 | @classmethod | cls (代表类) | 类.方法() | 无须实例化,且需操作类属性 |
| 静态方法 | @staticmethod | 无固定参数 | 类.方法() | 无须实例化,也不操作类属性(相当于普通函数放进了类里) |
class Dog:
@classmethod
def test_class(cls):
pass
@staticmethod
def test_static():
pass
6. 面向对象三大特性
6.1 封装 (Encapsulation)
- 屏蔽内部细节:将属性私有化。在 Python 中,如果属性或方法以双下划线
__开头,则对外不可见。 - 对外提供接口:外界通过特定的 getter / setter 方法访问或修改属性。
不可见的真相:Python 没有真正的私有化。
__name只是被改名成了_类名__name,依然可以通过s._Student__name访问(只能防君子不能防小人)。
@property 装饰器
可以让 getter 和 setter 的使用像访问普通属性一样优雅。
class Student:
def __init__(self):
self.__age = None
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
self.__age = value if value > 0 else 1
s = Student()
s.age = 10 # 调用 setter
print(s.age) # 调用 getter
6.2 继承 (Inheritance)
子类(派生类)可以继承父类(基类/超类)的属性和方法。Python 支持多继承(但不推荐)。
- 获取父类/子类:
类.__base__,类.__subclasses__() - 重写 (Override):子类可以重新定义父类中同名的方法。
调用父类方法
在子类重写的方法中,经常需要调用父类的逻辑,可以使用 super():
class Person:
def __init__(self, name):
self.name = name
class Student(Person):
def __init__(self, name, no):
super().__init__(name) # 调用父类的构造方法
self.no = no
6.3 多态 (Polymorphism)
父类类型的变量指向子类类型的对象,调用同一方法时,会根据对象的真实类型呈现出不同的行为(形态)。
def test(obj: Animal):
obj.run() # 如果传Dog调用Dog的run,传Cat调用Cat的run
7. 其他补充知识点
重载 (Overload)
- 在同一作用域定义多个同名但参数不同的方法。
- Python 不支持传统重载。因为后面的定义会直接覆盖前面的。
- Python 通过给参数设置默认值即可优雅替代重载的需求。
内置属性与方法 (Magic Methods)
双下划线开头和结尾的通常是内置方法/属性:
__dict__:存放对象所有自定义的属性字典。__str__:执行str(对象)或print(对象)时自动调用,返回对象的字符串表示。__doc__:文档注释。
isinstance 与 issubclass
isinstance(obj, Class):判断对象obj是否为Class类型(或其子类)的实例。issubclass(Class1, Class2):判断Class1是否为Class2的子类。
bool 继承自 int
bool 类型其实是 int 的子类,所以 True + 10 等于 11。