为了账号安全,请及时绑定邮箱和手机立即绑定

python中的下划线

标签:
Python
  • 前置的单下划线:_var

  • 后置的单下划线:var_

  • 前置的双下划线:__var

  • 前后置的双下划线:var

  • 单独的下划线

1. Single Leading Underscore: “_var”

  • 仅仅是个提示
    前置下划线形式的属性_var其实对解释器而言没有什么吗特殊的意义,只是PEP 8 里的一个提示:告诉使用者这个_var仅仅用于内部使用,不适合用于对外开放使用。
    外部调用这个_var也是能跑通的。(python对于private、public的界限并不明显)

class Test:
    def __init__(self):        self.foo = 11
        self._bar = 23>>> t = Test()>>> t.foo11>>> t._bar23
  • 模块中的import * 是有点区别的

# my_module.py:def external_func():
    return 23def _internal_func():
    return 42

上面是个demo模块,下面来使用它

>>> from my_module import *>>> external_func()23>>> _internal_func()
NameError: "name '_internal_func' is not defined"

可以看到全局import时是不识别_var类型的模块属性的。
但是,

>>> import my_module>>> my_module.external_func()23>>> my_module._internal_func()42

所以说PEP 8里不推荐import *的做法啊,,,
记住:
Single underscores are a Python naming convention that indicates a name is meant for internal use. It is generally not enforced by the Python interpreter and is only meant as a hint to the programmer.

2.Single Trailing Underscore: “var_”

有时候程序猿需要设定一个属性名恰好跟python的关键字重了,换个名字又不直观。
所以在属性名后加个_

>>> def make_object(name, class): SyntaxError: "invalid syntax">>> def make_object(name, class_):...     pass

3.Double Leading Underscore: “__var”

  • 说白了,就是这个属性不让派生类去继承,真正的仅仅自己使用
    __前置会导致python解释器重写这个属性名,用来避免跟派生类的名字冲突。

class Test:
    def __init__(self):        self.foo = 11
        self._bar = 23
        self.__baz = 42>>> 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(t)给出了t对象的属性列表,注意到了吗,没有__baz却有了个_Test__baz
It does this to protect the variable from getting overridden in subclasses.(英文描述还是准确些)
创建个子类来进一步看看

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.__bazAttributeError:"'ExtendedTest' object has no attribute '__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
其实还是有办法访问到这个__baz的值的,看

>>> t2._ExtendedTest__baz'overridden'>>> t2._Test__baz42

不过通常想让外部访问这个值的话还是建议封装一层,

class ManglingTest:
    def __init__(self):        self.__mangled = 'hello'
    def get_mangled(self):        return self.__mangled>>> ManglingTest().get_mangled()'hello'>>> ManglingTest().__mangledAttributeError:"'ManglingTest' object has no attribute '__mangled'"

4.dunders

class PrefixPostfixTest:
    def __init__(self):        self.__bam__ = 42>>> PrefixPostfixTest().__bam__42

dunders在python里用来指双下划线包围。
dunder methods通常叫做魔术方法,但社区好像不喜欢这么称呼来着。因为这就是python的核心特征之一,应该了解使用场景。
常用的就是__init__, __call__,__iter__, __next__这些。
通常我们应用层面的方法名不要用dunders。

5. Single Underscore: “_”

有些场景我们根本用不着一个变量,只是遍历时需要这么个变量来用作临时使用罢了。

>>> for _ in range(32):...     print('Hello, World.')

或者一些无关业务逻辑的不重要的变量也可以用_来当做这个变量的名字

>>> car = ('red', 'auto', 12, 3812.4)>>> color, _, _, mileage = car>>> color'red'>>> mileage3812.4>>> _ 12

上面这个场景你只要返回元组的首尾的值,所以其他值可以用代替,即使的值期间被更新了一次都不重要。



作者:洛克黄瓜
链接:https://www.jianshu.com/p/dcc51072051e


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消