Python面向对象

Henry Lv3

  • 创建类和其中的函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class Person:
    # 默认初始化方法
    def __init__(self):
    self.name = ''
    self.age = 0
    # 定义打印方法
    def display(self):
    print("Person({name}, {age})" .format(name = self.name,age = self.age))
    # 重写对象生成字符串方法
    def __str__(self):
    return "Person(%s, %d)" % (self.name, self.age)
    # 重写默认表示
    def __repr__(self):
    return str(self)
    # 简化打印方法
    def display_simple(self):
    print(self)

    p = Person()
    p.name = 'Bob'
    p.age = 30
    # p.display()
    # p.__str__()
    str(p)
    # p
    # p.display_simple()
  • 类的初始化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Person:
    # 带参数的初始化方法
    def __init__(self, name, age):
    self.name = name
    self.age = age
    # 重写对象生成字符串方法
    def __str__(self):
    return "Person(%s, %d)" % (self.name, self.age)
    # 重写默认表示
    def __repr__(self):
    return str(self)

    # 初始化Person对象
    p = Person('Bob', 30)
    p
  • 函数修饰器
  1. @property:将 方法 转换成 属性,可以使用属性访问语法来调用方法,保持了接口的统一性和简洁性。访问属性格式:obj.属性名
  2. @属性名.setter:必须在property定义之后声明。设置属性格式:obj.属性名 = 值
  3. @属性名.deleter:删除属性格式:del obj.属性名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    # 不使用@property修饰器时,获取属性和设置属性写法:
    class TemperatureWithoutProperty:
    def __init__(self, celsius=0):
    self._celsius = celsius

    def get_celsius(self):
    """获取摄氏温度"""
    print(f"获取摄氏温度: {self._celsius}°C")
    return self._celsius

    def set_celsius(self, value):
    """设置摄氏温度(带验证)"""
    if value < -273.15:
    print("错误:温度不能低于绝对零度(-273.15°C)")
    raise ValueError("温度不能低于绝对零度")
    print(f"设置摄氏温度: {value}°C")
    self._celsius = value

    temp1 = TemperatureWithoutProperty(25)
    print(f"初始温度: {temp1.get_celsius()}°C")

    temp1.set_celsius(30)
    print(f"新的摄氏温度: {temp1.get_celsius()}°C")

    try:
    temp1.set_celsius(-300)
    except ValueError as e:
    print(f"捕获错误: {e}")


    # 使用@property修饰器时,获取属性和设置属性写法:
    class TemperatureWithProperty:
    def __init__(self, celsius=0):
    self._celsius = celsius

    @property
    def celsius(self):
    """摄氏温度属性getter"""
    print(f"[getter] 获取摄氏温度: {self._celsius}°C")
    return self._celsius

    @celsius.setter
    def celsius(self, value):
    """摄氏温度属性setter"""
    if value < -273.15:
    print(f"[setter] 错误:温度不能低于绝对零度(-273.15°C)")
    raise ValueError("温度不能低于绝对零度")
    print(f"[setter] 设置摄氏温度: {value}°C")
    self._celsius = value

    temp2 = TemperatureWithProperty(25)
    print(f"初始温度: {temp2.celsius}°C")

    temp2.celsius=30
    print(f"新的摄氏温度: {temp2.celsius}°C")

    try:
    temp2.celsius = -300
    except ValueError as e:
    print(f"捕获错误: {e}")
  • 私有变量:使用单下划线开头的是保护变量/方法,约定俗成认为该变量应避免外部访问;使用双下划线开头的是私有变量/方法,外部不能直接访问或修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class TemperatureWithProperty:
    def __init__(self, celsius=0):
    self.__celsius = celsius

    @property
    def celsius(self):
    """摄氏温度属性getter"""
    print(f"[getter] 获取摄氏温度: {self.__celsius}°C")
    return self.__celsius

    @celsius.setter
    def celsius(self, value):
    """摄氏温度属性setter"""
    if value < -273.15:
    print(f"[setter] 错误:温度不能低于绝对零度(-273.15°C)")
    raise ValueError("温度不能低于绝对零度")
    print(f"[setter] 设置摄氏温度: {value}°C")
    self.__celsius = value
    def __private_method(self):
    print('这是私有方法')

    p = TemperatureWithProperty(25)
    # print(p.__celsius) # 直接访问双下划线的变量会报错

    p.__celsius = 5000 # 虽然双下划线开头的变量可以赋值,但是并不影响对象中的保护变量的值
    print(p.__celsius)
    # 5000
    print(p.celsius)
    # 25
    # p.__private_method() # 调用私有方法会报没有此方法
  • 继承:可以单继承,也可以多继承。使用super()调用父类方法。尽量使用组合而不是多继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 单继承
    # 定义玩家
    class Player():
    def __init__(self, name):
    self._name = name
    self._score = 0
    def incr_score(self):
    self._score = self._score + 1
    def __str__(self):
    return "name = %s, score = %d" % (self._name, self._score)
    def __repr__(self):
    return "Player(%s)" % str(self)
    # 人继承玩家
    class Human(Player):
    pass

    h = Human('Jack')
    print(h)
    h.incr_score()
    print(h)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    # 多继承
    class A:
    def method(self):
    print("A")

    class B(A):
    def method(self):
    print("B")
    super().method()

    class C(A):
    def method(self):
    print("C")
    super().method()
    # D多继承B和C
    class D(B, C):
    def method(self):
    print("D")
    super().method()

    print("\n" + "=" * 50)
    print("最终测试:预测输出顺序")
    print("=" * 50)

    d = D()
    d.method()
    print(D.__mro__) # 获取继承方法解析顺序
    print("D的MRO:", [cls.__name__ for cls in D.__mro__])

    ==================================================
    最终测试:预测输出顺序
    ==================================================
    D
    B
    C
    A
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    D的MRO: ['D', 'B', 'C', 'A', 'object']
  • 组合:允许一个类包含另一个类的实例作为自己的属性。以汽车继承交通工具为例,组合中汽车有交通工具中的引擎。可以降低耦合度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    # ============================================
    # 最简单的组合Demo:电脑由组件组成
    # 核心思想:电脑 "有" 组件,而不是电脑 "是" 组件
    # ============================================

    # 1. 定义组件类
    class CPU:
    """CPU组件"""
    def __init__(self, brand, cores):
    self.brand = brand
    self.cores = cores

    def process(self):
    return f"{self.brand} CPU正在处理,{self.cores}核"

    class Memory:
    """内存组件"""
    def __init__(self, size):
    self.size = size

    def load_data(self):
    return f"加载数据到 {self.size}GB 内存"

    class HardDrive:
    """硬盘组件"""
    def __init__(self, capacity):
    self.capacity = capacity

    def store_data(self):
    return f"存储数据到 {self.capacity}GB 硬盘"

    # 2. 定义电脑类 - 使用组合
    class Computer:
    """电脑类 - 由组件组合而成"""
    def __init__(self):
    # 组合:电脑有CPU、内存、硬盘
    self.cpu = CPU("Intel", 8) # 创建CPU实例
    self.memory = Memory(16) # 创建内存实例
    self.hard_drive = HardDrive(512) # 创建硬盘实例

    def power_on(self):
    """开机"""
    print("正在开机...")
    print(f"1. {self.cpu.process()}") # 调用CPU组件方法
    print(f"2. {self.memory.load_data()}") # 调用内存组件方法
    print(f"3. {self.hard_drive.store_data()}") # 调用硬盘组件方法
    print("电脑启动完成!")

    # 3. 使用电脑
    print("=" * 40)
    print("组合示例:电脑由组件组成")
    print("=" * 40)

    # 创建电脑对象
    my_computer = Computer()

    # 使用电脑功能
    my_computer.power_on()

    # 可以直接访问和操作组件
    print(f"\n电脑组件详情:")
    print(f"- CPU: {my_computer.cpu.brand} {my_computer.cpu.cores}核")
    print(f"- 内存: {my_computer.memory.size}GB")
    print(f"- 硬盘: {my_computer.hard_drive.capacity}GB")

    # 也可以单独使用组件
    print(f"\n单独使用CPU组件:")
    cpu_only = CPU("AMD", 12)
    print(cpu_only.process())
  • 重写:要求方法名和参数数量(默认参数除外)相同,可以使用super()调用父类方法。(python支持重写,但不支持重载,如果子类中的函数名与父类中的相同,但参数不同,则会覆盖父类中的函数。在一个类中有多个名称相同的函数,则以最后一个函数为准)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Payment:
    # ✅ 设置参数数据类型
    def pay(self, amount: int):
    self.amount = amount
    print(f"支付%d元" % self.get_money())

    # ✅ 指定函数返回数据类型
    def get_money(self) -> int:
    return self.amount

    class CreditCardPayment(Payment):
    # ✅ 可以添加默认参数,不影响原有调用
    def pay(self, amount, card_type="Visa"):
    print(f"使用{card_type}信用卡支付 {amount} 元")
    super().pay(amount) # 调用父类方法

    # 测试
    payment = CreditCardPayment()
    payment.pay(100) # ✅ 可以调用,使用默认参数
    payment.pay(200, "MasterCard") # ✅ 也可以传入新参数
  • 封装

    • 使用@property + 私有变量 = 最佳封装实践
    • 根据类创建对象
    • 获取对象的属性
    • 查看类的父类
    • 通过对象动态添加类的属性
    • 修改属性
    • self的用法
    • init()初始化
  • 多态

    • 不同子类对象调用相同父类方法,产生不同的执行效果,可以增加代码的灵活性
    • 前提:继承+重写父类的方法
    • 定义

