在Python中,单下划线“_”和双下划线“__”的使用场景和含义有显著区别,主要体现在命名约定语法

一、单下划线“_”的使用场景

单下划线更多是编程约定(而非强制语法),用于传递特定的“暗示”,不影响代码的实际运行。

1. 作为临时变量/占位符

用于表示“临时”或“无关紧要”的变量,仅作为语法占位,无需实际使用。
示例

# 循环中不需要用到的变量
for _ in range(5):print("Hello")# 解包时忽略某些值(只关心第二个和第四个元素)
data = (10, 20, 30, 40)
_, b, _, d = data  # 用_忽略10和30
print(b, d)  # 输出:20 40
2. 表示“内部使用”的变量/函数(模块/类级别)

按约定,单下划线开头的变量、函数或类(如_x_func())表示“仅供内部使用”,不建议外部直接访问(但Python不强制限制)。
示例

# 模块内的“内部”变量
# mymodule.py
_x = 100  # 暗示外部不要直接使用def _internal_func():  # 内部工具函数return "内部逻辑"def public_func():  # 公开接口return _internal_func()  # 内部调用# 外部导入时,默认不会导入单下划线开头的对象
from mymodule import *  # 不会导入_x和_internal_func

在类中,单下划线开头的属性/方法也表示“内部使用”,提醒子类或外部不要随意修改:

class MyClass:def __init__(self):self.public = "公开属性"self._internal = "内部属性(约定)"  # 外部仍可访问,但不建议def _internal_method(self):  # 内部方法return "内部逻辑"def public_method(self):return self._internal_method()  # 内部调用
3. 交互式解释器中的“上一次结果”

在Python交互式环境(如IDLE、Jupyter)中,_会自动保存上一次表达式的结果。
示例

>>> 1 + 2
3
>>> _  # 引用上一次结果
3
>>> _ * 2
6
>>> _
6
4. 数字分隔符(Python 3.6+)

用于分割长数字,提高可读性(不影响数值本身)。
示例

large_num = 1_000_000  # 等价于1000000
print(large_num)  # 输出:1000000pi = 3_1415_9265  # 更易读的格式

二、双下划线“__”的使用场景

双下划线有明确的语法特性,不仅是约定,会影响Python的解析行为。

1. 名称修饰(Name Mangling):避免子类覆盖父类成员

在类中,双下划线开头的变量或方法(如__x)会被Python自动“修饰”(重命名),形式为_ClassName__x,防止子类意外覆盖父类的成员。
原理:Python解释器在编译时会修改名称,确保父类的私有成员在子类中不被冲突。
示例

class Parent:def __init__(self):self.__secret = "父类的秘密"  # 双下划线开头def __print_secret(self):  # 双下划线开头的方法print(self.__secret)class Child(Parent):def __init__(self):super().__init__()self.__secret = "子类的秘密"  # 看似重名,实际不会冲突def __print_secret(self):  # 看似重写,实际不会覆盖父类方法print(self.__secret)# 测试
p = Parent()
c = Child()# 直接访问会报错(因为名称已被修饰)
# print(p.__secret)  # AttributeError# 查看修饰后的名称
print(p._Parent__secret)  # 输出:父类的秘密(正确访问方式)
print(c._Child__secret)   # 输出:子类的秘密(正确访问方式)p._Parent__print_secret()  # 输出:父类的秘密
c._Child__print_secret()   # 输出:子类的秘密

注意:名称修饰的目的不是“禁止访问”,而是“避免意外覆盖”。通过_ClassName__member仍可访问(不建议)。

2. 双下划线开头和结尾:魔术方法(Magic Methods)

格式为__xxx__的方法是Python的“魔术方法”(或“特殊方法”),由Python内置定义,用于实现类的特殊行为(如构造、比较、运算等)。
特点

  • 由Python自动调用(如__init__在创建对象时调用),无需手动调用。
  • 用户不应自定义类似格式的方法(避免与内置功能冲突)。

示例

class MyClass:def __init__(self, value):  # 构造方法,创建对象时调用self.value = valuedef __str__(self):  # 定义print()时的输出格式return f"MyClass(value={self.value})"def __add__(self, other):  # 定义+运算符的行为return MyClass(self.value + other.value)obj1 = MyClass(10)
obj2 = MyClass(20)
print(obj1)  # 自动调用__str__(),输出:MyClass(value=10)
print(obj1 + obj2)  # 自动调用__add__(),输出:MyClass(value=30)

