Python教程(十二):面向对象高级编程详解

news2024/12/24 7:10:16

目录

    • 专栏列表
    • 前言
    • 变量命名规则说明:
    • 一、类的内部变量和特殊方法
      • 1.1 内部变量
        • 示例
        • 测试结果:
      • 1.2 `__slots__`
        • 未使用`__slots__`
        • 使用`__slots__`
    • 二、装饰器
      • 2.1 函数装饰器
        • 示例
      • 2.2 @property
        • 示例
    • 三、枚举类
      • 3.1 枚举类概述
      • 3.2 枚举类定义
        • 示例
    • 四、元类
      • 4.1 什么是元类
      • 4.2 自定义元类
        • 示例
    • 结语

专栏列表

  • Python教程(一):环境搭建及PyCharm安装
  • Python 教程(二):语法与数据结构
  • Python 教程(三):字符串特性大全
  • Python 教程(四):Python运算符合集
  • Python 教程(五):理解条件语句和循环结构
  • Python 教程(六):函数式编程
  • Python 教程(七):match…case 模式匹配
  • Python 教程(八):高级特性【高逼格代码】
  • Python 教程(九):内置模块与第三方模块
  • Python教程(十):面向对象编程(OOP)
  • Python教程(十一):单元测试与异常捕获

在这里插入图片描述

正文开始如果觉得文章对您有帮助,请帮我三连+订阅,谢谢💖💖💖


前言

在学习了Python的基本面向对象编程(OOP)概念之后,本篇文章将深入探讨Python中的高级OOP特性。这些特性包括类的内部变量、特殊方法(Magic Methods)、装饰器、枚举类以及元类。通过对这些高级特性的介绍和实例演示,帮助你更好地掌握Python的面向对象编程。

变量命名规则说明:

单下划线、双下划线、头尾双下划线

  • _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *

  • __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。

  • __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。

一、类的内部变量和特殊方法

1.1 内部变量

内部变量(Internal Variables)是指以双下划线开头(__)的变量,它们主要用于防止变量在子类中被意外覆盖。这种命名方式会触发Python的名称改写机制(Name Mangling),使变量名变得难以在类外部访问。

  • __init__ 的特殊方法(构造方法),在生成对象时调用,这个我们已经在前文介绍过了
  • __del__ : 析构函数,释放对象时使用
  • __repr__ : 打印,转换
  • __setitem__ : 按照索引赋值
  • __getitem__: 按照索引获取值
  • __len__: 获得长度
  • __cmp__: 比较运算
  • __call__: 函数调用
  • __add__: 加运算
  • __sub__: 减运算
  • __mul__: 乘运算
  • __truediv__: 除运算
  • __mod__: 求余运算
  • __pow__: 乘方
  • __str__:定义对象的字符串表示,print函数调用时使用。
示例

class Container:
    def __init__(self, *args):
        self.container = list(args)  # 初始化容器,接受可变数量的参数

    def __del__(self):
        print(f"对象 {id(self)} 正在被销毁。")

    def __repr__(self):
        return f"Container({self.container})"

    def __setitem__(self, key, value):
        self.container[key] = value  # 索引赋值

    def __getitem__(self, key):
        return self.container[key]  # 索引获取

    def __len__(self):
        return len(self.container)  # 获取容器长度

    def __cmp__(self, other):
        if not isinstance(other, Container):
            return NotImplemented
        return (self.container > other.container) - (self.container < other.container)

    def __call__(self, *args):
        print(f"Container 对象被调用,参数为:{args}")

    def __add__(self, other):
        if isinstance(other, Container):
            return Container(*(self.container + other.container)) # * 是用作解包操作,将list中的参数一个一个的传递,而不是传递一个list
        return NotImplemented

    def __sub__(self, other):
        if isinstance(other, Container):
            return Container(*(self.container[:-1] if len(self.container) >= len(other.container) else self.container))
        return NotImplemented

    def __mul__(self, other):
        if isinstance(other, int):
            return Container(*(self.container * other))
        return NotImplemented

    def __truediv__(self, other):
        if isinstance(other, int) and other != 0:
            return Container(*(x / other for x in self.container))
        return NotImplemented

    def __mod__(self, other):
        if isinstance(other, int):
            return Container(*(x % other for x in self.container))
        return NotImplemented

    def __pow__(self, power):
        return Container(*(x ** power for x in self.container))

    def __str__(self):
        return f"Container 对象: {self.container}"

