python如何将属性val1和val2添加到类中。python内部是否会调用b1.__shared_state'val1‘= 'Jaga Gola!’之类的东西?
# Borg (monostate pattern) lets a class have as many instances as one likes,
# but ensures that they all share the same state
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
b1 = Borg()
b2 = Borg()
print(b1 == b2)
b1.val1 = 'Jaga Gola!!!'
b1.val2 = 'BOOOM!!!'
print(b2.val1, b1.val2)为什么如果我删除了val1,我不能向类添加属性,就会得到错误: AttributeError:'Borg‘对象没有'val1’属性?
class Borg:
def __init__(self):
pass
b1 = Borg()
b2 = Borg()
print(b1 == b2)
b1.val1 = 'Jaga Gola!!!'
b1.val2 = 'BOOOM!!!'
print(b2.val1, b1.val2)发布于 2020-04-17 19:19:02
在此代码中:
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state__shared_state = {}行出现在类级别,因此它只添加到类Borg中一次,而不是添加到Borg类型的每个对象中。这与编写afterwards.self.__dict__ = self.__shared_state是一样的,因为它使用了self.两次,但效果却截然不同:self.something时,something是在对象self中设置的。self.something读取时,首先在self对象中查找something,如果在self对象中找不到,则在该对象的类中查找。这种想法听起来很奇怪,但实际上你一直在使用它:这就是方法通常的工作方式。例如,在s = "foo"; b = s.startswith("f")中,对象s没有属性startswith,但它的类str有属性,这就是在调用an时使用的属性
这一行:
b1.val1 = 'Jaga Gola!!!'最终转换为:
b1.__dict__['val1'] = 'Jaga Gola!!!'但是我们知道b1.__dict__等于Borg.__shared_state,所以它被赋值给它。然后:
print(b2.val1, ...翻译为:
print(b2.__dict__['val1'])再一次,我们知道b2.__dict__等于的 Borg.__shared_state,所以找到了val1。
如果去掉开头关于__shared_state的内容,那么b1和b2就会得到自己的__dict__对象,所以将val1放入b1的字典中不会对b2产生任何影响,这就是如何得到您提到的错误的。
这对于理解正在发生的事情来说是很好的,但是你应该意识到这些代码不能保证工作,并且可能会在Python的未来版本或其他实现(如PyPy )中崩溃。Python documentation for __dict__将其描述为“只读属性”,所以您根本不应该给它赋值。不要在其他人可能会运行的代码中这样做!
事实上,认为a.foo就是a.__dict__['foo']的想法是一个巨大的简化。首先,我们已经遇到了在阅读时有时后面跟着a.__class__.__dict__['foo']的情况。另一个例子是,a.__dict__显然不是a.__dict__['__dict__'],否则它将如何结束!?这个过程有些复杂,并且在the Data Model docs中有文档记录。
获得此行为的受支持方法是使用特殊的__setattr__和__getattr__方法(在这些数据模型文档中也有描述),如下所示:
class Borg:
__shared_state = {}
def __getattr__(self, name):
try:
return Borg.__shared_state[name]
except KeyError:
raise AttributeError
def __setattr__(self, name, value):
Borg.__shared_state[name] = value发布于 2020-04-17 19:27:20
这是一件有趣的事情,你正在做什么,它是基于可变性的:
您声明的初始__shared_state是在执行任何代码之前创建的。该字典称为类属性,因为它链接到类,而不是实例(不使用self进行声明)。这意味着__shared_state是在b1和b2之间共享的,因为它是在它们之前创建的,而且因为它是一个dict,所以它是可变的。
它是可变的是什么意思?
这意味着一个字典分配给两个不同的实例,将引用相同的内存地址,即使我们改变独占,内存地址也将保持不变。下面是一个探测器:
class Example:
__shared_state = {1: 1}
def __init__(self):
self.__dict__ = self.__shared_state
print(self.__shared_state)
ex1 = Example()
ex2 = Example()
print(id(ex1.__dict__), id(ex2.__dict__))
# Prints
# {1: 1}
# {1: 1}
# 140704387518944 140704387518944注意到它们是如何具有相同的id的吗?这是因为它们引用的是同一个对象,而且由于dictionary类型是可变的,所以在一个对象中更改字典意味着您要为这两个对象更改字典,因为它们是相同的:
# Executing this
ex1.val1 = 2
# Equals this
ex1.__dict__['val1'] = 2
# Which also equals this
Example.__shared_state['val1'] = 2 整数不会发生这种情况,因为整数是不可变的
class Example:
__shared_state = 2
def __init__(self):
self.a = self.__shared_state
print(self.__shared_state)
ex1 = Example()
ex2 = Example()
ex2.a = 3
print(id(ex1.a), id(ex2.a))
# Prints
# 2
# 2
# 9302176 9302208
# Notice that once we change ex2.a, its ID changes!当您删除__shared_state时,当您分配b1.val1 = 'Jaga Gola!!!'和b1.val2 = 'BOOOM!!!'时,它只是从b1分配给字典,这就是为什么当您尝试打印b2.val1和b2.val2时,它会引发错误。
https://stackoverflow.com/questions/61270179
复制相似问题