Python3 面向对象详解
在 Python 中,面向对象编程(Object-Oriented Programming,OOP)是一种以 “对象” 为核心的编程范式,通过封装、继承、多态三大特性实现代码的复用、扩展和模块化。本文将系统解析 Python3 面向对象的核心概念与实战用法。
一、面向对象的基本概念
1. 什么是对象?
对象是现实世界实体的抽象,由属性(数据)和方法(行为)组成。例如:
- 一个 “人” 可以是对象:属性(姓名、年龄),方法(说话、走路)。
- 一个 “汽车” 可以是对象:属性(颜色、速度),方法(加速、刹车)。
2. 什么是类?
类是对象的模板,定义了对象的属性和方法。通过类可以创建多个具有相同结构的对象(实例)。
例如:“人类” 是类,“张三”“李四” 是该类的对象。
例如:“人类” 是类,“张三”“李四” 是该类的对象。
二、类与对象的定义和使用
1. 定义类
使用
class
关键字定义类,类名通常采用 “大驼峰命名法”(每个单词首字母大写)。class Person:
# 类属性:所有实例共享的属性
species = "人类" # 所有Person都是“人类”
# 构造方法:初始化对象属性(__init__是特殊方法,称为“魔术方法”)
def __init__(self, name, age):
# 实例属性:每个对象独有的属性
self.name = name # self代表当前对象
self.age = age
# 实例方法:定义对象的行为
def say_hello(self):
print(f"大家好,我是{self.name},今年{self.age}岁")
def grow(self):
self.age += 1 # 修改实例属性
__init__
:构造方法,创建对象时自动调用,用于初始化属性。self
:必须作为第一个参数,代表当前实例(类似 Java 的this
)。
2. 创建对象(实例化)
通过 “类名 (参数)” 创建对象,参数对应
__init__
方法的参数(不含self
)。# 创建两个Person对象
p1 = Person("张三", 20)
p2 = Person("李四", 25)
# 访问对象的属性和方法
print(p1.name) # 输出:张三
p1.say_hello() # 输出:大家好,我是张三,今年20岁
p2.grow()
print(p2.age) # 输出:26(年龄增长1岁)
# 访问类属性(所有实例共享)
print(p1.species) # 输出:人类
print(Person.species) # 输出:人类(也可通过类名访问)
三、类的核心组成
1. 属性分类
类型 | 定义位置 | 访问方式 | 特点 |
---|---|---|---|
实例属性 | __init__ 方法中 |
对象.属性名 |
每个对象独立存储 |
类属性 | 类内部,方法外 | 类名.属性名 或对象.属性名 |
所有对象共享,节省内存 |
示例:类属性与实例属性的区别
class Student:
school = "阳光小学" # 类属性:所有学生的学校相同
def __init__(self, name):
self.name = name # 实例属性:每个学生姓名不同
s1 = Student("小明")
s2 = Student("小红")
print(s1.school) # 输出:阳光小学(共享类属性)
print(s2.school) # 输出:阳光小学
Student.school = "星光小学" # 修改类属性,所有实例都会受影响
print(s1.school) # 输出:星光小学
2. 方法分类
Python 类中的方法分为三类,用途不同:
类型 | 定义方式 | 第一个参数 | 调用方式 | 用途 |
---|---|---|---|---|
实例方法 | def 方法名(self, ...) |
self |
对象.方法名() |
操作实例属性,依赖对象 |
类方法 | @classmethod 装饰 |
cls |
类名.方法名() |
操作类属性,不依赖对象 |
静态方法 | @staticmethod 装饰 |
无特殊参数 | 类名.方法名() |
工具函数,与类 / 对象弱关联 |
示例:三种方法的使用
class Calculator:
# 类属性:记录计算次数
count = 0
def __init__(self, a, b):
self.a = a
self.b = b
# 实例方法:计算两个数的和(依赖实例属性)
def add(self):
return self.a + self.b
# 类方法:更新计算次数(操作类属性)
@classmethod
def increment_count(cls):
cls.count += 1
# 静态方法:判断一个数是否为偶数(独立工具函数)
@staticmethod
def is_even(num):
return num % 2 == 0
# 实例方法使用
calc = Calculator(3, 5)
print(calc.add()) # 输出:8
# 类方法使用
Calculator.increment_count()
Calculator.increment_count()
print(Calculator.count) # 输出:2
# 静态方法使用
print(Calculator.is_even(4)) # 输出:True
四、面向对象的三大特性
1. 封装(Encapsulation)
核心思想:隐藏对象的内部细节,仅通过公开方法对外提供访问接口,确保数据安全。
Python 通过 “命名约定” 实现封装:
Python 通过 “命名约定” 实现封装:
- 公开属性 / 方法:默认命名(如
name
、say_hello
),可直接访问。 - 私有属性 / 方法:以双下划线
__
开头(如__secret
),只能在类内部访问。
示例:私有属性的封装
class BankAccount:
def __init__(self, account_id, balance):
self.account_id = account_id # 公开属性
self.__balance = balance # 私有属性(余额不允许直接修改)
# 公开方法:提供安全的余额访问
def get_balance(self):
return self.__balance
# 公开方法:提供安全的存款逻辑
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"存款成功,当前余额:{self.__balance}")
else:
print("存款金额必须为正数")
# 使用
account = BankAccount("622202XXXX", 1000)
print(account.account_id) # 输出:622202XXXX(允许访问公开属性)
# 尝试直接访问私有属性(会报错)
# print(account.__balance) # AttributeError: 'BankAccount' object has no attribute '__balance'
# 通过公开方法访问和修改
print(account.get_balance()) # 输出:1000
account.deposit(500) # 输出:存款成功,当前余额:1500
注:Python 的私有属性并非绝对不可访问(可通过_类名__属性名
间接访问,如account._BankAccount__balance
),但这是不推荐的 “黑魔法”,违背封装原则。
2. 继承(Inheritance)
核心思想:子类(派生类)继承父类(基类)的属性和方法,并可扩展新功能或重写父类方法,实现代码复用。
(1)单继承
一个子类只能继承一个父类(Python 也支持多继承)。
# 父类:动物
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name}在吃东西")
# 子类:狗(继承Animal)
class Dog(Animal): # 通过括号指定父类
# 重写父类方法(Override)
def eat(self):
print(f"{self.name}在啃骨头") # 扩展父类的实现
# 子类新增方法
def bark(self):
print(f"{self.name}在汪汪叫")
# 使用
dog = Dog("旺财")
dog.eat() # 输出:旺财在啃骨头(调用重写后的方法)
dog.bark() # 输出:旺财在汪汪叫(调用子类新增方法)
(2)调用父类方法
通过
super()
函数在子类中调用父类的方法(尤其是构造方法)。class Parent:
def __init__(self, a):
self.a = a
class Child(Parent):
def __init__(self, a, b):
# 调用父类的__init__方法初始化a
super().__init__(a) # 等价于 Parent.__init__(self, a)
self.b = b # 子类新增属性
child = Child(10, 20)
print(child.a, child.b) # 输出:10 20
(3)多继承
Python 支持一个子类继承多个父类,语法为
但需注意方法解析顺序(MRO):当多个父类有同名方法时,按
class 子类(父类1, 父类2, ...)
。但需注意方法解析顺序(MRO):当多个父类有同名方法时,按
子类.__mro__
的顺序查找。class A:
def say(self):
print("A的say方法")
class B:
def say(self):
print("B的say方法")
class C(A, B): # 继承A和B
pass
c = C()
c.say() # 输出:A的say方法(按MRO顺序,A在B前)
print(C.__mro__) # 输出:(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
3. 多态(Polymorphism)
核心思想:不同子类对同一方法有不同实现,通过父类引用调用时,表现出不同行为。
Python 的多态基于 “动态类型”(无需显式声明类型),更加灵活。
Python 的多态基于 “动态类型”(无需显式声明类型),更加灵活。
# 父类:形状
class Shape:
def draw(self):
pass # 父类方法,子类需重写
# 子类:圆形
class Circle(Shape):
def draw(self):
print("画圆形")
# 子类:矩形
class Rectangle(Shape):
def draw(self):
print("画矩形")
# 统一接口:接收Shape类型(或其子类)
def draw_shape(shape):
shape.draw() # 调用时自动匹配子类的实现
# 多态体现:同一接口,不同实现
draw_shape(Circle()) # 输出:画圆形
draw_shape(Rectangle()) # 输出:画矩形
五、特殊方法(魔术方法)
Python 类中以双下划线
__
开头和结尾的方法称为 “特殊方法”(或 “魔术方法”),用于实现类的特殊行为(如运算符重载、字符串表示等)。常用特殊方法
方法名 | 作用 | 示例场景 |
---|---|---|
__init__ |
构造方法,初始化对象 | def __init__(self, name): ... |
__str__ |
定义对象的字符串表示(str(obj) ) |
print(obj) 时调用 |
__repr__ |
定义对象的官方字符串表示(repr(obj) ) |
调试时显示 |
__add__ |
重载+ 运算符 |
obj1 + obj2 时调用 |
__len__ |
重载len() 函数 |
len(obj) 时调用 |
示例:自定义字符串表示和运算符
class Book:
def __init__(self, title, pages):
self.title = title
self.pages = pages
# 自定义print(book)的输出
def __str__(self):
return f"《{self.title}》({self.pages}页)"
# 自定义len(book)的行为
def __len__(self):
return self.pages
# 重载+运算符:两本书的总页数
def __add__(self, other):
return self.pages + other.pages
# 使用
book1 = Book("Python编程", 300)
book2 = Book("Java编程", 400)
print(book1) # 输出:《Python编程》(300页)(调用__str__)
print(len(book1)) # 输出:300(调用__len__)
print(book1 + book2)# 输出:700(调用__add__)
六、面向对象的优势
- 代码复用:通过继承减少重复代码。
- 模块化:每个类独立封装属性和方法,便于维护。
- 可扩展性:新增功能只需添加子类或修改方法,符合 “开闭原则”。
- 可读性:类和对象的设计贴近现实世界,逻辑清晰。
总结
Python 的面向对象编程通过类与对象的封装、继承与多态,实现了代码的高效组织与扩展。核心要点包括:
- 类是对象的模板,对象是类的实例;
- 封装通过私有属性和公开方法保护数据;
- 继承实现代码复用,
super()
用于调用父类方法; - 多态让不同子类通过统一接口表现不同行为;
- 特殊方法增强类的灵活性(如运算符重载)。
掌握这些概念,能帮助你设计出更清晰、更易维护的 Python 程序,尤其在大型项目开发中体现显著优势。