0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Python 里最具代表性的符号居然如此强大

Linux爱好者 来源:Python金牌大牛 作者:Python金牌大牛 2021-06-01 15:06 次阅读

要说 Python 里使用频率最高的符号,我想下划线应该排第一吧?

在不同场合下,下划线有不同含义:比如_var表示内部变量;__var表示私有属性;__var__表示魔术方法;这些含义有的是程序员群体的约定,如_var;有的是 Python 解释器规定的形式,如__var。

本文总结 Python 语言编程中常用下划线的地方,力图一次搞懂_用法。目前常见的用法有五种:

_用于临时变量

var_用于解决命名冲突问题

_var用于保护变量

__var用于私有变量

__var__用于魔术方法

下面我们具体看看这些下划线应用场景。

一、_用于临时变量

单下划线一般用于表示临时变量,在 REPL、for 循环和元组拆包等场景中比较常见。

1.1 REPL单下划线在 REPL 中关联的是上一次计算的非 None 结果。

》》》 1+1

2

》》》 _

2

》》》 a=2+2

》》》 _

2

1+1,结果为 2,赋值给_;而赋值表达式a=2+2a 为 4,但整个表达式结果为None,故不会关联到_。这有点类似日常大家使用的计算器中的ANS按键,直接保存了上次的计算结果。

1.2 for循环中的_for 循环中_作为临时变量用。下划线来指代没什么意义的变量。例如在如下函数中,当我们只关心函数执行次数,而不关心具体次序的情况下,可以使用_作为参数

nums = 13

for _ in range(nums):

fun_oper()

1.3 元组拆包中的_第三个用法是元组拆包,赋值的时候可以用_来表示略过的内容。如下代码忽略北京市人口数,只取得名字和区号。

》》》 city,_,code = (‘Beijing’,21536000,‘010’)

》》》 print(city,code)

Beijing 010

如果需要略过的内容多于一个的话,可以使用*开头的参数,表示忽略多个内容。如下代码忽略面积和人口数,只取得名字和区号

city,*_,code = (‘Beijing’,21536000,16410.54,‘010’)

1.4 国际化函数在一些国际化编程中,_常用来表示翻译函数名。例如 gettext 包使用时:

import gettext

zh = gettext.tranlation(‘dict’,‘locale’,languages=[‘zh_CN’])

zh.install()

_(‘hello world’)

依据设定的字典文件,其返回相应的汉字“你好世界”。

1.5 大数字表示形式_也可用于数字的分割,这在数字比较长的时候常用。

》》》 a = 9_999_999_999

》》》 a

9999999999

a 的值自动忽略了下划线。这样用_分割数字,有利于便捷读取比较大的数。

二、var_用于解决命名冲突问题

变量后面加一个下划线。主要用于解决命名冲突问题,元编程中遇时 Python 保留的关键字时,需要临时创建一个变量的副本时,都可以使用这种机制。

def type_obj_class(name,class_):

pass

def tag(name,*content,class_):

pass

以上代码中出现的class是 Python 的保留关键字,直接使用会报错,使用下划线后缀的方式解决了这个问题。

三、_var用于保护变量

前面一个下划线,后面加上变量,这是仅供内部使用的“保护变量”。比如函数、方法或者属性。

这种保护不是强制规定,而是一种程序员的约定,解释器不做访问控制。一般来讲这些属性都作为实现细节而不需要调用者关心,随时都可能改变,我们编程时虽然能访问,但是不建议访问。

这种属性,只有在导入时,才能发挥保护作用。而且必须是from XXX import *这种导入形式才能发挥保护作用。

使用from XXX import *是一种通配导入(wildcard import),这是 Python 社区不推荐的方式,因为你根本搞不清你到底导入了什么属性、方法,很可能搞乱你自己的命名空间。PEP8推荐的导入方式是from XXX import aVar , b_func , c_func这种形式。

