python之面向对象编程(OOP)常见用法

面向对象编程(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
详细解释
  1. 类变量 _instance

    • Singleton 类有一个类变量 _instance,用于存储单例实例。初始值为 None,表示还没有创建实例。
  2. 重写 __new__ 方法

    • __new__ 方法是一个特殊方法,用于控制对象的创建过程。它在 __init__ 方法之前被调用。
    • __new__ 方法的第一个参数是 cls,表示当前类。
    • __new__ 方法中,首先检查 cls._instance 是否为 None。如果是 None,表示还没有创建实例。
    • 使用 super(Singleton, cls).__new__(cls, *args, **kwargs) 创建一个新的实例,并将其赋值给 cls._instance
    • 返回 cls._instance,确保每次调用 Singleton 类时都返回同一个实例。
  3. __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!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼爱吃火锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值