Python,如何在作为重载该方法的类的一部分的dictionary对象上使用_usetattr__uu?
如下面的代码所示,为什么我不能使用Python,如何在作为重载该方法的类的一部分的dictionary对象上使用_usetattr__uu?,python,python-2.7,setattr,Python,Python 2.7,Setattr,如下面的代码所示,为什么我不能使用\uuuu setattr\uuuu来设置dict上的值,dict是重载该方法的类的一部分?我原以为b.hello不存在 class MyClass(): datastore = {} def __init__(self): self.datastore = {} def __getattr__(self, key): return self.datastore[key] def __set
\uuuu setattr\uuuu
来设置dict上的值,dict是重载该方法的类的一部分?我原以为b.hello
不存在
class MyClass():
datastore = {}
def __init__(self):
self.datastore = {}
def __getattr__(self, key):
return self.datastore[key]
def __setattr__(self, key, value):
self.datastore[key] = value
a = MyClass()
b = MyClass()
a.hello = "err"
print a.hello # err
print b.hello # err
b.hello
打印字符串“err”,因为datastore
是类本身的属性,而不是类的对象的属性。因此,当您在a
中初始化它时,b
也可以访问它
因此,从类中删除datastore={}
此外,在Python中:
如果\uuuu setattr\uuuu()
想要分配给实例属性,它应该
不仅仅是执行self.name=value
——这将导致递归
自言自语。相反,它应该在字典中插入值
实例属性,例如,self.\uuu dict\uuu[name]=value
。对于
新样式的类,而不是访问实例字典,它
应该使用相同的名称调用基类方法,例如,
object.\uuuuu setattr\uuuuu(自我、名称、值)
因此,将代码更改为:
class MyClass(object): # Use new style classes
def __init__(self):
object.__setattr__(self, 'datastore', {}) # This prevents infinite recursion when setting attributes
def __getattr__(self, key):
return self.datastore[key]
def __setattr__(self, key, value):
self.datastore[key] = value
a = MyClass()
b = MyClass()
a.hello = "err"
print a.hello # Works
print b.hello # Gives an error
首先让我解释一下为什么会发生这种情况:
class MyClass():
datastore = {}
def __init__(self):
self.datastore = {} # calls __setattr__
如您所见,\uuuuu init\uuuu
中的第一个变量定义最终调用了\uuuu setattr\uuuuu
def __setattr__(self, key, value):
self.datastore[key] = value
该实例尚未具有数据存储
属性,因为它仍在定义过程中。因此,这一行self.datastore[key]=value
首先尝试在实例的\uuu dict\uuu
中查找数据存储,但找不到它!然后它在类树中查找一个级别,并在其中找到它,作为类属性
记住这一点:
class MyClass():
datastore = {}
这一点一开始就相当混乱,因为实例变量和类变量都具有相同的名称,所以应该而不是两者都具有
因此,您可以将\uuuu init\uuuu
更改为:
object.__setattr__(self, 'datastore', {})
就像@Dhara建议的那样,或者你可以使用我推荐的更一般的方法:
super(MyClass, self).__setattr__('datastore', {})
其中后一个选项仅适用于您应该使用的新样式类(在各个方面都更好!)!
只需添加对象
作为超类即可
class MyClass(object): # In Py3k you don't need to since all classes are newstyle
有一点需要注意:
def __setattr__(self, key, value):
self.datastore[key] = value
仅在设置字典的键而不是实例的属性时才起作用。小心不要做像这样的事情
def __setattr__(self, key, value):
self.datastore = {} # for example
因为这将导致无限递归,如果您想在\uuuuu setattr\uuuuu
中执行类似的操作,请使用以前的相同技巧:
def __setattr__(self, key, value):
super(MyClass, self).__setattr__('datastore', {})
最终结果应该如下所示:
class MyClass(object):
def __init__(self):
super(MyClass, self).__setattr__('datastore', {})
def __getattr__(self, key):
return self.datastore[key]
def __setattr__(self, key, value):
self.datastore[key] = value
a = MyClass()
b = MyClass()
a.hello = "err"
print a.hello
print b.hello
谢谢你的完美解释。你能解释一下你写的代码吗:def u setattr uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?为什么我们需要这个?我理解这里和其他答案中的所有代码。我唯一没有接到的就是这个超级电话。为什么我们需要这个?如果你想知道原因,只需删除super(MyClass,self)。\uuuu setattr\uuuu('datastore',{})
并将其更改为self.datastore={}
,然后试着运行a=MyClass()
,看看发生了什么事为什么我们不能简单地说self[name]=value?错了吗@贾米拉克