python中的下划线

作者: 洛克黄瓜 | 来源:发表于2018-12-13 22:04 被阅读22次
    • 前置的单下划线:_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.foo
    11
    >>> t._bar
    23
    
    • 模块中的import * 是有点区别的
    # my_module.py:
    def external_func():
        return 23
    def _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.__baz
    AttributeError:
    "'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__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'"
    

    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'
    >>> mileage
    3812.4
    >>> _ 
    12
    

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

    相关文章

      网友评论

        本文标题:python中的下划线

        本文链接:https://www.haomeiwen.com/subject/sekihqtx.html