- 前置的单下划线:_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
上面这个场景你只要返回元组的首尾的值,所以其他值可以用代替,即使的值期间被更新了一次都不重要。
网友评论