比如在下例汽车库函数 tools.py 里定义的“保护属性”:发动机型号和轮胎型号,这属于实现细节,没必要暴露给用户。当我们使用 from tools import * 语句调用时,其实际并没有导入所有_开头的属性,只导入了普通 drive 方法。

_moto_type = ‘L15b2’

_wheel_type = ‘michelin’

def drive():

_start_engine()

_drive_wheel()

def _start_engine():

print(‘start engine %s’%_moto_type)

def _drive_wheel():

print(‘drive wheel %s’%_wheel_type)

查看命令空间print(vars())可见,只有 drive 函数被导入进来,其他下划线开头的“私有属性”都没有导入进来。

{‘__name__’: ‘__main__’, ‘__doc__’: None, ‘__package__’: None, ‘__loader__’: 《_frozen_importlib_external.SourceFileLoader object at 0x005CF868》, ‘__spec__’: None, ‘__annotations__’:{}, ‘__builtins__’: 《module ‘builtins’ (built-in)》, ‘__file__’: ‘。\xiahuaxian.py’, ‘__cached__’: None, ‘walk’: 《function walk at 0x01DA8C40》, ‘root’: ‘。\__pycache__’, ‘_’: [21536000, 16410.54], ‘dirs’: [‘tools.cpython-38.pyc’], ‘city’: ‘Beijing’, ‘code’: ‘010’, ‘drive’: 《function drive at 0x01DBC4A8》}

3.1 突破保护属性之所以说是“保护”并不是“私有”,是因为 Python 没有提供解释器机制来控制访问权限。我们依然可以访问这些属性:

import tools

tools._moto_type = ‘EA211’

tools.drive()

以上代码,以越过“保护属性”。此外,还有两种方法能突破这个限制,一种是将“私有属性”添加到 tool.py 文件的 __all__ 列表里,使from tools import *也导入这些本该隐藏的属性。

__all__ = [‘drive’,‘_moto_type’,‘_wheel_type’]

另一种是导入时指定“受保护属性”名。

from tools import drive,_start_engine

_start_engine()

甚至是,使用import tools也可以轻易突破保护限制。所以可见,“保护属性”是一种简单的隐藏机制,只有在from tools import *时,由解释器提供简单的保护,但是可以轻易突破。这种保护更多地依赖程序员的共识:不访问、修改“保护属性”。除此之外,有没有更安全的保护机制呢?有,就是下一部分讨论的私有变量。

四、__var用于私有变量

私有属性解决的之前的保护属性保护力度不够的问题。变量前面加上两个下划线,类里面作为属性名和方法都可以。两个下划线属性由 Python 的改写机制来实现对这个属性的保护。

看下面汽车例子中,品牌为普通属性,发动机为“保护属性”,车轮品牌为“私有属性”。

class Car:

def __init__(self):

self.brand = ‘Honda’

self._moto_type = ‘L15B2’

self.__wheel_type = ‘michelin’

def drive(self):

print(‘Start the engine %s,drive the wheel %s,I get a running %s car’%

(self._moto_type,

self.__wheel_type,

self.brand))

我们用var(car1)查看下具体属性值,

[‘_Car__wheel_type’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__init_subclass__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘_moto_type’, ‘brand’, ‘drive’]

可见,实例化 car1 中,普通属性 self.brand 和保护属性 self._moto_type 都得以保存,两个下划线的私有属性 __wheel_type 没有了。取而代之的是_Car_wheel_type这个属性。这就是改写机制(Name mangling)。两个下划线的属性,被改写成带有类名前缀的变量,这样子类很难明明一个和如此复杂名字重名的属性。保证了属性不被重载,保证了其的私有性。

4.1 突破私有属性这里“私有变量”的实现,是从解释器层面给与的改写,保护了私有变量。但是这个机制并非绝对安全,因为我们依然可以通过 obj._ClasssName__private 来访问 __private 私有属性。

car1.brand = ‘Toyota’

car1._moto_type = ‘6AR-FSE’

car1._Car__wheel_type = ‘BRIDGESTONE’

