python是否有类似于__setattr__的方法但是对于python类?

时间:2011-07-24 16:16:48

标签: python

目前 __ setattr __ 仅适用于实例。上课有类似的方法吗?我问这个问题是因为当用户在课堂上定义时,我想按顺序收集已定义属性的列表:

class CfgObj(object):
    _fields = []
    def __setattr__(self, name, value):
        self._fields.append([name, value])
        object.__setattr__(self, name, value)

class ACfg(CfgObj):
    setting1 = Field(str, default='set1', desc='setting1 ...')
    setting2 = Field(int, default=5, desc='setting2...')

我知道上面的代码无法按预期工作,因为 __ setattr __ 仅按实例调用如下:

acfg = ACfg()
acfg.c = 1
acfg._fields == [['c', 1]]

那么,python类有没有等效的 __ setattr __ ?主要目的是在用户在类中定义时按顺序收集define属性。

3 个答案:

答案 0 :(得分:3)

是的,但是that's not how you want to do it

class MC(type):
  def __init__(cls, name, bases, dct):
    print dct
    super(MC, cls).__init__(name, bases, dct)

class C(object):
  __metaclass__ = MC
  foo = 42

答案 1 :(得分:3)

如果在类的元类上定义__setattr__(),则在类上设置属性时会调用它,但仅在创建类后才会调用:

>>> class Meta(type):
...     def __setattr__(cls, name, value):
...         print "%s=%r" % (name, value)
... 
>>> class A(object):
...     __metaclass__ = Meta
... 
>>> A.a = 1
a=1

但是在课程定义时它不起作用,所以它可能不是你想要的。

获取元类__init__()中的类属性有效,但是你失去了定义的顺序(以及多个定义)。

答案 2 :(得分:0)

我将如何解决您的问题 - 而不是您的问题 - 是设置字段创建的时间戳创建一个计数器Field个对象,并将计数器的当前值设置为创建的对象:

class Field(object):
    count = 0
    def __init__(self, value, default=None, desc=None):
        self.value = value
        self.default = default
        self.desc = desc
        # Here comes the magic
        self.nth = Field.count
        Field.count += 1
        # self.created_at = time.time()

然后我会创建一个方法来返回按其计数器值排序的所有字段:

class CfgObj(object):
    def params(self):
        ns = dir(self)
        fs = [getattr(self, field) 
                    for field in ns 
                    if isinstance(getattr(self, field), Field)]
        # fs = sorted(fs, key=lambda f: f.created_at)
        fs = sorted(fs, key=lambda f: f.nth)
        return fs

它的用法很直观:

class ACfg(CfgObj):
    setting1 = Field(str, default='set1', desc='setting1 ...')
    setting2 = Field(int, default=5, desc='setting2...')

print ACfg().params()

显然,字段按对象创建时间排序,而不是 field 创建,但对您来说已经足够了。是吗?