前置的单下划线:_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
共同学习,写下你的评论
评论加载中...
作者其他优质文章