所谓私有变量,是指通过某种手段,使得对象中的属性或方法无法被外部所访问。属于Python的保护机制。
定义私有变量可以在变量名前加上两个 "_",来表示(这里说的私有变量并不是真正的私有,而是尽量避免从外部进行访问)
class C: #定义类C
def __init__(self,x): #定义带参构造函数
self.__x = x #定义私有变量
def set_x(self,x): #定义set_x方法,设置私用变量的值
self.__x = x
def get_x(self): #定义get_x方法,获取私有变量的值
print(self.__x)
c = C(22)
c.__x #从外部访问私有变量会报错
'''
Traceback (most recent call last):
File "", line 1, in
c.__x
AttributeError: 'C' object has no attribute '__x'
'''
c.get_x() #调用内部方法,访问私有变量
# 22
c.set_x(33)
c.get_x()
# 33
上述代码可知,我们从外部访问私有变量会产生错误,因为想访问私有变量的值,就需要通过指定的借口,通过调用内部的方法来实现访问私有变量。如果想从外部访问私有变量,我们可以利用Python的强访问方法—— name mangling机制 ,也就是名字改编。代码如下:
c.__dict__ #通过内省,查看实例对象中的数据
# {'_C__x': 33}
我们看到会得到{'_C__x': 33}的结果,也就是_类名__私有变量名,我们调用一下可以访问的到私有变量的值。
c._C__x
# 33
同样的,属性可以通过强访问的方式访问到,方法也是可以的,代码如下:
class Si:
def __funA(self): #定义私有方法
print("我是私有方法")
s = Si()
s.__funA()
'''
Traceback (most recent call last):
File "", line 1, in
s.__funA()
AttributeError: 'Si' object has no attribute '__funA'
'''
s._Si__funA() #强访问
# 我是私有方法
在对象诞生之后,通过动态添加属性的方式来添加私有变量。
c.__y = 250 向实例对象中添加数据
c.__dict__
# {'_C__x': 22, '__y': 250}
通过内省可以看到实例对象中有 __y 这个属性值,并且可以直接访问的到。并没有变成 _C__y 的形式,说明名字改编是发生在类实例化对象的时候的事情,之后添加的属性不会发生改变。
一个单横线开头的变量:通常是仅供内部使用的变量,不要随便的访问和试图修改。
一个单横线结尾的变量:一般用于要定义的变量名是属于Python关键字以及其他内部变量时,强制使用。(其实没啥用~)
def funA():
for_ = 100
print(for_)
funA()
# 100
当我们在实例对象中添加一个不存在的变量的时候,可以借助字典来完成,通过这种方法会很方便的向实例对象中添加数据,不过会浪费大量的存储空间。
class A: #定义类A
def __init__(self,x): #构造方法__init__
self.x = x
a = A(10) #对x进行赋值
a.x
# 10
a.y = 20 #向实例对象中添加属性y
a.y
# 20
a.__dict__ #查看实例对象中的属性值
# {'x': 10, 'y': 20}
a.__dict__['z'] = 30 #向实例对象中添加不存在的属性 z
a.z
# 30
a.__dict__
# {'x': 10, 'y': 20, 'z': 30}
这时Python就提供了一个叫做__slots__的类属性,避免了采用字典来存放造成空间上的浪费。采用这个方法可以限制类能使用的属性。
class B:
__slots__["x","y"] #限制该类中只能定义 x和y属性
def __init__(self,x):
self.x = x
b = B(20)
b.x
# 20
b.y = 30
b.y
# 30
b.z = 40 #像实例对象中加入__slots__中没有规定的数据时,会报错
#'B' object has no attribute 'z'
这种限制不仅体现在动态添加属性上面,如果我们想在类的内部创建一个__slots__中不包含的属性,也是不被允许的。
class B:
__slots__["x","y"] #限制该类中只能定义 x和y属性
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
b = B(20,30,40)
#'B' object has no attribute 'z'
__slots__类属性,使对象划分一个固定大小的空间来存放指定的属性,避免了利用字典来存放造成空间上的浪费(列表中的名称 用来限制类使用的属性)。
对于继承在父类的__slots__属性,不会在子类中生效,Python只会关注各个具体的类中定义的__slots__属性。
class B:
__slots__["x","y"] #限制该类中只能定义 x和y属性
def __init__(self,x):
self.x = x
class C(B): #定义类C,继承类 B
pass
c = C(20)
c.x
# 20
c.y = 30
c.y
# 30
c.z = 40 #定义继承类中不存在的属性
c.z
# 40 可以输出创建的属性值
c.__slots__
# ['x','y']
c.__dict__
# {'z',40}
对于继承的类中有__slots__属性时,父类中的属性会存放再__slots__中,而子类新添加的属性会存放在__dict__中。