面向对象编程(OOP)是 Python 中一种常用的编程范式,它通过类和对象来组织代码,使代码更加模块化、可重用和易于维护。下面是一些在项目中常用的 OOP 用法和具体代码示例。
1. 类和对象
定义类和创建对象
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f"{self.name} is barking!")
# 创建对象
my_dog = Dog("Buddy", 3)
# 调用方法
my_dog.bark()
# 输出: Buddy is barking!
2. 继承
继承允许我们创建一个新类,该类继承自一个或多个现有类,从而复用代码。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
# 创建对象
dog = Dog("Buddy")
cat = Cat("Whiskers")
# 调用方法
print(dog.speak()) # 输出: Buddy says Woof!
print(cat.speak()) # 输出: Whiskers says Meow!
3. 多态
多态允许我们在不考虑对象具体类型的情况下使用对象。
class Animal:
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
def make_animal_speak(animal):
print(animal.speak())
# 创建对象
dog = Dog()
cat = Cat()
# 调用方法
make_animal_speak(dog) # 输出: Woof!
make_animal_speak(cat) # 输出: Meow!
4. 封装
封装通过限制对类属性和方法的访问来保护对象的内部状态。
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 私有属性
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
def get_balance(self):
return self.__balance
# 创建对象
account = BankAccount(1000)
# 调用方法
account.deposit(500)
account.withdraw(200)
print(account.get_balance()) # 输出: 1300
# 尝试访问私有属性
# print(account.__balance) # AttributeError: 'BankAccount' object has no attribute '__balance'
在 Python 中,属性(或成员变量)可以分为以下几种类型:公有属性、受保护属性和私有属性。它们的定义方式和访问权限有所不同。
1. 公有属性(Public Attributes)
公有属性可以在类的内部和外部自由访问和修改。它们没有任何前缀。
class MyClass:
def __init__(self, value):
self.value = value # 公有属性
# 创建对象
obj = MyClass(10)
# 访问和修改公有属性
print(obj.value) # 输出: 10
obj.value = 20
print(obj.value) # 输出: 20
2. 受保护属性(Protected Attributes)
受保护属性以单个下划线 _
开头,表示它们不应该在类的外部直接访问,但在子类中可以访问。受保护属性是一种约定,而不是强制性的限制。
class MyClass:
def __init__(self, value):
self._value = value # 受保护属性
# 创建对象
obj = MyClass(10)
# 访问受保护属性(不推荐,但可以访问)
print(obj._value) # 输出: 10
obj._value = 20
print(obj._value) # 输出: 20
3. 私有属性(Private Attributes)
私有属性以双下划线 __
开头,表示它们只能在类的内部访问,不能在类的外部直接访问。私有属性通过名称重整(name mangling)来实现这一点。
class MyClass:
def __init__(self, value):
self.__value = value # 私有属性
def get_value(self):
return self.__value
# 创建对象
obj = MyClass(10)
# 尝试直接访问私有属性(会报错)
# print(obj.__value) # AttributeError: 'MyClass' object has no attribute '__value'
# 通过类内部的方法访问私有属性
print(obj.get_value()) # 输出: 10
# 通过名称重整访问私有属性(不推荐)
print(obj._MyClass__value) # 输出: 10
4. 属性装饰器(Property Decorators)
属性装饰器允许我们定义方法,但通过属性的方式来访问它们。常用的装饰器有 @property
、@<property_name>.setter
和 @<property_name>.deleter
。
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
if new_value >= 0:
self._value = new_value
else:
raise ValueError("Value must be non-negative")
@value.deleter
def value(self):
del self._value
# 创建对象
obj = MyClass(10)
# 通过属性装饰器访问和修改属性
print(obj.value) # 输出: 10
obj.value = 20
print(obj.value) # 输出: 20
# 尝试设置负值(会报错)
# obj.value = -10 # ValueError: Value must be non-negative
# 删除属性
del obj.value
# print(obj.value) # AttributeError: 'MyClass' object has no attribute '_value'
总结
- 公有属性:没有前缀,可以在类的内部和外部自由访问和修改。
- 受保护属性:以单个下划线
_
开头,表示不应该在类的外部直接访问,但在子类中可以访问。 - 私有属性:以双下划线
__
开头,只能在类的内部访问,通过名称重整实现。 - 属性装饰器:使用
@property
、@<property_name>.setter
和@<property_name>.deleter
来定义属性的访问、修改和删除方法。
5. 类方法和静态方法
类方法和静态方法是与类相关联的方法,而不是与实例相关联的方法。
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@classmethod
def multiply(cls, a, b):
return a * b
# 调用静态方法
print(MathUtils.add(3, 5)) # 输出: 8
# 调用类方法
print(MathUtils.multiply(3, 5)) # 输出: 15
6. 属性装饰器
属性装饰器允许我们定义方法,但通过属性的方式来访问它们。
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
@full_name.setter
def full_name(self, name):
first_name, last_name = name.split()
self.first_name = first_name
self.last_name = last_name
# 创建对象
person = Person("John", "Doe")
# 访问属性
print(person.full_name) # 输出: John Doe
# 设置属性
person.full_name = "Jane Smith"
print(person.first_name) # 输出: Jane
print(person.last_name) # 输出: Smith
7. 抽象类和接口
抽象类和接口用于定义必须在子类中实现的方法。Python 提供了 abc
模块来创建抽象类。
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
# 创建对象
dog = Dog()
cat = Cat()
# 调用方法
print(dog.speak()) # 输出: Woof!
print(cat.speak()) # 输出: Meow!
# 尝试实例化抽象类
# animal = Animal() # TypeError: Can't instantiate abstract class Animal with abstract methods speak
8. 组合
组合是通过将一个类的对象作为另一个类的属性来实现代码复用。
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self, model):
self.model = model
self.engine = Engine() # 组合
def start(self):
print(f"{self.model} car is starting...")
self.engine.start()
# 创建对象
my_car = Car("Toyota")
# 调用方法
my_car.start()
# 输出:
# Toyota car is starting...
# Engine started
9. 数据类
数据类是 Python 3.7 引入的一种简化类定义的方式,适用于主要用于存储数据的类。
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
# 创建对象
point = Point(1, 2)
# 访问属性
print(point.x) # 输出: 1
print(point.y) # 输出: 2
# 打印对象
print(point) # 输出: Point(x=1, y=2)
10. 运算符重载
运算符重载允许我们通过定义类的特殊方法(也称为魔术方法或双下划线方法)来重载内置运算符,以便使用内置运算符(如 +
、-
、*
等)来操作对象,这些特殊方法的名称是固定的。
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
# 创建对象
v1 = Vector(2, 3)
v2 = Vector(4, 5)
# 使用 + 运算符
v3 = v1 + v2
# 打印结果
print(v3) # 输出: Vector(6, 8)
11. 单例模式
单例模式(Singleton Pattern)是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。单例模式在需要确保某个类只有一个实例的场景中非常有用,例如数据库连接池、配置管理器、日志记录器等。
在 Python 中,实现单例模式的常见方法是重写类的 __new__
方法。__new__
方法是一个特殊方法,用于控制对象的创建过程。通过在 __new__
方法中检查是否已经存在实例,可以确保类只有一个实例。
以下是一个详细的单例模式实现示例:
单例模式实现
class Singleton:
_instance = None # 类变量,用于存储单例实例
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, value):
self.value = value
# 创建对象
s1 = Singleton(10)
s2 = Singleton(20)
# 检查是否是同一个实例
print(s1 is s2) # 输出: True
# 检查实例的属性值
print(s1.value) # 输出: 20
print(s2.value) # 输出: 20
详细解释
-
类变量
_instance
:Singleton
类有一个类变量_instance
,用于存储单例实例。初始值为None
,表示还没有创建实例。
-
重写
__new__
方法:__new__
方法是一个特殊方法,用于控制对象的创建过程。它在__init__
方法之前被调用。__new__
方法的第一个参数是cls
,表示当前类。- 在
__new__
方法中,首先检查cls._instance
是否为None
。如果是None
,表示还没有创建实例。 - 使用
super(Singleton, cls).__new__(cls, *args, **kwargs)
创建一个新的实例,并将其赋值给cls._instance
。 - 返回
cls._instance
,确保每次调用Singleton
类时都返回同一个实例。
-
__init__
方法:__init__
方法用于初始化实例的属性。在单例模式中,__init__
方法仍然会在每次创建对象时被调用。- 在这个示例中,
__init__
方法接受一个参数value
,并将其赋值给实例的属性value
。
注意事项
- 线程安全:上述实现并不是线程安全的。如果在多线程环境中使用单例模式,需要确保线程安全。可以使用线程锁(
threading.Lock
)来实现线程安全的单例模式。 - 惰性初始化:单例实例在第一次使用时才会被创建,这种方式称为惰性初始化(Lazy Initialization)。
线程安全的单例模式
以下是一个线程安全的单例模式实现示例:
import threading
class Singleton:
_instance = None
_lock = threading.Lock() # 线程锁
def __new__(cls, *args, **kwargs):
if not cls._instance:
with cls._lock:
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, value):
self.value = value
# 创建对象
s1 = Singleton(10)
s2 = Singleton(20)
# 检查是否是同一个实例
print(s1 is s2) # 输出: True
# 检查实例的属性值
print(s1.value) # 输出: 20
print(s2.value) # 输出: 20
在这个线程安全的实现中,使用了 threading.Lock
来确保在多线程环境中只有一个线程能够创建实例。这样可以避免多个线程同时创建多个实例的问题。
12. 工厂模式
工厂模式通过定义一个创建对象的接口来实现对象的创建,而不需要指定具体的类。
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
raise ValueError("Unknown animal type")
# 使用工厂创建对象
dog = AnimalFactory.create_animal("dog")
cat = AnimalFactory.create_animal("cat")
# 调用方法
print(dog.speak()) # 输出: Woof!
print(cat.speak()) # 输出: Meow!
。