python双划线_Python 中的下划线,双下划线

在 Python 中变量和方法里经常见到单下划线和双下划线,比如常见 __future__, __all__, __version__, __author__。

from __future__ import print_function

import os

__all__ = ['function1', 'function2']

__version__ = '0.01'

__author__ = 'towardsdeeplearning.com'

print("Hello World")

再细分的话就是下面几种情况了,我在这里简单列举下:前置的单下划线:_var

后置的单下划线:var_

前置的双下划线:__var

前后置的双下划线:__var__

单独的下划线:_

1. Single Leading Underscore: “_var”

下划线前缀一般约定是为了提示其他程序员,以单个下划线开头的变量或方法供内部使用。PEP 8 中定义了此约定,这是最常用的 Python 编程规范。当然,这个只是一个指示性,并不是强制,Python 在“私有”和“公共”变量之间没有像 Java 明确。

class Test:

def __init__(self):

self.foo = 11

self._bar = 23

>>> t = Test()

>>> t.foo

11

>>> t._bar

23

这里即使加上了下划线的前缀,我们也能访问变量,但要注意的是,下划线的前缀会影响从模块导入名称的方式。

# my_module.py:

def external_func():

return 23

def _internal_func():

return 42

我们倒入的时候能看到一个奇怪的现象:

>>> from my_module import *

>>> external_func()

23

>>> _internal_func()

NameError: "name '_internal_func' is not defined"

这主要是因为通过通配符导从模块中导入所有函数,Python 将不会导入带下划线的函数(或者你显式的在__all__ 列表里定义),应避免使用通配符导入。但是常规导入不受前缀下划线命名约定的影响:

>>> import my_module

>>> my_module.external_func()

23

>>> my_module._internal_func()

42

2.Single Trailing Underscore: “var_”

当一个属性名恰好跟 Python 的关键字重名,为了直观,可以在属性名后加个_

>>> def make_object(name, class):

SyntaxError: "invalid syntax"

>>> def make_object(name, class_):

... pass

3.双下划线前缀:“__var”

此时 Python 解释器会重写属性名称垃圾避免子类中命名冲突,这就是所谓的 mangling,名字修饰,解释器以某种方式更改变量的名称,以使以后扩展类时更难产生冲突。

class Test:

def __init__(self):

self.foo = 11

self._bar = 23

self.__baz = 42

使用 Python 内置的函数 dir() 查看下 Test 类的属性。

>>> t = Test()

>>> dir(t)

['_Test__baz', '__class__', '__delattr__', '__dict__','__dir__',

'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',

'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__',

'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',

'__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'foo']

dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。上边返回类里变量 foo, _bar, 但是没有发现 __baz 这个变量。

强行访问的话就会报错

>>> t = Test()

>>> t.__baz

AttributeError: "'Test' object has no attribute '__baz'"

我们仔细看下上边的列表,发现有个叫 _Test__baz 属性,这就是所谓的mangling ,这样做是为了防止变量在子类中被覆盖。

我们来建立个类 ExtendedTest,继承自 Test,试图在构造函数里覆盖已经存在的属性。

class ExtendedTest(Test):

def __init__(self):

super().__init__()

self.foo = 'overridden'

self._bar = 'overridden'

self.__baz = 'overridden'

来看下 ExtendedTest 实例中 foo, _bar, 和 __baz 变量。

>>> t2 = ExtendedTest()

>>> t2.foo

'overridden'

>>> t2._bar 'overridden'

>>> t2.__baz

AttributeError: "'ExtendedTest' object has no attribute '__baz'"

当试图访问 t2.__baz 时,又出现了 AttributeError,这其实就是 mangling,查看下属性确实没有__baz 这个属性。

>>> dir(t2)

['_ExtendedTest__baz', '_Test__baz', '__class__', '__delattr__',

'__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',

'__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__',

'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',

'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',

'_bar', 'foo', 'get_vars']

__baz 变成了 _ExtendedTest__baz,基类 Test 的变量变成了 _Test__baz,我们试图访问下:

>>> t2._ExtendedTest__baz 'overridden'

>>> t2._Test__baz

42

那么对于方法来说,mangling 同样适用。

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

4. 前后双下划线

常用于 __init__, __call__,__iter__, __next__这些方法里,但是,通常我们自己的方法名最好不要用。

class PrefixPostfixTest:

def __init__(self):

self.__bam__ = 42

>>> PrefixPostfixTest().__bam__

42

5. Single Underscore: “_”

有时候函数返回值不止一个,但有些变量我们不需要,就可以使用 _ 来当个用不到的变量。

>>> for _ in range(32):

... print('Hello, World.')

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值