Python 面向对象编程(OOP)基础

Python 面向对象编程(OOP)简介

Python 面向对象编程(OOP)是一种编程范式,强调将数据和操作数据的代码封装在一起。通过使用对象,OOP 提供了一种更自然和直观的方式来组织和管理代码。这里将介绍 OOP 的基本概念,包括定义类和对象、构造函数、类的方法与属性,以及继承与多态。


面向对象编程(OOP)基础内容

1. 定义类和对象

类是创建对象的蓝图或模板。它定义了对象的属性(数据)和方法(行为)。

对象

对象是类的实例。通过类可以创建多个对象,每个对象都有自己的属性值。

示例
class Dog:
    # 类定义
    class_attribute = "可爱的小狗子"  # 类属性

    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age

# 创建对象
my_dog = Dog("辣白菜", 5)
print(my_dog.name)  # 输出: 辣白菜

2. 构造函数(__init__

构造函数是类的一个特殊方法,用于在创建对象时初始化属性。它的名称为 __init__,并且会在每次实例化对象时自动调用。

示例

class Car:
    def __init__(self, brand, color):
        self.brand = brand  # 实例属性
        self.color = color

my_car = Car("劳斯莱斯", "蓝黑")
print(my_car.brand)  # 输出: 劳斯莱斯

注意

  • self 是指向对象自身的引用,使我们可以访问对象的属性和方法。

3. 类的方法与属性

类的方法

类的方法是定义在类中的函数,用于实现特定的功能。它们通常会操作对象的属性。

示例
class Number:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def add(self):
        return self.a + self.b # 计算a+b的值

number = Number(5, 6)
print(number.add())  # 输出: 11

类的属性

类的属性是属于类本身的变量,所有实例共享。例如,可以定义一个类属性来表示所有狗的共同特性。

示例
class Dog:
    class_attribute = "可以四条腿走路"

# 访问类属性
print(Dog.class_attribute)  # 输出: 可以四条腿走路
类方法与实例方法的区别
特性类方法实例方法
绑定对象绑定到类绑定到实例
第一个参数cls(类本身)self(实例本身)
访问权限可以访问类属性可以访问实例属性
调用方式可以通过类名或实例调用只能通过实例调用
类属性和实例属性之间的区别.
特性类属性实例属性
定义位置类体内部(方法外部)在构造方法 __init__ 内部
作用域与类关联,所有实例共享与特定实例关联,每个实例独立
访问方式通过类名或实例访问通过实例访问
共享性所有实例共享同一值每个实例有自己的值
适用场景用于需要在多个实例之间共享的常量或状态用于需要跟踪特定实例的状态
修改影响修改类属性会影响所有实例修改实例属性只影响特定实例
建议使用当需要定义常量或类级别的状态时使用当需要为每个实例存储独立状态时使用

4. 继承与多态

继承

继承是 OOP 的一个重要特性,允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以重用父类的代码,并可以扩展或修改其功能。

示例
class Animal: # 父类, 这是个动物
    def speak(self):
        return "我是个动物"

class Dog(Animal):  # Dog 继承 Animal
    def speak(self):
        return "旺旺"

my_dog = Dog()
print(my_dog.speak())  # 输出: 旺旺

多态

多态是指同一种方法可以在不同的类中表现出不同的行为。通过父类引用调用子类的方法,可以实现灵活性。

示例
class Cat(Animal): # 猫继承动物
    def speak(self):
        return "喵~哦~"

def animal_sound(animal): # 直接调用父类定义的方法, 参数传入的实例来选择不同执行.
    print(animal.speak())
my_dog = Dog() # 狗子
animal_sound(my_dog)  # 输出: 旺旺
my_cat = Cat() # 猫咪
animal_sound(my_cat)  # 输出: 喵~哦~

二、继续深入面向对象编程(OOP)

在掌握了 OOP 的基础概念后,我们可以进一步探讨一些更高级的主题,包括类的封装、类的组合、运算符重载和抽象类。


5. 封装

封装是 OOP 的一个核心原则,旨在将数据(属性)和操作数据的代码(方法)包装在一起,并控制对数据的访问。通过封装,可以隐藏对象的内部状态,只暴露必要的接口,增强代码的安全性和灵活性。

示例:使用封装
class BankAccount:
    def __init__(self, balance=0):
        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
        else:
            print("取款失败:余额不足或金额不合法。")
    # 获取余额
    def get_balance(self):
        return self.__balance  # 提供公共方法访问私有属性

my_account = BankAccount()
my_account.deposit(200) # 存入 +200
my_account.withdraw(50) # 取出 -50
print(my_account.get_balance())  # 输出: 150

解释

  • 使用 __balance 声明私有属性,外部无法直接访问, 硬访问会报错。
  • 通过公共方法(deposit, withdraw, get_balance)来操作和访问私有数据。

6. 类的组合

组合是另一种代码复用的方式,通过在一个类中包含其他类的对象来实现。这使得类的功能更加灵活。

示例:组合
class Engine: # 引擎
    def start(self):
        return "发动机启动"

class Car:
    def __init__(self):
        self.engine = Engine()  # Car 类包含 Engine 类的对象

    def start(self):
        return self.engine.start()  # 调用 Engine 的方法

my_car = Car()
print(my_car.start())  # 输出: 发动机启动

解释

  • Car 类包含 Engine 类的实例,利用组合实现更复杂的功能。

7. 运算符重载

运算符重载允许我们定义如何对自定义对象使用常规运算符(如 +, -, * 等)。这使得自定义对象可以像内置类型一样自然地使用。

示例:运算符重载
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)
result = v1 + v2  # 使用重载的 + 运算符
print(result)  # 输出: Vector(6, 8)

