我需要为没有属性的字段定义__setattr__,但对有属性的字段使用setter/getter函数

5 投票
1 回答
6565 浏览
提问于 2025-04-16 10:27

定义 __setattr__ 会覆盖我在类中定义的所有设置方法和属性。我想在属性存在的情况下使用已定义的设置方法,如果没有属性,就用 self.__dict__[name] = value 来处理。

求助!我找到一个使用 __setitem__ 的解决方案,但对我来说不管用。

在 Python 类中,属性存储在哪里?我该如何访问它们?

我该如何定义 __setattr__,以便在有设置方法的字段上使用这些属性?

class test(object):

def _get_gx(self):
    print "get!"
    return self.__dict__['gx']

def _set_gx(self, gx):
    print "set!"
    self.__dict__['gx'] = gx
    gx = property(_get_gx, _set_gx)

def __setattr__(self, name, value):
    self.__dict__[name] = value

def __init__(self):
    pass

还有,

为什么当我执行时,“get!” 会被打印两次,

x = test()
x.gx = 4
x.gx

prints: 

   "gets!"
   "gets!"
   4

1 个回答

10

你需要重新写一下你的 __setattr__ 函数。根据文档,新风格的类应该使用 baseclass.__setattr__(self, attr, value),而不是 self.__dict__[attr] = value。前者会查找任何描述符,而后者只是直接给字典赋值。

所以把你的方法改成

def __setattr__(self, name, value):
    object.__setattr__(self, name, value)

或者

def __setattr__(self, name, value):
    super(Test, self).__setattr__(name, value)

这样就没问题了。代码

class Test(object):
    @property
    def gx(self):
        print "getting gx"
        return self.__dict__['gx']

    @gx.setter
    def gx(self, value):
        print "setting gx"
        self.__dict__['gx'] = value

    def __setattr__(self, attr, value):
        print "using setattr"            
        object.__setattr__(self, attr, value)

t = Test()
t.gx = 4
t.dummy = 5
print t.gx
print t.dummy

print dir(Test)

输出

using setattr
setting gx
getting gx
using setattr
4
5
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gx']

我不知道你版本的代码为什么会调用获取器两次,而这个版本不会。此外,关于描述符的位置,你可以很清楚地看到它在类字典的最后一项。

值得注意的是,你在例子中并不需要 __setattr__ 来实现你想要的功能。Python 总是会把赋值 foo.bar = x 写成 foo.__dict__['bar'] = x,无论 foo.__dict__ 中是否有这个条目。__setattr__ 是用来当你想要改变值、记录赋值或者其他类似操作时使用的。

撰写回答