# 测试代码
if __name__ == "__main__":
    c1 = Container(1, 2, 3)
    c2 = Container(4, 5)
    print(f"c1: {c1}")  # 使用 __str__
    print(f"c2: {c2}")

    c1[1] = 20  # 使用 __setitem__
    print(f"c1 修改后: {c1}")

    print(c1[1])  # 使用 __getitem__
    print(len(c1))  # 使用 __len__

    c3 = c1 + c2  # 使用 __add__
    print(f"c1 + c2: {c3}")

    c4 = c1 - c2  # 使用 __sub__
    print(f"c1 - c2: {c4}")

    c5 = c1 * 2  # 使用 __mul__
    print(f"c1 * 2: {c5}")

    c6 = c1 / 2  # 使用 __truediv__
    print(f"c1 / 2: {c6}")

    c7 = c1 % 3  # 使用 __mod__
    print(f"c1 % 3: {c7}")

    c8 = c1 ** 2  # 使用 __pow__
    print(f"c1 ** 2: {c8}")

    c1(123)  # 使用 __call__

测试结果:

在这里插入图片描述

1.2 __slots__

__slots__是一个特殊的类属性,用于控制类实例的动态属性的添加。默认情况下,Python的类是基于字典的,这意味着每个实例可以动态地添加任意数量的属性。但是,使用__slots__可以限制实例可以拥有的属性,只允许在__slots__中明确定义的属性。

使用__slots__有以下几个主要好处:

  1. 节省内存:通过限制属性的数量,可以减少内存的使用,因为不需要为每个实例创建一个字典来存储属性。
  2. 提高性能:访问预定义的属性比动态属性访问更快,因为预定义属性可以直接通过索引访问。
  3. 避免意外添加属性:使用__slots__可以确保类的实例不会意外地添加未定义的属性。
未使用__slots__
class Person:
    __init(self,*args)__:
      pass


# 创建 Student 类的实例
p = Person()
p.name = '子羽'  
print(p.name)

使用__slots__

在定义类时,你可以在类定义的顶部添加一个特殊的__slots__属性,其值为一个包含允许属性名的元组或列表。

class Student:
    __slots__ = ('name', 'age', 'grade')  # 只允许 name, age, grade 三个属性

# 创建 Student 类的实例
s = Student()
s.name = 'Alice'  # 正确,因为 'name' 在 __slots__ 中
s.age = 20        # 正确,因为 'age' 在 __slots__ 中
s.grade = 'A'    # 正确,因为 'grade' 在 __slots__ 中

# 尝试添加未在 __slots__ 中定义的属性
s.address = '123 Main St'  # 抛出 AttributeError

在上面的例子中,尝试给s添加一个不在__slots__列表中的属性address将会抛出AttributeError

二、装饰器

2.1 函数装饰器

装饰器是一个高阶函数,用于在不改变原函数代码的情况下,动态地增加功能。装饰器通常用于日志记录、性能测试、事务处理等。

示例

def my_decorator(func):
    def wrapper(world):
        print("日志记录开始.")
        func(world)
        print("日志记录结束")
    return wrapper

@my_decorator
def say_hello(world):
    print(f"Hello {world}!")

say_hello('子羽')

在这里插入图片描述

2.2 @property

@property 是 Python 中的一个装饰器,用于将一个方法转变为属性访问的形式。这使得你可以使用点符号(.)来访问一个方法,就像访问一个普通的属性一样。
@property 通常用于当你想要属性值的获取有特定的逻辑处理时,例如,当你需要在获取属性值之前进行验证或计算。

示例

使用 @property 非常简单,你只需要在方法前加上 @property 装饰器,然后在该方法内部定义获取属性值的逻辑。下面是一个简单的例子:

