类和对象-变量
私有变量
私有变量: 通过某种手段,使得对象中的属性或方法无法被外部访问。在 Python 中仅限从一个对象内部才能访问的私有变量并不存在,但是 Python 引用了另外一个方法- name mangling 名称改写,语法为在名称的前方加两个连续下划线。
| Python |
|---|
| # 定义类并定义私有变量
class A:
def __init__(self, x):
self.__x = x
def set_x(self, x):
self.__x = x
def get_x(self):
print(self.__x)
# 此时无法在对象外部访问__x
a = A(250)
# 只可以通过get_x进行访问
print(a.get_x()) # 250
# 通过set_x进行修改__x
a.set_x(520)
print(a.get_x()) # 520
# 通过__dict__可以查看私有变量
print(a.__dict__) # {'_A__x': 520}
# 可以直接访问c._A__X访问私有变量值,格式:对象名加点然后类名加连续的双下划线再加变量名即可
print(a._A__x) # 520
# 定义类并定义一个私有方法,和私有变量类似
class B:
def __init__(self):
self.x = 1
def __func(self):
print("hello word", self.x)
def get_func(self):
self.__func()
b = B()
# 同样不可以直接使用私有方法
# 只能在对象的内部使用
b.get_func() # hello word 1
# 或者使用b._B__func(),不建议这样使用
b._B__func() # hello word 1
# 注意对象外部是不可以直接通过下表添加私有变量的
# 比如:b.__y = 250,这样不会发生异常,但是添加的也不是私有变量
|
定义下划线变量
单个下划线开头
仅供内部使用的变量,属于约定俗称的规则,不要随意的访问它,也不要随意的去修改它。
单个下划线结尾
通过结尾添加下划线可以是内置的 BIF 当成普通变量使用。
效率提升
Python 对象动态添加属性的方法属于字典的使用,通过使用 __dict__ 方法可以看到对应对象的属性,同样可以使用 __dict__方法直接设置对象的属性。
| Python |
|---|
| # 创建类
class A:
def __init__(self):
self.x = 1
# 创建对象
a = A()
# 通过__dict__查看对象的属性
print(a.__dict__) # {'x': 1}
# 通过对象创建属性
a.y = 100
print(a.__dict__) # {'x': 1, 'y': 100}
# 通过__dict__键值创建属性
a.__dict__["z"] = 300
print(a.__dict__) # {'x': 1, 'y': 100, 'z': 300}
|
字典的效率高,但是字典的占用内存空间却非常大, 动态添加属性的方法恰恰使用的是字典的方式,这样如果确定某个类的属性不会发生改变,这个时候可以使用 __slots__ 属性,避免用字典存放造成的空间浪费。这样通过类创建的对象就会划分固定的地址空间存放指定的属性,这也就是对象失去了动态创建属性的功能,进而 __dict__ 属性也就没有了。空间就节约下来了。
| Python |
|---|
| # 定义类
class A:
# 注意这里slots里面的属性定义完成后,在类中只可以有这些属性,可以暂且定义部分,另外的可以通过对象外部定义
__slots__ = ["x", "y"]
def __init__(self, x):
self.x = x
print(self.x)
# 按照指定的变量定义可以正常使用
a = A(1) # 1
# 可以通过对象外部定义y
a.y = 100 # y=100
# 有且只可以定义x和y
|
继承自父类的 __slots__属性是不会在子类中生效的,Python 只会关注各个具有的类中定义的 __slots__属性。
| Python |
|---|
| # 定义类A
class A:
__slots__ = ["x", "y"]
def __init__(self, x):
self.x = x
# 定义类B继承类A
class B(A):
pass
# 定义对象b
b = B(1)
# B继承A所以A的属性B同样可以使用
print(b.x) # 1
b.y = 100
print(b.y) # 100
# b可以随意动态的添加属性,不继承对应的__slots__限制
b.z = 300
print(b.z)
# 但是A的属性不会同步到B的属性中
print(b.__dict__) # {'z': 300}
# 同样查看b的__slots__属性可以发现有,但是这个属性是属于A的
print(b.__slots__) # ['x', 'y']
|