car1.drive()

结果

Start the engine 6AR-FSE,

drive the wheel BRIDGESTONE,

I get a running Toyota car

可见,对改写机制改写的私有变量,虽然保护性加强了,但依然可以访问并修改。只是这种修改,只是一种杂耍般的操作,并不可取。

五、__var__用于魔术方法

变量前面两个下划线,后面两个下划线。这是 Python 当中的魔术方法,一般是给系统程序调用的。例如上例中的 __init__ 就是类的初始化魔术方法,还有支持 len 函数的 __len__ 方法,支持上下文管理器协议的 __enter__ 和 __exit__ 方法,支持迭代器协议的 __iter__ 方法,支持格式化显示的 __repr__ 和 __str__ 方法等等。这里我们为上例的 Car 类添加魔术方法 __repr__ 来支持格式化显示。

def __repr__(self):

return ‘***Car %s:with %s Engine,%sWheel***’%

(self.brand,self._moto_type,self.__wheel_type)

未添加__repr__魔术方法之前,print(car1)结果为《__main__.Car object at 0x0047F7F0》,这个结果让人看的一头雾水,增加 repr 魔术方法之后,显示结果为***Car Toyota:with 6AR-FSE Engine,BRIDGESTONE Wheel***清晰明了,利于调试。这就是魔术方法的功效:支持系统调用,改进用户类表现,增加协议支持,使用户类表现得更像系统类。

5.1 Python魔术方法分类以下所有魔术方法均需要在前后加上__,这里省略了这些双下划线。

一元运算符 neg pos abs invert

转换 complex int float round inex

算术运算 add sub mul truediv floordiv mod divmod pow lshift rshift and xor or

算术运算除 and 之外,前面再加上 r,表示反运算。除 dimod 外,前面加上 i,表示就地运算。

比较 lt le eq ne gt ge

类属性 getattr getattribute setattr delattr dir get set delete

格式化 bytes hash bool format

类相关 init del new

列表 getitem

迭代器 iter next

上下文管理器 enter exit

六、总结

总之,下划线在 Python 当中应用还是很广泛的,甚至可以说 Python 对下划线有所偏爱。可以看到 _常用于临时变量,在 REPL,for 循环,元组拆包和国际化中得到了广泛应用。var_用于解决命名冲突问题,使用时比较简单易懂的。

_var对变量的保护,只是一种脆弱的保护,更多依靠程序员的约定。__var用于私有变量,借助改写机制支持,已经支持了私有变量,但是仍然存在漏洞。对__var__用于魔术方法,进行了一个简单的介绍,魔术方法较多,但是理解并不复杂。希望以后可以进一步介绍这些魔术方法。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • python
    +关注

    关注

    51

    文章

    4669

    浏览量

    83457
  • 解释器
    +关注

    关注

    0

    文章

    98

    浏览量

    6419

