def __init__(self,x):
self.__x=x
def set_x(self,x):
self.__x=x
def get_x(self):
print(self.__x)
c=C(250)
c.__x
Traceback (most recent call last):
File "<pyshell#249>", line 1, in <module>
c.__x
AttributeError: 'C' object has no attribute '__x'
c.get_x()
250
c.set_x(520)
c.get_x()
520
c.__dict__
{'_C__x': 520}
c._C__x
520
class D:
def __func(self):
print("hello fishc.")
d=D()
d.__func()
Traceback (most recent call last):
File "<pyshell#260>", line 1, in <module>
d.__func()
AttributeError: 'D' object has no attribute '__func'. Did you mean: '_D__func'?
d._D__func()
hello fishc.
c.__y=250
c.__dict__
{'_C__x': 520, '__y': 250} class C:
def __init__(self,x):
self.x=x
c=C(250)
c.x
250
c.__dict__
{'x': 250}
c.y=520
c.__dict__
{'x': 250, 'y': 520}
c.__dict__['z']=666
c.__dict__
{'x': 250, 'y': 520, 'z': 666}
c.z
666
class C:
__slots__=["x","y"]
def __init__(self,x):
self.x=x
c=C(250)
c.x
250
c.y=520
c.y
520
c.z=666
Traceback (most recent call last):
File "<pyshell#287>", line 1, in <module>
c.z=666
AttributeError: 'C' object has no attribute 'z'
class D:
__slots__=["x","y"]
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z
d=D(3,4,5)
Traceback (most recent call last):
File "<pyshell#295>", line 1, in <module>
d=D(3,4,5)
File "<pyshell#294>", line 6, in __init__
self.z=z
AttributeError: 'D' object has no attribute 'z'
class E(C):
pass
e=E(250)
e.x
250
e.y=520
e.y
520
e.z=666
e.__slots__
['x', 'y']
e.__dict__
{'z': 666} 私有变量是一种保护机制,指通过某种手段,使得对象中的属性或方法无法被外部所访问。Python引入的“name mangling”(名字改编、名称改写或名称修饰)机制可以实现“私有化”,只要在变量名前加上两个连续的下横线即可实现,方法名也与之类似。然而,Python其实是将该变量或方法偷换了名字,以此来掩人耳目;__dict__属性可以揭开真相,我们仍可通过“下横线+类名+私有变量名”或“下横线+类名+私有方法名”的方式访问到该变量或方法,只不过在现实中并不提倡这么做,毕竟这会违背私有化的初衷。事实上,Python给予程序员最大的自由度,并不存在仅限从对象内部访问的私有变量。此外,名字改编仅发生在类实例化对象时,实例化对象后添加的属性并不会被改编。
通常来说,单个下横线开头的变量是仅供内部使用的变量,尽量不要随意访问或修改;单个下横线结尾的变量可用于解决命名冲突(如与Python关键字重名)的问题,这是约定俗成的规则。
由于Python动态添加属性背后的实现原理是字典,以空间换时间,会牺牲大量的内存空间,因此,当我们不需要动态添加属性的功能时,便可以使用__slots__属性来避免利用字典造成的空间浪费。我们只需将必要的属性放入列表赋值给__slots__,这样对象就会划分一个固定大小的空间来存放指定的属性,省去了为__dict__属性划分的字典,有时可以大幅减少内存消耗,不失为一个好方法!继承自父类的__slots__属性是不会在子类中生效的,该子类仍可动态添加属性(拥有__dict__字典),因为Python只关注各个具体的类中定义的__slots__属性。虽然使用__slots__属性会牺牲Python动态语言的灵活性,但利用这一副作用又可以限制类属性的滥用,由此可见:技术永远是中立的,因地制宜,对症下药,方能实现最佳疗效! 本帖最后由 Ensoleile 于 2023-1-10 00:36 编辑
私有变量和__slots__()
#私有变量:P147 Name Mangling,
# 定义方法:__变量名,外部访问方法:_类名__变量名
#舍得之道:对象中灵活添加的属性,是用字典存储,字典效率快的背后是占用了大量内存(空间换时间)
class C:
def __init__(self, x):
self.x = x
c = C(250)
print(c.__dict__)
#{'x': 250}
c.__dict__['y'] = 520
print(c.__dict__)
#{'x': 250, 'y': 520}
#__slots__:如果已经明确一个类的对象设计出来不会有动态添加属性的需求,可以使用__slots__的类属性避免利用字典存放造成空间浪费
class D:
__slots__ = ['x', 'y'] #列表中的就是希望的属性名
def __init__(self, x):
self.x = x
d = D(10)
d.y = 20
print(d.x, d.y, sep=' ')
try:
print(d.__dict__)
except AttributeError as e:
print(e)
#'D' object has no attribute '__dict__'
try:
d.z = 66
except AttributeError as e:
print(e)
#'D' object has no attribute 'z'
#类的内部同样不允许创建__slots__不包含的属性
class D:
__slots__ = ['x', 'y']
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
# d = D(3, 4, 5)
#AttributeError: 'D' object has no attribute 'z'
#使用__slots__后,对象就会划分一个固定大小的空间来存放指定属性
#__slots__限制动态添加属性,也可以用来防止属性的滥用
#继承在父类的__slots__属性不会在子类中生效
class E(C):
pass
e = E(3)
e.z = 10
print(e.__dict__)
#{'x': 3, 'z': 10}
print(e.__slots__)
#AttributeError: 'E' object has no attribute '__slots__' Ensoleile 发表于 2023-1-2 23:06
私有变量和__slots__()
感谢,以后我也要边学边记笔记然后发评论区
子类继承__solts__的属性,不会对新加属性造成影响 class C:
def __init__(self,x):
self.__x = x
def set_x(self,x):
self.__x = x
def get_x(self):
print(self.__x)
get私有变量 下节课没知识备忘了,也没作业了{:10_266:} {:10_257:}{:10_257:}{:10_257:} 懂了,就像电算时代之前,银行不乐意给个人储户开活期储存,以缩限每个账户(存折)属性量,进而大大减小人工操作和局端存底成本。 在线等,求教:一个函数中如何添加多个私有变量啊{:9_241:} leizhenzi23 发表于 2024-1-22 14:14
在线等,求教:一个函数中如何添加多个私有变量啊
请问你是说这样子吗
class A:
def __init__(self,x,y):
self.__x=x
self.__y=y
>>> class E(C):
... pass
...
>>> e = E(250)
>>> e.x
250
>>> e.y = 520
>>> e.z = 666
>>> e.__slots__
['x', 'y']
在最后的这个继承中,为什么e.__dict__中只有z,没有x,y呢 # 1. 私有变量
# 在大多数面向对象的编程语言中,都存在着私有变量(private variable)的概念,所谓私有变量,就是指通过某种手段,使得对象中的属性或方法无法被外部所访问。
# Python对于私有变量的实现是引入了一种叫name mangling 的机制(翻译过来叫“名字改编”“名称改写”或者“名称修饰”),语法是在变量名前面加上两个连续下划线(__)
class C:
def __init__(self, x):
self.__x = x
def set_x(self, x):
self.__x = x
def get_x(self):
print(self.__x)
c = C(250)
#此时,我们是无法直接通过变量名访问到该变量的:
# c.__x
# Traceback (most recent call last):
# File "<pyshell#13>", line 1, in <module> c.__x
# AttributeError: 'C' object has no attribute '__x
#想要访问变量的值,就需要使用指定的接口,比如这段代码中的 set_x() 和 get_x() 方法:
c.get_x()
c.set_x(520)
c.get_x()
#2. name mangling 机制的实现原理 我们看看 __dict__ 属性里面有啥:
print(c.__dict__)#虽然这里面没有看到 __x,但是,却多了一个 _C__x 的属性对不对?
#访问一下试试:
print(c._C__x) #果然如此……这个就是传说中的名字改编术!
#方法名也是同样的道理:
class D:
def __func(self):
print("Hello FishC.")
d = D()
#d.__func()
# Traceback (most recent call last):
# File "<pyshell#12>", line 1, in <module>
# d.__func() AttributeError: 'D' object has no attribute '__func'
d._D__func()
#注意:name mangling 机制是发生在类实例化对象时候的事情,给对象动态添加属性则不会有同样的效果!!!
# 3. 不同数量的前缀下划线含义
# 不同数量的前缀下划线均有不同的特殊含义:
# 单下划线前缀_FishC仅供内部使用的变量(约定俗成,无强制措施)
# 双下划线前缀__FishC私有变量,Python 启用 name mangling 机制修改变量名称
# 单下划线后缀class_通常为了避免与 Python 关键字命名冲突使用,比如想定义一个叫class的变量名,但无奈class是属于 Python 的关键字,所以你可以写成 class_
# 前后均有双下划线__init__Python 魔法方法的命名方案,我们应该避免自己的属性使用这种命名形式
# 单独一个下划线_表示一个临时变量,在 IDLE 的交互模式中,_ 是最后一个表达式的结果
# 4. 效率提升之道
# Python 对象存储属性的工作原理 —— 字典(__dict__):
# 对象动态添加属性,就是将键值对添加到 __dict__ 中:
# 甚至你可以直接通过给字典添加键值对的形式来创建对象的属性:c.__dict__['z'] = 666
# 但是,字典高效率的背后是以付出更多存储空间为代价的(字典和集合高效背后的玄机)
# 如果我们明确知道一个类的对象设计出来,就只是需要那么固定的某几个属性,并且不需要有动态添加属性这样的功能,那么利用字典来存放属性,这种空间上的牺牲就是纯纯地浪费!
# 针对这个情况,Python 专门设计了一个 __slots__ 类属性,避免了利用字典存放属性造成空间上的浪费
class C:
__slots__ = ['x', 'y']
def __init__(self, x):
self.x = x
c = C(250)
print(c.x)
c.y=666
print(c.y)
#如果想要动态地添加一个属性,那就不好意思了:
# c.z = 100
# Traceback (most recent call last):
# File "<pyshell#27>", line 1, in <module>
# c.z = 100
# AttributeError: 'C' object has no attribute 'z'
# 这种限制不仅体现在动态添加属性上,如果在类的内部,想创建一个 __slots__ 不包含的属性,也是不被允许的
class D:
__slots__ = ['x', 'y']
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
# d = D(3, 4, 5)
# File "<pyshell#6>", line 6, in __init__
# self.z = z
# AttributeError: 'D' object has no attribute 'z'
# 甚至是 __dict__ 属性,也不存在了:
#d.__dict__
# AttributeError: 'D' object has no attribute '__dict__'
#因为使用了 __slots__ 属性,那么对象就会划分一个固定大小的空间来存放指定的属性,这时候 __dict__ 属性就不需要了,空间也就节约了出来。
# 不过这里有一点是需要特别强调的,就是使用 __slots__ 属性的副作用其实也相当明显,那就是要以牺牲 Python 动态语言的灵活性,作为前提。
# 使用了 __slots__ 属性,就没办法再拥有动态添加属性的功能了……
# 这可以说是它的一个副作用,但实际上很多开发者却利用这个副作用,来限制类属性的滥用4
#最后,还有一点需要大家知道的是,继承自父类的 __slots__ 属性是不会在子类中生效的,Python 只关注各个具体的类中定义的 __slots__ 属性:
class E(C):
pass
e = E(250)
e.x
e.y = 520
e.z = 666
print(e.__slots__) #对象 e 虽然拥有 __slots__ 属性,但它同时也拥有 __dict__ 属性:
print(e.__dict__)
页:
[1]