解释

  • + (加法) 通过重载 __add__ 方法,我们可以定义 Vector 对象如何相加。
  • -(减法):使用__sub__方法进行重载。比如实现两个自定义对象相减的操作。
  • *(乘法):通过__mul__方法实现乘法运算符的重载。
  • /(除法):定义__truediv__方法来重载除法运算符。
  • %(取模):可使用__mod__方法。
  • **(幂运算):借助__pow__方法。
  • +=-=*=/=等复合赋值运算符可以通过相应的算术运算符重载方法与__iadd____isub____imul____itruediv__等方法结合实现。
  • [0](索引操作):使用__getitem__、__setitem__和__delitem__方法分别实现对象的索引取值、赋值和删除操作。
class MyClass:
       def __init__(self):
           self.data = [1, 2, 3]
       def __getitem__(self, index):
           return self.data[index]
       def __setitem__(self, index, value):
           self.data[index] = value
myclass=MyClass ()

print(myclass[0]) # 1
myclass[2] = 5
print(myclass[2]) # 5

  • ()(函数调用):通过定义__call__方法,使得对象可以像函数一样被调用。
class Adder:
    def __init__(self, initial_value=0):
        self.value = initial_value

    def __call__(self, x):
        self.value += x
        return self.value

adder = Adder()
print(adder(5))  # 输出 5.
print(adder(3))  # 输出 8.

8. 抽象类与接口

抽象类是一种不能被实例化的类,通常用于定义接口和共通方法。子类必须实现这些方法,从而保证一定的接口一致性。

示例:抽象类
from abc import ABC, abstractmethod

class Animal(ABC):  # 抽象类
    @abstractmethod # 抽象方法
    def speak(self):
        pass  # 抽象方法,没有实现

class Dog(Animal):
    def speak(self):
        return "旺~旺~"

class Cat(Animal):
    def speak(self):
        return "喵~呜~"

# animal = Animal()  # 不能实例化抽象类
my_dog = Dog()
my_cat = Cat()
print(my_dog.speak())  # 输出: 旺~旺~
print(my_cat.speak())  # 输出: 喵~呜~

解释

  • Animal 是一个抽象类,定义了一个抽象方法 speak,强制所有子类实现该方法。
调用父类的方法

使用spuer()

   class Parent:
       def method(self):
           print("父")

   class Child(Parent):
       def method(self):
           super().method() # 调用父类方法
           print("子")

   c = Child()
   c.method() # 输出: 父
              #      子

三、继续深入面向对象编程(OOP)的实用技巧与模式

在进一步了解 OOP 的高级概念后,我们可以探索一些实用的设计模式、属性装饰器、类的静态方法和类方法等。


10. 常用设计模式

设计模式是解决特定问题的最佳实践,能够提升代码的可复用性和可维护性。以下是几种常用的设计模式。

10.1 单例模式

单例模式确保一个类只有一个实例,并提供全局访问点。

class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

# 测试单例
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # 输出: True

