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?错了吗@贾米拉克