Python 面向对象编程
Python(03)学习笔记
发布于 2025-04-12类与对象
定义类
在 Python 中,使用 class
关键字定义类:
class Person:
"""人类的简单模型"""
def __init__(self, name, age):
"""初始化属性name和age"""
self.name = name
self.age = age
def say_hello(self):
"""问候方法"""
return f"你好,我是{self.name},今年{self.age}岁!"
创建对象
定义类后,可以创建该类的实例(对象):
# 创建Person类的实例
alice = Person("爱丽丝", 25)
# 访问对象的属性
print(alice.name) # 输出: 爱丽丝
# 调用对象的方法
print(alice.say_hello()) # 输出: 你好,我是爱丽丝,今年25岁!
__init__
方法
__init__
是 Python 的特殊方法(构造器),在创建对象时自动调用,用于初始化对象的属性。 self
参数表示对象本身,是约定俗成的命名,必须是方法的第一个参数。
封装
封装是将数据和方法绑定在一起,限制外部对对象内部数据的直接访问,只能通过对象提供的方法进行交互。
私有属性和方法
在 Python 中,约定以双下划线( __
)开头的属性或方法为私有:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance # 私有属性
def deposit(self, amount):
if amount > 0:
self.__balance += amount
return True
return False
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
return True
return False
def get_balance(self):
return self.__balance
尽管 Python 没有真正的私有属性(可以通过 _类名__属性名
访问),但这种命名约定提供了一定程度的封装。
继承
继承允许我们基于现有类(父类/基类)创建新类(子类/派生类),子类继承父类的属性和方法,并可以添加新的属性和方法或覆盖父类方法。
继承实现示例
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def make_sound(self):
pass
def move(self):
print(f"{self.name}正在移动")
class Dog(Animal):
def __init__(self, name, age, breed):
super().__init__(name, age) # 调用父类的__init__方法
self.breed = breed
def make_sound(self):
return "汪汪!"
def fetch(self):
return f"{self.name}在捡球"
# 创建Dog实例
dog = Dog("旺财", 3, "拉布拉多")
print(dog.name) # 继承自Animal的属性
print(dog.make_sound()) # 重写的方法
print(dog.fetch()) # Dog特有的方法
super()函数
super()
函数用于调用父类方法,避免直接引用父类,使代码更加灵活,特别是在多重继承的情况下。
多态
多态允许不同类的对象对同一消息(方法调用)做出不同的响应。在 Python 中,由于其动态类型特性,多态是自然而然的:
def animal_sound(animal):
return animal.make_sound()
dog = Dog("旺财", 3, "拉布拉多")
cat = Cat("咪咪", 2, "橘色")
bird = Bird("小黄", 1, 15.5)
print(animal_sound(dog)) # 输出: 汪汪!
print(animal_sound(cat)) # 输出: 喵喵!
print(animal_sound(bird)) # 输出: 啾啾!
这里的 animal_sound
函数不关心传入的对象类型,只要对象实现了 make_sound
方法即可。
特殊方法与属性
Python 提供了许多特殊方法(也称为"魔术方法"或"双下方法"),以双下划线开头和结尾,用于实现对象的特定行为。
常用特殊方法
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
"""返回对象的字符串表示,用于print()"""
return f"Vector({self.x}, {self.y})"
def __repr__(self):
"""返回对象的"官方"字符串表示,用于调试"""
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
"""实现加法操作符+"""
return Vector(self.x + other.x, self.y + other.y)
def __eq__(self, other):
"""实现等于操作符=="""
return self.x == other.x and self.y == other.y
def __len__(self):
"""实现len()函数"""
return int((self.x**2 + self.y**2)**0.5)
使用这些特殊方法,我们可以使自定义对象的行为更像 Python 内置类型:
v1 = Vector(3, 4)
v2 = Vector(1, 1)
print(v1) # 调用__str__
print(v1 + v2) # 调用__add__
print(v1 == v2) # 调用__eq__
print(len(v1)) # 调用__len__
高级特性
类方法和静态方法
- 类方法(classmethod): 操作类而非实例的方法,第一个参数是类本身(
cls
) - 静态方法(staticmethod): 与类关联但不操作类或实例的方法
class MathUtils:
def __init__(self, a=0, b=0):
self.a = a
self.b = b
@staticmethod
def add(a, b):
return a + b
@classmethod
def from_string(cls, string):
a, b = map(int, string.split(','))
return cls(a, b) # 创建类实例
属性装饰器
使用 @property
装饰器可以将方法转换为属性,实现更优雅的属性访问和修改:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""获取半径"""
return self._radius
@radius.setter
def radius(self, value):
"""设置半径,确保值为正数"""
if value <= 0:
raise ValueError("半径必须为正数")
self._radius = value
@property
def area(self):
"""计算面积"""
return 3.14159 * self._radius ** 2
# 使用
circle = Circle(5)
print(circle.radius) # 访问属性
circle.radius = 10 # 设置属性
print(circle.area) # 计算属性
多重继承
Python 支持多重继承,一个类可以继承多个父类:
class A:
def method_a(self):
return "A方法"
class B:
def method_b(self):
return "B方法"
class C(A, B): # 继承A和B
def method_c(self):
return "C方法"
# 使用
c = C()
print(c.method_a()) # 继承自A
print(c.method_b()) # 继承自B
print(c.method_c()) # C自己的方法
在多重继承中,Python 使用 C3 线性化算法来确定方法解析顺序(MRO),可以通过 类名.__mro__
查看。
抽象基类
使用 abc
模块可以定义抽象基类,强制子类实现特定方法:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
尝试实例化抽象基类或不实现抽象方法的子类会引发错误。
最佳实践
1. 遵循命名约定
- 类名使用驼峰命名法(
CamelCase
) - 方法和属性使用小写下划线命名法(
snake_case
) - 常量使用大写下划线命名法(
UPPERCASE_WITH_UNDERSCORES
) - 受保护的属性和方法以单下划线开头(
_protected
) - 私有属性和方法以双下划线开头(
__private
)
2. 单一职责原则
每个类应该只有一个职责,一个改变的理由。这使得类更加内聚、易于维护。
3. 组合优于继承
过度使用继承可能导致复杂的层次结构。在许多情况下,组合(让一个类包含另一个类的实例)是更好的选择:
# 继承
class Car(Vehicle):
pass
# 组合
class Car:
def __init__(self):
self.engine = Engine()
self.wheels = [Wheel() for _ in range(4)]
4. 使用描述性的文档字符串
为类和方法提供清晰的文档字符串,说明其用途、参数和返回值:
class Person:
"""
表示一个具有姓名和年龄的人。
属性:
name (str): 人的姓名
age (int): 人的年龄
"""
def __init__(self, name, age):
"""
初始化Person实例。参数:
name (str): 人的姓名
age (int): 人的年龄
"""
self.name = name
self.age = age
5. 使用类型提示
在 Python3.5+中,可以使用类型提示提高代码的可读性和可维护性:
from typing import List, Optional
class ShoppingCart:
def __init__(self) -> None:
self.items: List[str] = []
def add_item(self, item: str) -> None:
self.items.append(item)
def get_item(self, index: int) -> Optional[str]:
if 0 <= index < len(self.items):
return self.items[index]
return None