【Python特性】Python中的下划线和双下划线是什么意思?

平时写代码经常碰到下划线、双下划线等“奇怪”的写法,今天特意花时间彻底解决这个问题。文章内容主要参考《深入理解Python特性》一书。

文章目录

  • 前置单下划线:_var
  • 后置单下划线:var_
  • 前置双下划线:__var
  • 前后双下划线:__ var__
  • 单下划线:_
  • 总结:


前置单下划线:_var

意义:python社区约定好单下划线表达的是某种意思,本身不会影响程序的行为

  1. PEP8中定义:以单个下划线开头的变量或方法只在内部使用
  2. 这个符号对python解释器没有什么用,它只是个小小的提示:这个变量或方法并不是这个类的公共接口,最好不要使用它——(因为python中没有严格界定“私有”和“公有”变量,因此下划线可以作为提示)
  3. 使用通配符导入模块Python不会导入带有前置但下划线的名称,除非模块中定义了__all__列表覆盖了这个行为,举个例子:
# test_import.py文件内容
def hello():
    print('Hello, world!')


def _world():
    print('Hello, world!')

>>> from test_import import *
>>> hello()
Hello, world!
>>> _world()
Traceback (most recent call last):
  File "", line 1, in 
NameError: name '_world' is not defined

后置单下划线:var_

意义:名称被Python语言中的关键字占用的时候,就可以使用,比如classdef这些,使用class_def_代替


前置双下划线:__var

这个估计经常遇到

意义:告诉python解释器重写属性名称,避免子类中的命名冲突。

  1. 也称为:名称改写(name mangling)
  2. dir()可以查看对象的属性和方法
  3. 注意类似__bar前面双下划线的方法和变量,
class Test:
   def __init__(self):
       self.foo = 12
       self._bar = 24
       self.__bar = 43
class ExtendedTest(Test):
   def __init__(self):
       super(ExtendedTest, self).__init__()
       self.foo = 'hello'
       self._bar = 'world'
       self.__bar = 'down'

当创建ExtendedTest类的实例t时,调用t.__bar会报错AttributeError: 'ExtendedTest' object has no attribute '__bar'
具体来看一下原因:输入dir(t)

>>> dir(t)
['_ExtendedTest__bar', '_Test__bar', '__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__', '_bar', 'foo']

我们发现t没有__bar属性,而是变成了_ExtendedTest__bar_Test__bar这是因为Python进行了名称重写
继续输入:t._ExtendedTest__bart__Test__bar,出现了down43

>>> t._ExtendedTest__bar
'down'
>>> t._Test__bar
43
  1. 我们无法察觉双下划线名称的改写,也就是我们无法通过t.__bar直接访问__bar的值,只能借的类方法去访问或者是通过t._ExtendedTest__bar。类似举例如下:
class ManglingTest:
  def __init__(self):
      self.__mangled = 'hello'

  def get_mangled(self):
      return self.__mangled

>>> ManglingTest().get_mangled()
'hello'
>>> ManglingTest().__mangled
AttributeError: "'ManglingTest' object has no attribute '__mangled'"
  1. 名称改写也适用于方法名。
class MangledMethod:
  def __method(self):
      return 42

  def call_it(self):
      return self.__method()

>>> MangledMethod().__method()
AttributeError: "'MangledMethod' object has no attribute '__method'"
>>> MangledMethod().call_it()
42
  1. 还有更神奇的用法:由于名称的改写,因此类中test()方法用__mangled就可以访问在MangledGlobal类中访问全局变量_MangledGlobal__mangled,因为Python的名称改写自动扩展了变量名。
_MangledGlobal__mangled = 23

class MangledGlobal:
  def test(self):
      return __mangled

>>> MangledGlobal().test()
23

前后双下划线:__ var__

意义:如果使用前后双下划线,那么则不会发生名字重写,不受python解释器的影响

  1. 双下划线方法称为魔法方法,最好避免在自己程序中使用双下划线开头和结尾的名称,避免于python语言未来版本变更发生冲突。
  2. python里面有很多内置方法,如:__hash____iter____dict____repr__等其他内置函数,都是用前后双下划线

单下划线:_

  1. 表明变量是临时的或者无关紧要
for _ in range(10):
	print('Hello, world! ')
  1. 表示解释器计算的上一个表达式的结果
>>> 20 + 3
23
>>> _
23
>>> print(_)
23

>>> list()
[]
>>> _.append(1)
>>> _.append(2)
>>> _.append(3)
>>> _
[1, 2, 3]

总结:

  1. 前置单下划线_var:命名约定,表明仅在内部使用(在通配符import * 的时候会有小小的区别),一般对python解释器没有特殊的含义
  2. 后置单下划线:var_:命名约定,避免与python关键字命名冲突
  3. 前置双下划线:__var:名称重写,在类环境中使用会触发名称改写,对python解释器有影响
  4. 前后双下划线:__var__:python定义的魔法方法,在自定义属性中逼民啊用这种命名方式
  5. 单下划线:_:表明变量是临时的或者无关紧要。此外还可以表示Python REPL会话中的上一个结果。

结束了…

你可能感兴趣的:(Python)