class Circle:
    def __init__(self, radius):
        self._radius = radius  # 私有属性,用来存储圆的半径

    @property
    def radius(self):
        """获取圆的半径"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """设置圆的半径,可以包含验证逻辑"""
        if value < 0:
            raise ValueError("半径不能为负数")
        self._radius = value

# 创建 Circle 类的实例
circle = Circle(5)

# 使用 @property 获取属性
print(circle.radius)  # 输出: 5

# 使用 @setter 设置属性
circle.radius = 10
print(circle.radius)  # 输出: 10

# 尝试设置非法的半径值
circle.radius = -1  # 抛出 ValueError

三、枚举类

3.1 枚举类概述

枚举(Enum)是一种特殊的类,用于表示一组相关的常量值。枚举类中的每个成员都是唯一的,可以使用名称或值进行访问。

3.2 枚举类定义

可以使用Python的 enum 模块定义枚举类。

示例
from enum import Enum, auto

class Color(Enum):
    RED = auto() # 默认从 1 开始
    GREEN = auto()
    BLUE = auto()
    YELLOW = 5
    purple = 6

print(Color.RED)  # 输出: Color.RED
print(Color.GREEN.name)  # 输出: GREEN
print(Color.GREEN.value)  # 输出: 2
print(Color.YELLOW.name)  # 输出: YELLOW
print(Color.YELLOW.value)  # 输出: 5

在这里插入图片描述

四、元类

4.1 什么是元类

元类(Metaclass)是用于创建类的类。默认情况下,Python中的所有类都是由 type 元类创建的。通过自定义元类,可以改变类的创建行为。

4.2 自定义元类

自定义元类需要继承自 type,并重写其方法,如 __new____init__

示例
class MyMeta(type):
    def __new__(cls, name, bases, dct):
        print(f"创建新类 :{name}")
        return super().__new__(cls, name, bases, dct)

    def __init__(cls, name, bases, dct):
        print(f"初始化类: {name}")
        super().__init__(name, bases, dct)

class MyClass(metaclass=MyMeta):
    def __init__(self):
        print("创建 Myclass 类的示例")

obj = MyClass()

在这里插入图片描述

结语

通过本篇文章,我们深入探讨了Python面向对象编程中的一些高级特性,包括类的内部变量、特殊方法、装饰器、枚举类和元类。这些高级特性能够帮助你编写更加灵活和强大的代码。如果你有任何疑问或想法,欢迎在评论区留言讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1992340.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

去除猫咪浮毛哪款更胜一筹?希喂、有哈宠物空气净化器测试对比

随着养宠人群的增多&#xff0c;宠物空气净化器受到铲屎官们的喜爱&#xff0c;成为家庭清洁的好帮手。然而&#xff0c;市场上的选择繁多&#xff0c;不少品牌以次充好&#xff0c;让人们掉入消费陷阱。为此&#xff0c;挑选一台优质有保障的宠物空气净化器品牌&#xff0c;需…

智界S7 小鹏P7 G3 G3i P5 G9 P7i G6 X9维修手册和电路图线路图接线资料更新

汽修帮手资料库提供各大厂家车型维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表位置等&#xff0c;并长期保持高频率资料更新&#xff01; 覆盖车型2020-2024年智界S7 小鹏…

不是智商税!六个核桃健脑效果获科学支持,效果源自七大方面

这两年来&#xff0c;关于脑雾、脑损伤的话题在社交媒体上越发受到关注&#xff0c;健脑也越发成为国民刚需。 不过&#xff0c;要做到科学健脑并不容易。有消费者选择专业保健品补剂&#xff0c;也有消费者倾向于食补。中国饮食传统中就有核桃补脑的说法&#xff0c;但不少人…

Untiy Modbus 西门子 S7-1200 基础通信

Untiy Modbus 西门子 S7-1200 基础通信 ModbusModbus是什么Modbus 协议版本Modbus 通信和设备Modbus 如何实现Modbus 使用限制Modbus 通信协议学理上的弱点分析 UnityUnity ModbusTCPUnity ModbusTCP 单个线圈读取方法Unity ModbusTCP 单个线圈写入方法 IntUnity ModbusTCP 单个…

Android 让程序随系统自动启动并允许后台运行(白名单)

最近制作一个管理程序&#xff0c;需要在开机时候启动&#xff0c;并持续运行。这里简单记录下如何制作。 自启动原理 系统在启动的时候会广播一个ACTION_BOOT_COMPLETED&#xff0c;带有接收的程序可以收到&#xff0c;所以我们在接收到以后把程序运行起来。 清单文件设置 …

PyMysql快速上手操作详解

PyMySQL是从Python连接到MySQL数据库服务器的接口。 它实现了Python数据库API v2.0&#xff0c;并包含一个纯Python的MySQL客户端库 一、PyMysql安装 pip install pymysql 或者 pip3 install pymysql二、连接数据库 pymysql连接数据库使用的是 pymsql.connect() 函数&#xff…

数据库设计笔记3-事务管理,冲突串行化,锁定协议,死锁测试

#1.指令冲突 注&#xff1a;读读操作不冲突&#xff0c;剩下的冲突。 #2.冲突串行化 <1理解 如果一个调度可以在不改变冲突操作顺序的情况转换为任意串行调度&#xff0c;那么两个调度的结果是相同的&#xff0c;也就是说这个调度是可冲突串行化的 <2正反举例 <3测…

【教师秘籍】AI预测学生未来?职场规划大揭秘!

​声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/2150.html 嘿老师们&#xff0c;你们有没有和我一样的烦恼&#xff1a;学生各有千秋&#xff0c;家长各有各的操心&#xff0c;信息一箩筐却总是不够用&#xff1f;&am…

基于JAVA的校园跑腿网站的设计与实现

摘要 随着计算机技术&#xff0c;网络技术的迅猛发展&#xff0c;Internet 的不断普及&#xff0c;网络在各个领域里发挥了越来越重要的作用。特别是随着近年人民生活水平不断提高&#xff0c;校园跑腿网站给学校的业务带来了更大的发展机遇。 在经济快速发展的带动下&#xff…

[NPUCTF2020]ReadlezPHP1

打开题目&#xff0c;看到信息 ctrlu查看源代码 看到php代码&#xff0c;打开 代码审计看一下&#xff0c;进行代码审计&#xff0c;发现存在反序列化语句&#xff1a;$ppp unserialize($_GET["data"]);和执行漏洞&#xff1a;echo $b($a);&#xff0c;此处未想到fl…

荟萃科技:海外问卷调查项目可以长期做不?

当然可以&#xff01; 我已经做了两年多的海外问卷调查了&#xff0c;我觉得还是蛮有发言权的。 现在网络飞速发展&#xff0c;实体的生意也越来越来越不好做了&#xff0c;有人就把目标转移到了网络上&#xff0c;想知道一些其他的网络项目能不能做&#xff0c;如果能找到一…

【可控图像生成系列论文(六)】ECCV24-Glyph-ByT5 微软亚研院、清华、北大合作工作(上)

系列文章目录 【可控图像生成系列论文&#xff08;一&#xff09;】 简要介绍了 MimicBrush 的整体流程和方法&#xff1b;【可控图像生成系列论文&#xff08;二&#xff09;】 就 MimicBrush 的具体模型结构、训练数据和纹理迁移进行了更详细的介绍。【可控图像生成系列论文…

提示词工程学的前世今生:Generative Pre-trained Transformer 到AIGC,再到Prompt Engineering

人工智能&#xff08;Artificial intelligence&#xff0c;AI&#xff09;的演进已然变革了我们对于技术的理解以及应用方式。自最初的规则系统直至当下的深度学习&#xff0c;AI 在众多领域均彰显出了极为巨大的潜力。当中&#xff0c;生成式预训练模型&#xff08;Generative…

浮毛烦恼不复存在!不容错过的养宠好物——宠物空气净化器

猫咪一年有两次换毛季&#xff0c;多集中在春夏和秋冬&#xff0c;尤其是在春季&#xff0c;换毛时长可以达到一个月之久。在此期间。猫咪会疯狂掉毛&#xff0c;需要铲屎官们在此期间做好相关措施&#xff0c;让猫咪顺利度过换毛季。其中&#xff0c;最重要的就是猫毛清理&…

PLC远程控制网关再也不用劳累出差

在当今快速发展的工业4.0时代&#xff0c;随着智能制造与物联网技术的深度融合&#xff0c;工厂自动化系统的远程监控与管理已成为提高生产效率、优化资源配置的关键。其中&#xff0c;可编程逻辑控制器&#xff08;PLC&#xff09;作为工业控制的核心部件&#xff0c;其远程控…

Retrofit 自定义注解 实现可选择性的打印接口日志

序言 有时候我们需要打印okhttp的日志&#xff0c;但是现在的日志拦截器&#xff0c;不能做到接口级别的日志输出控制。要么就是全部打印。这样很影响调试效率。所以我在这块做了一些探索。 使用效果 普通输出 只需要在要打印日志的接口上添加 PrintLog 注解就可以打印&…

奥运足球背后的中国小公司

有一家中国的小公司叫做顶碁运动&#xff0c;居然打败了耐克和阿迪达斯这样的巨头&#xff0c;成功地成为了现在巴黎奥运会的足球供应商。 顶碁运动研发的足球&#xff0c;最大的优点就是能够在一秒钟之内精准地识别500次。因为他们在足球的内胆里面装置了芯片和传感器&#xf…

【Linux】:进程控制1(创建、终止、等待)

目录 1.进程创建 2.进程终止&#xff08;退出&#xff09; 2.1 什么是进程终止 2.2 进程退出的场景&#xff08;原因&#xff09; 2.3 进程退出码 2.4 错误码errno 2.5 进程常见的退出方法 正常终止 从main函数返回 调用库函数exit 系统接口_exit 3.进程等待 3.1 …

[qt] 多线程应用02

源码: 点击此处 一 UI 1.1 效果 1.2 代码 首先定义一系列的控件和按钮&#xff0c;用来显示Tcp连接数据信息。 QLabel *m_serverNameLabel;QLineEdit *m_serverLineEdit;QLabel *m_portLabel;QLineEdit *m_portLineEdit;QDateTimeEdit *m_d…

【书生大模型实战营第三期】基础岛 第3关 浦语提示词工程实践

欢迎大家参与第三期书生大模型实战营&#xff01;&#xff01;&#xff01; 1. 基础任务 背景问题&#xff1a;近期相关研究发现&#xff0c;LLM 在对比浮点数字时表现不佳&#xff0c;经验证&#xff0c;internlm2-chat-1.8b&#xff08;internlm2-chat-7b&#xff09;也存在这…