# 私有化及_下划线命名
# 引言
Python中没有真正的私有属性或方法,没有真正的私有化,但有一些和命名有关的约定,让编程人员处理一些需要私有化的情况,我们常常需要区分私有方法、属性和公有方法、属性以方便管理和调用。
在变量、方法命名中有下列几种情况:
xx 公有变量/方法
_xx 前置单下划线- **建议 ** 不在外部使用
- import * 无法导入
__xx 前置双下划线- 无法在外部调用
- 使用名字重整技术将命名
object变为_Class_object的形式
__xx__ 前后双下划线- 魔法对象或属性,有着特殊作用。
xx_ 后置单下划线
# _单前置下划线
一般Python约定前置单下划线 _ 的属性和方法为私有方法或属性,以提示该属性和方法 不应 在外部调用。Python中的前置单下划线只是一个公认的约定,至少在涉及变量名和方法名时是这样的这个约定对Python解释器并没有特殊含义。PEP 8 中定义了这个约定( PEP 8 是最常用的 Python 代码风格指南)。
与Java不同,Python在 “私有” 和 “公共” 变量之间并没有很强的区别。
前置下划线会影响从模块中导入名称的方式,使用 通配符导入 从这个模块中导入所有名称时Python 不会 导入带有前置单下划线的名称(除非模块中定义了__all__ 列表覆盖了这个行为。
# demo.py
_key = '123'
def _set_key(key):
global _key
_key = key
# test.py
from demo import *
print(_key) # NameError: name '_key' is not defined
_set_key('567') # NameError: name '_set_key' is not defined
对此解释器会抛出异常:NameError: name '_key' is not defined。
但并非 demo.py 中的前置单下划线变量/方法在 test.py 中就不可以使用,完全可以 import module,然后通过 module.xxx 方式,test.py 代码做如下调整:
# test.py
import demo
print(demo._key) # 正常使用
demo._set_key('789') # 正常调用
print(demo._key) # 正常使用
# __前置双下划线
前置双下划线用于对象的数据封装,以此命名的属性或者方法为类的私有属性或者私有方法,在外部无法访问直接访问私有属性或方法。
Python会通过 名字重整 name mangling机制实现的,目的是以防类意外重写基类的方法或属性。
名字重整
name mangling 的技术,又叫name decoration命名修饰。在很多现代编程语言中,这一技术用来解决 需要唯一名称而引起的问题,比如命名冲突/重载等。
类中所有以双下划线开头的名称都会自动变成 _Class_object 的新名称,如 __name >>> _Foo__name ,我们可以用 dir()来查看类中成员详情。
通过这种机制可以阻止继承类重新定义或者更改方法的实现,如果在子类中向 __名字 赋值,那么会在子类中定义的一个与父类相同名字的属性。
# coding:utf8
class Foo(object):
def __init__(self):
self__name = "private attribute"
def getname():
return self.__name
def __method():
print("private method")
def run(self):
self.__method()
In [7]: dir(f)
Out[7]:
['_Foo__method',
'_Foo__name',
'__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__',
'getname',
'run']
In [8]: f._Foo__name
Out[8]: 'private attribute'
In [9]: f._Foo__method()
private method
# 前后双下划线
前后均带双下划线的命名,一般用于特殊方法的命名,用来实现对象的一些行为或者功能,比如 __new__() 方法用来创建实例,__init__() 方法用来初始化对象,x + y操作被映射为方法 x.__add__(y),序列或者字典的索引操作 x[k] 映射为x.__getitem__(k),__len__()、__str__() 分别被内置函数 len()、str()调用等等。
# 后置单下划线_
后置单下划线,用于避免与Python关键词的冲突。如下:
list_ = ["wang", "hui", "zack"]
dict_ = {
"name": "hui",
"age": 21
}