8.2 面向对象


文章目录

  • 前言
  • 一、简介
  • 二、基本操作
    • [2.1 类的定义](#2.1 类的定义)
    • [2.2 类的基本示例](#2.2 类的基本示例)
    • [2.3 访问属性和方法](#2.3 访问属性和方法)
    • [2.4 私有属性和方法](#2.4 私有属性和方法)
    • [2.5 继承](#2.5 继承)
    • [2.6 方法重写和扩展](#2.6 方法重写和扩展)
    • [2.7 特殊方法(魔术方法)](#2.7 特殊方法(魔术方法))
    • [2.8 属性装饰器](#2.8 属性装饰器)
  • 三、面向对象编程的优势

前言

本文主要介绍了面向对象编程的基本概念和三大特性。


一、简介

面向对象编程(OOP)是一种对现实世界进行理解和抽象的编程范式。在面向对象的思想中,一切皆对象。Python 是一门支持面向对象的语言,面向对象编程本质上是一种封装代码的方式,使代码更易于维护、扩展和复用。

  1. 面向对象相关概念
  • 类:描述具有相同属性和方法的对象的集合,是一个创建对象的模板。
  • 对象:类的实例化结果。
  • 方法:类中定义的函数。
  • 类变量:定义在类中且在方法之外的变量,在所有实例化对象中共享。
  • 实例变量:每个对象独有的变量。
  • 局部变量:方法中定义的变量,只在方法内有效。
  1. 面向对象三大特性
  • 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,提高复用性和安全性。
  • 继承:一个类继承基类便可拥有基类的属性和方法,提高代码复用性。
  • 多态:父类定义的引用变量可以指向子类的实例对象,提高程序扩展性。

二、基本操作

2.1 类的定义

Python 中使用 class 关键字定义类,基本语法如下:

python 复制代码
python
class 类名:
    # 类变量(类属性)
    类变量名 = 值
    
    # 构造方法
    def __init__(self, 参数):
        # 实例变量(实例属性)
        self.实例变量名 = 值
    
    # 实例方法
    def 方法名(self, 参数):
        # 方法体
        pass
    
    # 类方法
    @classmethod
    def 类方法名(cls, 参数):
        pass
    
    # 静态方法
    @staticmethod
    def 静态方法名(参数):
        pass

2.2 类的基本示例

python 复制代码
python
class Cat:
    """猫类"""
    
    # 类变量 - 所有猫共享的属性
    species = 'Felis catus'  # 物种
    count = 0  # 统计创建的猫的数量
    
    # 构造方法 - 在创建对象时自动调用
    def __init__(self, name, age=1):
        """
        初始化猫对象
        :param name: 猫的名字
        :param age: 猫的年龄,默认为1
        """
        # 实例变量 - 每个猫独有的属性
        self.name = name  # 名字
        self.age = age    # 年龄
        self.__weight = 2.5  # 私有属性:体重(kg)
        
        # 每创建一个猫,计数器加1
        Cat.count += 1
    
    # 实例方法 - 第一个参数必须是self
    def eat(self, food):
        """猫吃东西的方法"""
        self.food = food  # 设置食物属性
        print(f'{self.name}正在吃{food}')
        self.__weight += 0.1  # 吃完体重增加
        return f'{self.name}吃完了{food}'
    
    def meow(self):
        """猫叫的方法"""
        return f'{self.name}说:喵喵~'
    
    def get_weight(self):
        """获取体重(公有方法访问私有属性)"""
        return f'{self.name}的体重是{self.__weight}kg'
    
    def set_weight(self, weight):
        """设置体重(公有方法修改私有属性)"""
        if weight > 0:
            self.__weight = weight
            return f'设置成功,当前体重{self.__weight}kg'
        else:
            return '体重必须大于0'
    
    # 类方法 - 第一个参数必须是cls
    @classmethod
    def get_species(cls):
        """获取物种信息"""
        return f'所有猫都属于物种:{cls.species}'
    
    @classmethod
    def create_baby_cat(cls, name):
        """创建一个刚出生的猫"""
        return cls(name, age=0)
    
    # 静态方法 - 不需要self或cls参数
    @staticmethod
    def animal_info():
        """提供猫科动物的静态信息"""
        return '猫科动物(Felidae)是哺乳纲食肉目的一科'

2.3 访问属性和方法

python 复制代码
python
# 1. 访问类变量(不需要创建对象)
print('=' * 50)
print('类变量访问:')
print(f'猫的物种:{Cat.species}')
print(f'已创建的猫数量:{Cat.count}')

# 2. 创建对象(实例化)
print('\n' + '=' * 50)
print('创建对象:')
cat1 = Cat('Tom', 3)  # 创建名为Tom的3岁猫
cat2 = Cat('Kitty')   # 创建名为Kitty的猫(使用默认年龄1岁)

print(f'已创建的猫数量:{Cat.count}')  # 应该显示2

# 3. 访问实例属性和方法
print('\n' + '=' * 50)
print('实例属性和方法:')

# 访问实例属性
print(f'猫1的名字:{cat1.name}')
print(f'猫1的年龄:{cat1.age}')

# 调用实例方法
result = cat1.eat('鱼')
print(result)
print(cat1.meow())

# 4. 访问类方法
print('\n' + '=' * 50)
print('类方法:')
print(Cat.get_species())  # 通过类名访问
print(cat1.get_species())  # 通过对象访问

# 5. 访问静态方法
print('\n' + '=' * 50)
print('静态方法:')
print(Cat.animal_info())

# 6. 使用类方法创建对象
print('\n' + '=' * 50)
print('使用类方法创建对象:')
baby_cat = Cat.create_baby_cat('Baby')
print(f'新生猫的名字:{baby_cat.name}')
print(f'新生猫的年龄:{baby_cat.age}')

2.4 私有属性和方法

Python 中通过在属性或方法名前加双下划线 __ 来定义私有成员,外部不能直接访问:

python 复制代码
python
class BankAccount:
    """银行账户类"""
    
    def __init__(self, owner, initial_balance=0):
        self.owner = owner  # 公有属性:账户持有人
        self.__balance = initial_balance  # 私有属性:余额
        self.__password = '123456'  # 私有属性:密码
    
    def __verify_password(self, password):
        """私有方法:验证密码"""
        return password == self.__password
    
    def deposit(self, amount, password):
        """存款方法"""
        if not self.__verify_password(password):
            return '密码错误,存款失败'
        
        if amount > 0:
            self.__balance += amount
            return f'存款成功!当前余额:{self.__balance}元'
        else:
            return '存款金额必须大于0'
    
    def withdraw(self, amount, password):
        """取款方法"""
        if not self.__verify_password(password):
            return '密码错误,取款失败'
        
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            return f'取款成功!当前余额:{self.__balance}元'
        else:
            return '余额不足或金额无效'
    
    def get_balance(self, password):
        """查询余额"""
        if not self.__verify_password(password):
            return '密码错误,无法查询'
        return f'当前余额:{self.__balance}元'

# 使用示例
print('=' * 50)
print('银行账户示例:')

account = BankAccount('张三', 1000)
print(f'账户持有人:{account.owner}')

# 正确的方式访问私有属性
print(account.deposit(500, '123456'))  # 密码正确
print(account.withdraw(300, '123456'))  # 密码正确
print(account.get_balance('123456'))  # 密码正确

# 错误的方式(会报错或无法访问)
try:
    print(account.__balance)  # 报错:AttributeError
except AttributeError as e:
    print(f'错误:{e}')

try:
    account.__verify_password('123456')  # 报错:AttributeError
except AttributeError as e:
    print(f'错误:{e}')

2.5 继承

Python 支持单继承和多继承:

python 复制代码
python
# 基类(父类)
class Animal:
    """动物基类"""
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self, food):
        return f'{self.name}正在吃{food}'
    
    def sleep(self):
        return f'{self.name}正在睡觉'
    
    def make_sound(self):
        return '动物发出声音'

# 单继承
class Dog(Animal):
    """狗类 - 继承自动物类"""
    
    def __init__(self, name, age, breed):
        # 调用父类的构造方法
        super().__init__(name, age)
        # 添加狗特有的属性
        self.breed = breed  # 品种
        self.__loyalty = 100  # 私有属性:忠诚度
    
    # 重写父类方法
    def make_sound(self):
        return f'{self.name}汪汪叫!'
    
    # 添加子类特有的方法
    def fetch(self, item):
        return f'{self.name}正在捡{item}'
    
    def guard(self):
        self.__loyalty += 10
        return f'{self.name}正在看家,忠诚度提升到{self.__loyalty}'

# 单继承示例
print('=' * 50)
print('单继承示例:')

dog = Dog('旺财', 3, '金毛')
print(dog.eat('骨头'))  # 继承自父类的方法
print(dog.sleep())      # 继承自父类的方法
print(dog.make_sound()) # 重写后的方法
print(dog.fetch('飞盘')) # 子类特有的方法
print(dog.guard())      # 子类特有的方法
print(f'品种:{dog.breed}')  # 子类特有的属性

# 多继承
class Flyable:
    """可飞行的能力"""
    
    def __init__(self, max_height):
        self.max_height = max_height
    
    def fly(self):
        return f'最高可飞到{self.max_height}米'

class Swimmable:
    """可游泳的能力"""
    
    def swim(self):
        return '在水中游泳'

class Duck(Animal, Flyable, Swimmable):
    """鸭子类 - 多重继承"""
    
    def __init__(self, name, age, max_height=100):
        # 调用Animal的构造方法
        Animal.__init__(self, name, age)
        # 调用Flyable的构造方法
        Flyable.__init__(self, max_height)
        # 不需要调用Swimmable的构造方法(它没有__init__)
    
    def make_sound(self):
        return f'{self.name}嘎嘎叫!'
    
    def all_abilities(self):
        """展示所有能力"""
        abilities = [
            self.make_sound(),
            self.eat('虫子'),
            self.fly(),
            self.swim()
        ]
        return abilities

# 多继承示例
print('\n' + '=' * 50)
print('多继承示例:')

duck = Duck('唐老鸭', 2, 50)
print(duck.make_sound())  # 重写的方法
print(duck.eat('小鱼'))    # 继承自Animal
print(duck.fly())         # 继承自Flyable
print(duck.swim())        # 继承自Swimmable

print('\n展示所有能力:')
for ability in duck.all_abilities():
    print(f'- {ability}')

# 方法解析顺序(MRO)
print('\n方法解析顺序:')
print(Duck.__mro__)  # 显示类的继承顺序

2.6 方法重写和扩展

python 复制代码
python
class Vehicle:
    """交通工具基类"""
    
    def __init__(self, brand, model, speed=0):
        self.brand = brand
        self.model = model
        self.speed = speed
    
    def start(self):
        return f'{self.brand} {self.model}启动'
    
    def stop(self):
        self.speed = 0
        return f'{self.brand} {self.model}停止'
    
    def get_info(self):
        return f'品牌:{self.brand},型号:{self.model},当前速度:{self.speed}km/h'

class Car(Vehicle):
    """汽车类"""
    
    def __init__(self, brand, model, fuel_type):
        super().__init__(brand, model)
        self.fuel_type = fuel_type  # 燃料类型
        self.__fuel_level = 100     # 私有属性:油量
    
    # 扩展父类方法而不是完全重写
    def start(self):
        if self.__fuel_level > 0:
            result = super().start()  # 调用父类的start方法
            return f'{result},油量:{self.__fuel_level}%'
        else:
            return '油量不足,无法启动'
    
    # 重写父类方法
    def get_info(self):
        # 先获取父类的信息
        base_info = super().get_info()
        # 添加子类的信息
        return f'{base_info},燃料类型:{self.fuel_type},油量:{self.__fuel_level}%'
    
    # 添加子类特有的方法
    def refuel(self, amount):
        if amount > 0:
            self.__fuel_level = min(100, self.__fuel_level + amount)
            return f'加油成功,当前油量:{self.__fuel_level}%'
        return '加油量无效'

# 方法重写和扩展示例
print('=' * 50)
print('方法重写和扩展示例:')

car = Car('Toyota', 'Camry', '汽油')
print(car.start())
print(car.get_info())
print(car.refuel(30))

2.7 特殊方法(魔术方法)

python 复制代码
python
class Student:
    """学生类 - 演示特殊方法"""
    
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    # 字符串表示方法
    def __str__(self):
        return f'学生:{self.name},分数:{self.score}'
    
    def __repr__(self):
        return f'Student("{self.name}", {self.score})'
    
    # 比较运算符重载
    def __eq__(self, other):
        if isinstance(other, Student):
            return self.score == other.score
        return False
    
    def __lt__(self, other):
        if isinstance(other, Student):
            return self.score < other.score
        return NotImplemented
    
    def __gt__(self, other):
        if isinstance(other, Student):
            return self.score > other.score
        return NotImplemented
    
    # 算术运算符重载
    def __add__(self, other):
        if isinstance(other, (int, float)):
            return Student(self.name, self.score + other)
        return NotImplemented
    
    # 调用对象时执行的方法
    def __call__(self):
        return f'{self.name}被调用啦!'

# 特殊方法示例
print('=' * 50)
print('特殊方法示例:')

s1 = Student('小明', 90)
s2 = Student('小红', 85)

print(str(s1))      # 调用__str__
print(repr(s1))     # 调用__repr__
print(s1 == s2)     # 调用__eq__
print(s1 > s2)      # 调用__gt__
print(s1 < s2)      # 调用__lt__

s3 = s1 + 5         # 调用__add__
print(s3)

print(s1())         # 调用__call__

2.8 属性装饰器

python 复制代码
python
class Person:
    """人类 - 演示属性装饰器"""
    
    def __init__(self, name, age):
        self._name = name  # 受保护的属性
        self._age = age
    
    @property
    def name(self):
        """获取name属性"""
        return self._name
    
    @name.setter
    def name(self, value):
        """设置name属性"""
        if not value or not value.strip():
            raise ValueError("姓名不能为空")
        self._name = value.strip()
    
    @property
    def age(self):
        """获取age属性"""
        return self._age
    
    @age.setter
    def age(self, value):
        """设置age属性"""
        if not isinstance(value, int):
            raise TypeError("年龄必须是整数")
        if value < 0 or value > 150:
            raise ValueError("年龄必须在0-150之间")
        self._age = value
    
    @property
    def info(self):
        """只读属性"""
        return f'{self._name},{self._age}岁'

# 属性装饰器示例
print('=' * 50)
print('属性装饰器示例:')

person = Person('张三', 25)
print(person.name)   # 使用property访问
print(person.age)    # 使用property访问
print(person.info)   # 只读属性

person.name = '李四'  # 使用setter设置
person.age = 30      # 使用setter设置
print(person.info)

try:
    person.name = ''  # 会触发验证错误
except ValueError as e:
    print(f'错误:{e}')

try:
    person.age = 200  # 会触发验证错误
except ValueError as e:
    print(f'错误:{e}')

三、面向对象编程的优势

  • 代码复用:通过继承可以复用已有代码 模块化:将相关功能封装在类中,使代码结构更清晰
  • 易维护:修改一个类的实现不会影响其他代码
  • 可扩展:通过继承和多态轻松扩展功能 数据安全:通过封装保护数据,防止意外修改
  • 通过合理使用面向对象编程,可以创建更健壮、更易维护的Python应用程序。

相关推荐
小小星球之旅2 小时前
CompletableFuture学习
java·开发语言·学习
蹦蹦跳跳真可爱5892 小时前
Python----大模型(GPT-2模型训练加速,训练策略)
人工智能·pytorch·python·gpt·embedding
xwill*2 小时前
π∗0.6: a VLA That Learns From Experience
人工智能·pytorch·python
kylezhao20193 小时前
C# 语言基础(变量、数据类型、流程控制、面向对象编程)
开发语言·计算机视觉·c#·visionpro
还不秃顶的计科生3 小时前
LeetCode 热题 100第二题:字母易位词分组python版本
linux·python·leetcode
咯哦哦哦哦3 小时前
WSL + ubantu22.04 + 远程桌面闪退+黑屏闪退解决
linux·开发语言
翩若惊鸿_3 小时前
【无标题】
开发语言·c#
weixin_462446233 小时前
exo + tinygrad:Linux 节点设备能力自动探测(NVIDIA / AMD / CPU 安全兜底)
linux·运维·python·安全
不瘦80斤不改名3 小时前
Python 日志(logging)全解析
服务器·python·php