python中下划线的5种含义_python中的下划线含义

单下划线和双下划线在Python变量和方法名称中都有含义。其中一些含义仅仅是按照惯例,作为给程序员的提示,而另外一些则由Python解释器执行。

在本文中,主要讨论以下五种下划线模式和命名约定,以及它们如何影响Python程序的行为:

1.单前置下划线:_var

单下划线前缀是一个提示,即以单个下划线开头的变量或方法将用于内部使用。PEP 8中定义了这种约定。Python不像java对公共变量和私有变量有着严格的区分,单下划线前缀不会影响程序的行为。

class Test:

def __init__(self):

self.foo = 11

self._bar = 23

>>> t = Test()

>>> t.foo

11

>>> t._bar

23

可以看到,_bar没有阻止进入类的内部并获取相应的变量值,在Python中,一个下划线前缀只是一种约定,至少在变量和方法名中是这样。

但是,前导下划线确实影响从模块导入名称的方式。假设有一个模块叫my_module:

# This is my_module.py:

def external_func():

return 23

def _internal_func():

return 42

如果使用通配符进行导入my_module中所有名称(在PEB 8中建议避免使用通配符的导入方式),则Python不会导入带有前导下划线的名称(除非模块定义了覆盖此行为的__all__列表):

>>> from my_module import *

>>> external_func()

23

>>> _internal_func()

NameError: "name '_internal_func' is not defined"

而常规的导入方式不会受到单前导下划线约定的影响:

>>> import my_module

>>> my_module.external_func()

23

>>> my_module._internal_func()

42

总结就是:单下划线是一种Python命名约定,指示名称用于内部使用。Python解释器通常不会强制执行它,只是作为对程序员的一个提示。

2.单后置下划线:var_

有时候一个变量最适合的名称已经被关键字所使用,在Python中类似def、class等关键字不能被用作变量名,可以在这些名称后面加单下划线以解决冲突。

>>>def make_object(name, class):

SyntaxError: "invalid syntax"

>>>def make_object(name, class_):

... pass

总之,单后置下划线是为了与Python关键字命名冲突而约定的。

3.双前置下划线:__var

前面两种命名模式都是一种约定,而双下划线前缀会导致Python解释器重写属性名,以避免子类中的命名冲突。这也被称为名称修饰( name mangling)——解释器在某种程度上更改变量名使得以后扩展类时更难产生冲突。

class Test:

def __init__(self):

self.foo = 11

self._bar = 23

self.__baz = 23

可以用dir()方法看一下对象的属性:

>>>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']

在这个列表里面没有__baz属性,但是可以看到有一个_Test__baz属性,这就叫做名称修饰,可以避免该属性被子类所覆盖。

现在创建一个类继承Test类,然后尝试覆盖Test类中的__baz属性:

class ExtendedTest(Test):

def __init__(self):

super().__init__()

self.foo = 'overridden'

self._bar = 'overridden'

self.__baz = 'overridden'

>>>t2 = ExtendedTest()

>>>t2.foo

'overridden'

>>>t2._bar

'overridden'

>>>t2.__baz

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

在执行t2.__baz时出现了AttributeError,我们看一下t2里面的属性:

>>>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']

可以发现,t2里面有_ExtendedTest__baz和_Test__baz,_Test__baz是继承自Test对象的属性,而_ExtendedTest__ba则是t2里面通过名称修饰得到的属性。

>>>t2._ExtendedTest__baz

'overridden'

>>>t2._Test__baz

42

双下划线前缀对编程者来说是完全透明的,如下面的一个例子:

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'"

>>>ManglingTest()._ManglingTest__mangled

'hello'

名称修饰也会应用到方法上:

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

>>>MangledMethod()._MangledMethod__method()

42

下面是另一个名称修饰的例子:

_MangledGlobal__mangled = 23

class MangledGlobal:

def test(self):

return __mangled

>>>MangledGlobal().test()

23

在这里设置了一个全局变量_MangledGlobal__mangled,然后在创建一个MangledGlobal对象去调用test方法时,test方法返回的时_MangledGlobal__mangled,这说明名称修饰不是专门与类属性绑定的。它适用于类上下文中以两个下划线开头的任何名称。

4.双前置和后置下划线:__var__

名称修饰并不会作用于双下划线前缀和后缀的变量:

class PrefixPostfixTest:

def __init__(self):

self.__bam__ = 42

>>>PrefixPostfixTest().__bam__

42

双前置和后置下划线命名在Python语言中保留为特殊用途,这条规则包括如__init__用于对象构造函数或__call__使对象可调用。最好避免在自己的代码中使用双下划线前缀和后缀的名称,以防止未来Python语言的新变化。

5.单下划线:_

根据惯例,一个单独的下划线有时用作一个名称,表示变量是临时的或不重要的。

>>>for _ in range(32):

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

可以在解包表达式时使用单个下划线作为不需要关心的变量,来忽略特定的值。同样,这个用法只是按照约定,在Python解释器中没有触发特殊的行为。单个下划线只是一个有效的变量名,有时用于此目的。

>>>car = ('red', 'auto', 12, 3812.4)

>>>color, _, _, mileage = car

>>>color

'red'

>>>mileage

3812.4

>>>_

12

除了用作临时变量之外,在大多数Python REPLs中,“_”是一个特殊的变量,表示解释器对最后一个表达式求值的结果。

>>> 20 + 3

23

>>> _

23

>>> print(_)

23

>>> list()

[]

>>> _.append(1)

>>> _.append(2)

>>> _.append(3)

>>> _

[1, 2, 3]

Quick Summary:

70a5cf9b4cabfb37df42f0fe1ff1803a.png

原文链接:https://blog.csdn.net/Aray1234/article/details/106558655

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值