文件操作

  • 异常
    • 定义
    • 有异常不会影响下面代码执行
    • 常用Exception类、else、finally
  • 模块
    • 定义:就是一个.py文件
    • 通过import 模块名
    • 通过from 模块名 import 方法名/对象名
    • 模块别名 form 模块名 import 方法名 as 别名
  • 文件读写
    • 打开文件
    • 读/写
    • 关闭文件
  • 打开方式
    - r:只读,文件不存在会报异常
    - w:只写,覆盖原文件,文件不存在则创建。
    - encoding:指定编码格式,win写入需要指定格式,默认格式为cp936->GBK
    - 注意:文件被打开之后,多次写入数据不会覆盖之前的数据
    - a:追加写入

    • b:二进制形式
      • 注意:二进制模式下不需要添加encoding参数
      • rb:二进制方式打开文件用于只读;
        • 对二进制的数据斤进行解码操作,将bytes类型转换为str类型
        • 将str转换为bytes类型
      • rw:二进制方式打开一个文件用于只写

匿名函数

  • 定义:函数没有名字,用lambda关键字进行定义
  • 创建

常用python包

  • PIL:图像处理
  • Tkinter: Python GUI
  • Django:交互式网站
  • Bottle:小型交互式网站
  • Pygame:2D动画
  • SciPy:科学计算
  • Twisted:网络编程
  • PyPI:Python索引包
  • 标题: Python面向对象
  • 作者: Henry
  • 创建于 : 2025-12-30 15:44:50
  • 更新于 : 2026-01-06 16:53:22
  • 链接: https://mybetterworks.github.io/2025/12/30/Python面向对象/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论