三、魔术方法(Magic Methods,又称特殊方法,格式为__xxx__

前面我们提到魔术方法(Magic Methods,又称特殊方法,格式为__xxx__),这里我们详细讨论一下。
魔术方法是Python中预定义的特殊函数,用于让自定义类实现与Python内置语法、函数或运算符的交互能力。它们的核心作用是“让自定义对象像内置对象(如列表、字典、整数)一样自然地融入Python生态”,大幅提升代码的可读性和易用性。

1、对象的创建与生命周期管理

用于控制对象的创建、初始化、销毁等过程,是最基础的魔术方法。

魔术方法作用应用场景举例
__new__(cls)实例创建的第一步(分配内存),返回实例实现单例模式(确保类只有一个实例)
__init__(self)实例初始化(设置初始属性)所有类的基础初始化(必用)
__del__(self)实例被销毁时调用(垃圾回收)释放资源(如关闭文件、数据库连接)

示例:单例模式(__new__
确保一个类只有一个实例(如配置管理器、日志管理器):

class Singleton:_instance = None  # 存储唯一实例def __new__(cls):if cls._instance is None:cls._instance = super().__new__(cls)  # 首次创建实例return cls._instance  # 后续调用直接返回已有实例# 测试:无论创建多少次,都是同一个实例
a = Singleton()
b = Singleton()
print(a is b)  # 输出:True
2、字符串表示与格式化

用于定义对象转换为字符串的规则,影响print()str()repr()等函数的输出,便于调试和用户交互。

魔术方法作用区别
__str__(self)返回“用户友好”的字符串表示str(obj)print(obj)调用
__repr__(self)返回“开发者友好”的字符串表示(可重现对象)repr(obj)、控制台直接输出调用

示例:自定义日志对象的字符串表示

class Log:def __init__(self, level, message):self.level = levelself.message = messagedef __str__(self):# 用户看到的简洁信息return f"[{self.level.upper()}] {self.message}"def __repr__(self):# 开发者看到的详细信息(可用于重建对象)return f"Log(level='{self.level}', message='{self.message}')"log = Log("error", "文件不存在")
print(log)  # 调用__str__:[ERROR] 文件不存在
print(repr(log))  # 调用__repr__:Log(level='error', message='文件不存在')
3、运算符重载

让自定义对象支持Python的内置运算符(如+==>等),使代码更直观。

魔术方法对应运算符/操作应用场景
__add__(self, other)self + other自定义加法(如向量相加、字符串拼接)
__sub__(self, other)self - other自定义减法
__eq__(self, other)self == other自定义相等性判断
__lt__(self, other)self < other自定义小于比较(支持排序)
__len__(self)len(self)支持长度计算(如容器类)

示例:实现向量加法与比较

class Vector:def __init__(self, x, y):self.x = xself.y = y# 支持向量加法:v1 + v2def __add__(self, other):return Vector(self.x + other.x, self.y + other.y)# 支持相等判断:v1 == v2def __eq__(self, other):return self.x == other.x and self.y == other.y# 支持小于判断(按模长):v1 < v2def __lt__(self, other):return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)def __str__(self):return f"Vector({self.x}, {self.y})"v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # 调用__add__:Vector(4, 6)
print(v1 == v2)  # 调用__eq__:False
print(v1 < v2)   # 调用__lt__:True(v1模长√5 < v2模长√25)
4、容器行为模拟

让自定义类像内置容器(列表、字典、集合)一样支持索引、切片、迭代、in判断等操作。

魔术方法对应操作应用场景
__getitem__(self, key)obj[key](获取元素)支持索引/切片访问(如自定义列表)
__setitem__(self, key, value)obj[key] = value(设置元素)支持赋值操作
__contains__(self, item)item in obj(成员判断)支持in运算符
__iter__(self)迭代(for item in obj让对象可迭代
__len__(self)len(obj)(长度)支持长度计算

示例:实现一个简易的自定义列表

class MyList:def __init__(self, data):self.data = list(data)# 支持索引访问:obj[i]def __getitem__(self, key):return self.data[key]# 支持赋值:obj[i] = valuedef __setitem__(self, key, value):self.data[key] = value# 支持in判断:item in objdef __contains__(self, item):return item in self.data# 支持迭代:for item in objdef __iter__(self):return iter(self.data)  # 委托给内置列表的迭代器# 支持len():len(obj)def __len__(self):return len(self.data)ml = MyList([1, 2, 3, 4])
print(ml[1])  # 调用__getitem__:2
ml[2] = 100   # 调用__setitem__
print(3 in ml)  # 调用__contains__:False(已被改为100)
for item in ml:  # 调用__iter__print(item, end=" ")  # 输出:1 2 100 4
5、上下文管理(with语句)

通过__enter____exit__实现“资源自动获取与释放”,无需手动处理关闭(如文件、数据库连接)。

魔术方法作用
__enter__(self)进入with块时调用,返回资源对象
__exit__(self, exc_type, exc_val, exc_tb)退出with块时调用,释放资源(无论是否出错)

示例:自定义文件管理器(自动关闭文件)

class FileManager:def __init__(self, filename, mode):self.filename = filenameself.mode = modeself.file = Nonedef __enter__(self):self.file = open(self.filename, self.mode)  # 获取资源return self.file  # 允许with ... as f使用def __exit__(self, exc_type, exc_val, exc_tb):self.file.close()  # 释放资源(必执行)# 可处理异常(如返回True表示已处理异常)return False# 使用with语句:自动调用__enter__和__exit__
with FileManager("test.txt", "w") as f:f.write("Hello, Magic Methods!")
# 退出with块后,文件已自动关闭,无需手动f.close()
6、属性访问控制

用于拦截或定制对象的属性访问(获取、设置、删除),实现动态属性、权限控制等。

魔术方法作用应用场景
__getattr__(self, name)访问不存在的属性时调用动态生成属性(如从字典映射)
__setattr__(self, name, value)设置属性时调用(包括存在的)限制属性修改(如只读属性)
__delattr__(self, name)删除属性时调用禁止删除关键属性

示例:动态映射属性到内部字典

class DynamicAttr:def __init__(self):self.data = {"name": "默认名称", "age": 0}  # 内部存储# 访问属性时,从data中获取(如obj.name → data["name"])def __getattr__(self, name):if name in self.data:return self.data[name]raise AttributeError(f"属性'{name}'不存在")# 设置属性时,存入data(如obj.age = 18 → data["age"] = 18)def __setattr__(self, name, value):if name == "data":  # 特殊处理内部的data属性super().__setattr__(name, value)else:self.data[name] = value  # 其他属性存入dataobj = DynamicAttr()
print(obj.name)  # 调用__getattr__:默认名称
obj.age = 20     # 调用__setattr__
print(obj.age)   # 输出:20
obj.gender = "男"  # 动态添加新属性
print(obj.gender)  # 输出:男
7、可调用对象

通过__call__方法让类的实例像函数一样被调用,实现“带状态的函数”。

示例:带计数器的函数

class Counter:def __init__(self):self.count = 0  # 维护状态# 实例被调用时执行(如obj())def __call__(self):self.count += 1return f"已调用{self.count}次"counter = Counter()
print(counter())  # 调用__call__:已调用1次
print(counter())  # 输出:已调用2次
print(counter.count)  # 查看状态:2

魔术方法的核心价值是让自定义类“适配”Python的内置语法和功能,使代码更符合Python的“风格”(简洁、直观)。

合理使用魔术方法能大幅提升自定义类的灵活性和易用性,但避免过度使用(如自定义的__xxx__可能与内置功能冲突)。

四、回顾

类型本质作用场景语法强制力
单下划线_编程约定临时变量、内部成员(提示)、数字分隔符、交互式解释器结果无(仅约定)
双下划线__语法特性名称修饰(避免子类覆盖)、魔术方法(__xxx__,内置行为)有(解释器处理)
使用建议
  1. 单下划线:遵循“内部成员”约定,提醒自己和他人不要随意外部访问,但不阻止访问。
  2. 双下划线:仅在需要“防止子类覆盖父类关键成员”时使用,避免过度使用(会降低代码可读性)。
  3. 魔术方法:仅使用Python内置的__xxx__方法,不自定义类似格式的方法(如__myfunc__)。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我们为什么需要时序数据库?

引言在当今数据驱动的世界中&#xff0c;时间序列数据正以前所未有的速度增长。从物联网设备传感器、金融交易记录到应用程序性能监控&#xff0c;时间序列数据无处不在。传统的关系型数据库在处理这类数据时往往力不从心&#xff0c;这时时序数据库(Time Series Database, TSD…

python-林粒粒的视频笔记1

python的方法和函数指什么 可变类型和不可变类型 不可变类型&#xff0c;比如字符串通过方法调用后&#xff0c;字符串本身的值不改变 要改变需要重新赋值才能进行改变 比如可变数据类型类型&#xff0c;调用方法后可以直接改变原列表 因此&#xff0c;可变数据类型需要再重新赋…

CentOS 7的下载与安装

一 、CentOS 7的下载与安装 注意&#xff1a; CentOS 7 已于2024年6月30日停止维护&#xff01; 1、下载 由于 centos 7 已经停止维护&#xff0c;部分镜像网站移除了对centos 7的支持&#xff0c;这里找到了部分现在还可以使用的镜像网站 阿里云开源镜像站&#xff1a;http…

矿物分类系统开发笔记(二):模型训练[删除空缺行]

目录 一、阶段衔接与开发目标 二、数据准备 三、模型选择与训练 1. 逻辑回归&#xff08;LR&#xff09; 2. 随机森林&#xff08;RF&#xff09; 3. 高斯朴素贝叶斯&#xff08;GNB&#xff09; 4. 支持向量机&#xff08;SVM&#xff09; 5. AdaBoost 6. XGBoost 四…

通信方式:命名管道

一、命名管道 1. 命名管道的原理 有了匿名管道&#xff0c;理解命名管道就非常简单了。 对于普通文件而言&#xff0c;两个进程打开同一个文件&#xff0c;OS是不会将文件加载两次的&#xff0c;这两个进程都会指向同一个文件&#xff0c;那么&#xff0c;也就享有同一份 in…

如何将数据库快速接入大模型实现智能问数,实现chatbi、dataagent,只需短短几步,不需要配置工作流!

智能问数系统初始化操作流程 一、系统初始化与管理员账号创建登录与初始化提示&#xff1a;首次访问系统登录页&#xff0c;若系统未初始化&#xff0c;会弹出 “系统未完成初始化&#xff0c;请初始化管理员账号” 提示&#xff0c;点击【去创建】。填写管理员信息&#xff1a…

告别手写文档!Spring Boot API 文档终极解决方案:SpringDoc OpenAPI

在前后端分离和微服务盛行的今天&#xff0c;API 文档是团队协作的“通用语言”。一份清晰、准确、实时同步的文档&#xff0c;能极大提升开发和联调效率。然而&#xff0c;手动编写和维护 API 文档&#xff08;如 Word、Markdown 或 Postman&#xff09;是一场永无止境的噩梦—…

N4200EX是一款全智能超声波检测仪产品简析

N4200EX是一款全智能超声波检测仪&#xff0c;适用于石油、石化、天然气、气体生产等行业的压力管路、阀门、设备的各种防爆场合气体泄漏、真空泄漏、阀门内漏检测。●本安防爆设计&#xff0c;防爆、防尘、防水、抗摔。●适应恶劣环境&#xff0c;可在-25℃超低温环境检测&…

NestJS @Inject 装饰器入门教程

一、核心概念解析 1.1 依赖注入&#xff08;DI&#xff09;的本质 依赖注入是一种设计模式&#xff0c;通过 IoC&#xff08;控制反转&#xff09;容器管理对象生命周期。在 NestJS 中&#xff0c;Injectable() 标记的类会被容器管理&#xff0c;而 Inject() 用于显式指定依赖项…

网络地址详解

子网划分详解&#xff1a;从 IP 地址结构到实际应用 在计算机网络中&#xff0c;子网划分是一项关键的技术&#xff0c;它能帮助我们更高效地管理 IP 地址资源&#xff0c;优化网络性能。要深入理解子网划分&#xff0c;首先需要从 IP 地址的基本结构说起。 一、IPv4 地址的基…

吾日三省吾身 | 周反思 8.19

上周一览总体来说&#xff0c;上个周是一个被项目驱使而险些丧失自主思考能力的危险阶段。相比任何有机械化工作经验的读者都有类似的体验&#xff0c;在手上打螺丝的无尽循环中&#xff0c;自己的脑子就会逐渐丧失对自身的感知以及自主思考的能力。而这个负循环一旦开始&#…

08.19总结

连通性 在无向图中&#xff0c;若任意两点间均存在路径相连&#xff0c;则该图称为连通图。 若删除图中任意一个顶点后&#xff0c;剩余图仍保持连通性&#xff0c;则该图为点双连通图。 若删除图中任意一条边后&#xff0c;图仍保持连通性&#xff0c;则该图为边双连通图。 在…

车e估牵头正式启动乘用车金融价值评估师编制

8月13日&#xff0c;汽车金融行业职业能力评价规范编制启动工作会议在广州圆满落幕。本次会议由中国机械工业联合会机械工业人才评价中心主办&#xff0c;广州穗圣信息科技有限公司&#xff08;车e估&#xff09;承办。会议汇聚了众多行业精英&#xff0c;包括中国机械工业联合…

清空 github 仓库的历史提交记录(创建新分支)

想在 现有仓库中创建一个新分支 master&#xff0c;删除原来的 main&#xff0c;然后把 master 重命名为 main&#xff0c;并且清空历史。可以用下面一条完整的命令序列操作&#xff1a; # 1. 创建一个没有历史的新分支 master git checkout --orphan master# 2. 添加当前所有文…

使用B210在Linux下实时处理ETC专用短程通信数据(2)-CPU单核高速数据处理

在上一篇文章中&#xff0c;使用Octave初步验证了ETC车联数据的格式。然而&#xff0c;Octave无法实时处理20M的采样带宽。我们本节通过C语言&#xff0c;重写 Octave程序&#xff0c;实现实时处理&#xff0c;涉及下面三个关键特点。 文章目录1. 全静态内存2. 使用环状缓存3 无…

Spark 运行流程核心组件(二)任务调度

1、调度策略参数默认值说明spark.scheduler.modeFIFO调度策略&#xff08;FIFO/FAIR&#xff09;spark.locality.wait3s本地性降级等待时间spark.locality.wait.processspark.locality.waitPROCESS_LOCAL 等待时间spark.locality.wait.nodespark.locality.waitNODE_LOCAL 等待时…

Orbbec---setBoolProperty 快捷配置设备行为

在奥比中光&#xff08;Orbbec&#xff09;SDK&#xff08;通常称为ob库&#xff09;中&#xff0c;setBoolProperty函数是用于设置设备或传感器的布尔类型属性的核心接口。它主要用于开启/关闭设备的某些功能或模式&#xff0c;是配置设备行为的重要方法。 函数原型与参数解析…

[OWASP]智能体应用安全保障指南

1.关键组件定义 KC1 生成式语言模型&#xff08;Generative Language Models&#xff09; KC1.1 大语言模型&#xff08;LLMs&#xff09;&#xff1a;作为代理的“大脑”&#xff0c;基于预训练基础模型&#xff08;如 GPT 系列、Claude、Llama、Gemini&#xff09;&#xff…

【Vivado TCL 教程】从零开始掌握 Xilinx Vivado TCL 脚本编程(三)

【Vivado TCL 教程】从零开始掌握 Xilinx Vivado TCL 脚本编程&#xff08;三&#xff09; 系列文章目录 1、VMware Workstation Pro安装指南&#xff1a;详细步骤与配置选项说明 2、VMware 下 Ubuntu 操作系统下载与安装指南 3、基于 Ubuntu 的 Linux 系统中 Vivado 2020.1 下…

AI与大数据驱动下的食堂采购系统源码:供应链管理平台的未来发展

在数字化浪潮不断加速的今天&#xff0c;很多企业和机构都在追求一个目标&#xff1a;如何把“效率”与“成本”做到最佳平衡。对于学校、企事业单位的食堂来说&#xff0c;采购环节就是重中之重。往小了说&#xff0c;它关系到食堂员工的工作体验&#xff1b;往大了说&#xf…