Python类是否有类似于__setattr__的方法?
目前,__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__ 的方法呢?我的主要目的是在用户定义类的时候,按顺序收集定义的属性。
3 个回答
3
是的,不过这样做并不是你想要的方式。
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
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__()
中获取类的属性是可以的,但这样会失去定义的顺序(还有可能会出现重复定义的问题)。
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()
显然,这些字段是按照对象创建的时间来排序的,而不是字段创建的时间,但这可能对你来说已经足够了。这样可以吗?