[EMAIL PROTECTED] wrote: > Fresh copies of class vars so the first one is the correct: ('foo', > 'bar', [], False)
Ahh, yeah, then you definitely need the copy.copy call. >>>> import copy >>>> >>>> class ClassVars(type): > ... def __init__(cls, name, bases, dict): > ... for name, value in type(cls).classVars.iteritems(): > ... if name not in dict: > ... setattr(cls, name, copy.copy(value)) > ... >>>> def are(**kwargs): > ... return type('', (ClassVars,), {'classVars':kwargs}) > ... >>>> class C(object): > ... __metaclass__ = are(name='foo', desc='bar', list=[]) > ... name = 'not foo' #<<< Changing a copy only owned by this class > ... >>>> class D(C): > ... pass > ... >>>> C.name, C.desc, C.list > ('not foo', 'bar', []) <<<<<<<<<<<<<<<<<<<<<< Separate copy we changed >>>> D.name, D.desc, D.list, D.list is C.list > ('foo', 'bar', [], False) <<<<<<<<<<<<<<<<<<<< Defaults are not changed Hmm... I don't think I can get away with just a function for __metaclass__ in this situation since D doesn't invoke it: >>> class C(object): ... def __metaclass__(*args): ... print '__metaclass__%r' % (args,) ... return type(*args) ... __metaclass__('C', (<type 'object'>,), {'__module__': '__main__', '__metaclass__': <function __metaclass__ at 0x00FA89F0>}) >>> class D(C): ... pass ... >>> I'm not sure why this is. Anyone else out there know? D *does* invoke __metaclass__ if it's a subclass of type: >>> class C(object): ... class __metaclass__(type): ... def __init__(*args): ... print '__init__%r' % (args,) ... __init__(<class '__main__.C'>, 'C', (<type 'object'>,), {'__module__': '__main__', '__metaclass__': <class '__main__.__metaclass__'>}) >>> class D(C): ... pass ... __init__(<class '__main__.D'>, 'D', (<class '__main__.C'>,), {'__module__': '__main__'}) >>> So it seems you pretty much have to go with the approach you're currently using. It doesn't make any real difference, but I'd tend to do it with a nested class statement instead of a call to type: >>> def set_classvars(**kwargs): ... class __metaclass__(type): ... def __init__(cls, name, bases, classdict): ... for name, value in kwargs.iteritems(): ... if name not in classdict: ... setattr(cls, name, copy.copy(value)) ... return __metaclass__ ... >>> class C(object): ... __metaclass__ = set_classvars(name='foo', desc='bar', list=[]) ... name = 'not foo' ... >>> class D(C): ... pass ... >>> C.name, C.desc, C.list ('not foo', 'bar', []) >>> D.name, D.desc, D.list, D.list is C.list ('foo', 'bar', [], False) > Thanks for your help btw. No problem. This is much more fun than doing real work. ;-) STeVe -- http://mail.python.org/mailman/listinfo/python-list