平时写代码经常碰到下划线、双下划线等“奇怪”的写法,今天特意花时间彻底解决这个问题。文章内容主要参考《深入理解Python特性》一书。
意义:python社区约定好单下划线表达的是某种意思,本身不会影响程序的行为
# test_import.py文件内容
def hello():
print('Hello, world!')
def _world():
print('Hello, world!')
>>> from test_import import *
>>> hello()
Hello, world!
>>> _world()
Traceback (most recent call last):
File "", line 1, in
NameError: name '_world' is not defined
意义:名称被Python语言中的关键字占用的时候,就可以使用,比如class
,def
这些,使用class_
,def_
代替
这个估计经常遇到
意义:告诉python解释器重写属性名称,避免子类中的命名冲突。
dir()
可以查看对象的属性和方法__bar
前面双下划线的方法和变量,class Test:
def __init__(self):
self.foo = 12
self._bar = 24
self.__bar = 43
class ExtendedTest(Test):
def __init__(self):
super(ExtendedTest, self).__init__()
self.foo = 'hello'
self._bar = 'world'
self.__bar = 'down'
当创建ExtendedTest
类的实例t时,调用t.__bar
会报错AttributeError: 'ExtendedTest' object has no attribute '__bar'
。
具体来看一下原因:输入dir(t)
>>> dir(t)
['_ExtendedTest__bar', '_Test__bar', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__
', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'foo']
我们发现t
没有__bar
属性,而是变成了_ExtendedTest__bar
和_Test__bar
。这是因为Python进行了名称重写。
继续输入:t._ExtendedTest__bar
和t__Test__bar
,出现了down
和43
>>> t._ExtendedTest__bar
'down'
>>> t._Test__bar
43
.__bar
直接访问__bar
的值,只能借的类方法去访问或者是通过t._ExtendedTest__bar
。类似举例如下: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'"
class MangledMethod:
def __method(self):
return 42
def call_it(self):
return self.__method()
>>> MangledMethod().__method()
AttributeError: "'MangledMethod' object has no attribute '__method'"
>>> MangledMethod().call_it()
42
test()
方法用__mangled
就可以访问在MangledGlobal
类中访问全局变量_MangledGlobal__mangled
,因为Python的名称改写自动扩展了变量名。_MangledGlobal__mangled = 23
class MangledGlobal:
def test(self):
return __mangled
>>> MangledGlobal().test()
23
意义:如果使用前后双下划线,那么则不会发生名字重写,不受python解释器的影响。
__hash__
,__iter__
,__dict__
和__repr__
等其他内置函数,都是用前后双下划线for _ in range(10):
print('Hello, world! ')
>>> 20 + 3
23
>>> _
23
>>> print(_)
23
>>> list()
[]
>>> _.append(1)
>>> _.append(2)
>>> _.append(3)
>>> _
[1, 2, 3]
结束了…