原文标题:Python 里最具代表性的符号,竟如此强大

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    小白请问电路这两个半圆代表什么?

    请问电路这两个半圆代表什么元件? 没有搜到呀。 另外,请问下图中的3.3v 电源是不是都要接到一起. 谢谢
    发表于 02-16 16:32

    如何使用linux下gdb来调试python程序

    如何使用linux下gdb来调试python程序  在Linux下,可以使用GDB(GNU调试器)来调试Python程序。GDB是一个强大的调试工具,可以帮助开发者诊断和修复程序中的错误。在本文
    的头像 发表于 01-31 10:41 415次阅读

    断路器上各种符号代表什么

    断路器是一种用于保护电路免受过载和短路的电器设备。它能够通过切断电流来阻止意外情况的发生,从而保护电器设备和人身安全。在断路器上,有许多符号,它们代表着不同的功能和特征。接下来,我将详细介绍断路器
    的头像 发表于 12-15 10:58 3139次阅读

    常见电子元器件符号的含义

    不同电子元器件的符号代表着它们的不同功能和特性。以下是一些常见电子元器件的符号以及它们的含义。
    的头像 发表于 12-01 09:18 3095次阅读
    常见电子元器件<b class='flag-5'>符号</b>的含义

    python中number代表什么

    Python中,number(数字)是一种内置的数据类型,用于表示数值。Python提供了几种不同的number类型,分别是整数(int)、浮点数(float)、复数(complex)和布尔值
    的头像 发表于 11-22 09:50 702次阅读

    解读可穿戴设备代表性产品核心技术原理

    电子发烧友网站提供《解读可穿戴设备代表性产品核心技术原理.doc》资料免费下载
    发表于 10-31 11:22 0次下载
    解读可穿戴设备<b class='flag-5'>代表性</b>产品核心技术原理

    Delorean:优秀的Python时间格式转换工具

    模块名称的由来,Delorean 是电影《回到未来》里的那辆极为炫酷的鸥翼汽车,采用这部电影里的非常具有代表性
    的头像 发表于 10-31 10:51 233次阅读

    Camelot:Python强大的PDF表格提取器

    如果你有从PDF中批量提取表格的需求,那么这篇文章就是你的福音。 Python 第三方模块 Camelot 能够精准识别PDF中的表格信息,并提取为pandas数据结构,而且还能导出为多种格式
    的头像 发表于 10-21 10:57 721次阅读
    Camelot:<b class='flag-5'>Python</b>超<b class='flag-5'>强大</b>的PDF表格提取器

    Python编程实用指南

    Python 学习编程的读者,尤其适合缺乏编程基础的初学者。通过阅读本书,读者将能利用最强大的编程语言和工具,并且将体会到 Python 编程的快乐
    发表于 09-27 06:21

    KiCad中不同GND符号的含义及应用

    。 该符号 (IEC 60417 #5018) 代表“干净”的地。从这个意义上讲,它是一个特别设计的“地”,不会受噪声的影响,以确保敏感设备的正常运行。 保护接地。此符号 (IE
    发表于 08-18 16:55

    为什么python适合人工智能

    Python是一种相对简单的编程语言。它的语法和结构逻辑清晰,代码易于阅读和理解。Python中没有像C++或Java那样的过多的符号和特殊语法。这使得Python很容易让编程新手进入
    的头像 发表于 08-13 14:30 748次阅读

    Symbol(符号)和Designator(器件标识)

    Symbol(符号)是用于表示特定电子元件的图形化表示,它是一个抽象的图形,代表了元件的功能和特性。符号通常由线条、箭头、标记和其他几何形状组成,用于在原理图或电路图中表示元件的连接方式和电气特性。
    的头像 发表于 06-26 11:34 2048次阅读

    153个!PCB板上的字母符号代表啥?一图带你搞懂!

    PCB板是基于电路设计图而生产的,看过电路设计图的小伙伴都会知道,上面有各种物理电学标准符号。通过分析电路设计图,可以得知将使用哪些电子元器件,各元器件之间的关系,以及该电路具备哪些性能。 为此
    的头像 发表于 05-11 20:16 1577次阅读

    153个!PCB板上的字母符号代表啥?一图带你搞懂!

    PCB板是基于电路设计图而生产的,看过电路设计图的小伙伴都会知道,上面有各种物理电学标准符号。通过分析电路设计图,可以得知将使用哪些电子元器件,各元器件之间的关系,以及该电路具备哪些性能。为此
    的头像 发表于 05-05 09:45 2437次阅读
    153个!PCB板上的字母<b class='flag-5'>符号</b>都<b class='flag-5'>代表</b>啥?一图带你搞懂!

    153个!PCB板上的字母符号代表啥?一图带你搞懂!

    小编在网络上搜集了一些电工电路图常用的字母符号及释义。供大家参考。
    的头像 发表于 05-04 13:58 4850次阅读
    153个!PCB板上的字母<b class='flag-5'>符号</b>都<b class='flag-5'>代表</b>啥?一图带你搞懂!