解释

  • __new__ 方法用于控制对象的实例化,确保每次调用返回同一个实例。
  • super(Singleton, cls).__new__(cls)调用了父类(在这里是object,因为如果没有显式指定父类,Python 中的类默认继承自object)的__new__方法来创建一个新的实例。如果cls._instance为None,就创建一个新实例并将其赋值给_instance;如果已经存在实例,就直接返回这个实例,从而保证了单例模式。
10.2 工厂模式

工厂模式用于创建对象的接口,允许子类决定实例化哪一个类。

class Shape: # 形状
    def draw(self):
        pass

class Circle(Shape): # 圆
    def draw(self):
        return "画出一个圆形"

class Square(Shape): # 方形
    def draw(self):
        return "画出一个方形"

class ShapeFactory: # 形状工厂
    @staticmethod # 静态方法, ShapeFactory.get_shape(...)
    def get_shape(shape_type):
        if shape_type == "圆形":
            return Circle()
        elif shape_type == "方形":
            return Square()
        return None

# 使用工厂模式
shape = ShapeFactory.get_shape("圆形")
print(shape.draw())  # 输出: 画出一个圆形

11. 属性装饰器

属性装饰器允许你定义 getter 和 setter 方法,从而在访问或修改属性时执行额外逻辑。

示例:使用 @property@setter
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property # 只读属性, print(实例.celsius)
    def celsius(self):
        return self._celsius

    @celsius.setter # 可修改属性: 实例.celsius=10
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value

temp = Temperature(25)
print(temp.celsius)  # 输出: 25
temp.celsius = 30    # 设置新温度
print(temp.celsius)  # 输出: 30
# temp.celsius = -300  # 触发异常

解释

  • @property 用于定义只读属性,@setter 用于定义可以修改的属性。

12. 静态方法和类方法

静态方法和类方法是与类关联的方法,但不需要实例化对象。

12.1 静态方法

静态方法不需要访问实例或类属性,可以直接通过类调用。

class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b

print(MathUtils.add(3, 5))  # 输出: 8
12.2 类方法

类方法接收类作为参数,可以访问类属性和其他类方法。

class MyClass:
    count = 0

    @classmethod
    def increment_count(cls):
        cls.count += 1

MyClass.increment_count()
print(MyClass.count)  # 输出: 1

解释

  • 静态方法不涉及类或实例,类方法可以访问和修改类属性。

13. 反射与动态属性

Python 允许动态添加属性和方法,可以使用 setattrgetattrhasattr 函数进行反射操作。

示例:动态属性
class Person:
    def __init__(self, name):
        self.name = name

person = Person("张三")
setattr(person, "age", 30)  # 动态添加属性
print(person.age)  # 输出: 30

# 反射检查属性, 是否存在属性
if hasattr(person, "name"):
    print(getattr(person, "name"))  # 输出: 张三

解释

  • 使用反射可以在运行时动态修改对象的属性和方法,增加灵活性。
  • getattr(object, name[, default]):用于获取对象的属性值。参数 object 是要获取属性的对象,name 是属性名,如果属性不存在且提供了 default 参数,则返回 default,否则会抛出 AttributeError 异常。
  • setattr(object, name, value):用于设置对象的属性值。参数含义与 getattr 类似,将对象 object 的属性 name 的值设置为 value。
  • hasattr(object, name):用于判断对象是否具有某个属性。返回 True 如果对象有指定的属性,否则返回 False。
  • callable(object):用于判断对象是否可调用(例如函数、方法等)。如果对象可调用,则返回 True,否则返回 False。
   def my_function():
       return "Hello, World!"

   print(callable(my_function))  # 输出 True

** 应用场景 **

  • 动态加载模块和对象:根据用户输入或配置文件动态地加载不同的模块和对象,以实现灵活的程序架构。
    假设有模块: hello_module.py
class MyClass:
    def __init__(self) : 
        self.a = 10
        print("Myclass create")
        pass

    def __str__(self):
       return "Myclass instace"

动态加载代码: app.py

module_name = "hello_module"
try:
    module = __import__(module_name) # 模块
    cls = getattr(module, "MyClass") # 获得模块中的类
    obj = cls() # 创建实例
    print(obj) # 
    print(dir(obj)) # 获得属性名、方法名们
except ImportError:
    print(f"Module {module_name} not found.")
  • 功能插件: 允许第三方开发者通过定义特定的接口来扩展程序的功能,而不需要修改程序的核心代码.
  • 自动化测试:通过反射可以动态地调用被测试对象的方法和属性,进行自动化测试。

总结

每日一记、开心一天.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值