开发者

Does python has methods similar to __setattr__ but for python class?

开发者 https://www.devze.com 2023-03-22 18:56 出处:网络
Currently __setattr__ only works for instance. Is there any similar method for class? I am asking this question because I want to collect the list of defined attribute in order when user define it in

Currently __setattr__ only works for instance. Is there any similar method for class? I am asking this question because I want to collect the list of defined attribute in order when user define it in class as below:

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...')

I know the above code will not work as expected because the __setattr__ only called by instance as below:

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

So, is t开发者_如何学运维here any equivalent __setattr__ for python class? The main purpose is to collect the define attribute in order when user define it in class.


Yes, but 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


If you define __setattr__() on the metaclass of a class, it will be called when setting attributes on the class, but only after creating the class:

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

But it won't work at the time of class definition, so it's probably not what you want.

Getting the class attributes in the metaclass __init__() works, but you loose the order of definition (and multiple definitions as well).


What I would do to solve your problem - but not your question - is to set the timestamp of the field creation create a counter of Field objects and set the current value of the counter to the created one:

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()

Then I would create a method for returning all fields ordered by its counter value:

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

Its usage is intuitive:

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

print ACfg().params()

Clearly the fields are ordered by time of object creation, not field creation, but it can be enough for you. Is it?

0

精彩评论

暂无评论...
验证码 换一张
取 消