python-神奇的下划线
2019-12-16 22:45:29
python中下划线有各种各样的作用,本章就来分别介绍一下各种下划线的功能。
一、开头单下划线 _VAR
开头单下划线还是挺常用的,在类中表示为保护变量/保护函数,但是需要注意的是,这个只是一种约定俗成,这不是Python强制规定的。
换言之,你依然可以访问一个类中以单下划线开头的变量或者方法而不报错。
class a: def __init__(self): self.a = 1 self._b = 2 def _func(self): print("Hello world.") if __name__ == "__main__": aa = a() print(aa.a) print(aa._b) aa._func()
上述的代码运行是完全没有任何的问题的,这是因为Python中的单个下划线前缀仅仅是一个约定 - 至少相对于变量和方法名而言。
但是,前导下划线的确会影响从模块中导入名称的方式。
假设你在一个名为my_module的模块中有以下代码:
# This is my_module.py: def external_func(): return 23 def _internal_func(): return 42
现在,如果使用通配符从模块中导入所有名称,则Python不会导入带有前导下划线的名称:
>>> from my_module import * >>> external_func() 23 >>> _internal_func() NameError: "name ‘_internal_func‘ is not defined"
当然,如果不是使用通配符进行的导入,那么依然是不会出现任何的问题的,事实上,我们也不建议使用通配符的方式来进行方法的导入。
二、开头双下划线 __VAR
上述的单下划线开头有点类似于君子协定,看到了就是告诉你这个是私有的,不能外部访问的,但是实际上你要外部访问也没辙。但是,开头双下划线的就不一样了,这个在python中有固定的使用方式的。
双下划线前缀会导致Python解释器重写属性名称,以避免子类中的命名冲突。
python会对以双下划线开头的变量或者方法的name进行重写(_ClassName__VAR),在外部访问的时候如果直接按照变量名访问就会报错。
class Test: def __init__(self): self.foo = 11 self._bar = 23 self.__baz = 23 def get_var(self): print(self.__baz) # 内部可以直接访问 def __method(self): print("This is method.") if __name__ == "__main__": a = Test() # print(a.__baz) # AttributeError: ‘Test‘ object has no attribute ‘__baz‘ print(a._Test__baz) # 对内透明 a.get_var() # a.__method() # AttributeError: ‘Test‘ object has no attribute ‘__method‘ a._Test__method()
三、开头末尾双下划线
如果一个名字同时以双下划线开始和结束,则不会应用名称修饰。 由双下划线前缀和后缀包围的变量不会被Python解释器修改:
class PrefixPostfixTest: def __init__(self): self.__bam__ = 42 >>> PrefixPostfixTest().__bam__ 42
但是,Python保留了有双前导和双末尾下划线的名称,用于特殊用途。 这样的例子有,__init__对象构造函数,或__call__ --- 它使得一个对象可以被调用。
这些dunder方法通常被称为神奇方法 - 但Python社区中的许多人(包括我自己)都不喜欢这种方法。
最好避免在自己的程序中使用以双下划线(“dunders”)开头和结尾的名称,以避免与将来Python语言的变化产生冲突。