class variables for subclasses tuple
Peter Otten
__peter__ at web.de
Wed Mar 8 05:45:34 EST 2006
alainpoint at yahoo.fr wrote:
>
> Peter Otten wrote:
>> alainpoint at yahoo.fr wrote:
>>
>> > Point.x=0 leads to having p.x==0
>> > It seems not possible to have class variables and instance variable
>> > having the same name and yet different values.
>>
>> A quick check:
>>
>> >>> class T(tuple):
>> ... class __metaclass__(type):
>> ... x = property(lambda cls: 0)
>> ... x = property(lambda self: self[0])
>> ...
>> >>> t = T("abc")
>> >>> t.x
>> 'a'
>> >>> T.x
>> 0
>>
>> So possible it is. Come back if you're stuck generalizing the above.
>>
>> Peter
>
> Thanks for your magic answer.
> But i am not so good at magic ;-)
Once I grokked that a class is just an instance of its metaclass all magic
magically vanished :-)
> If i want to generalize to a arbitrary number of variables, i got
> syntax errors.
> Within a class, you can only method/class definitions and assignments.
> It is therefore difficult to do something like:
> for idx, attr_name in enumerate(attribute_names):
> setattr(__metaclass__,attr_name, property(lambda cls:idx)
> for idx, attr_name in enumerate(attribute_names):
> setattr(T,attr_name, property(lambda self:self[idx])
>
> Alain
I'm not getting syntax errors:
>>> names = "xyz"
>>> class T(tuple):
... class __metaclass__(type):
... pass
... for index, name in enumerate(names):
... setattr(__metaclass__, name, property(lambda cls,
index=index: index))
... del index
... del name
...
>>> for index, name in enumerate(names):
... setattr(T, name, property(lambda self, index=index: self[index]))
...
Traceback (most recent call last):
File "<stdin>", line 2, in ?
AttributeError: can't set attribute
However, the read-only property of the metaclass prevents setting the class
attribute. A workaround is to set the class properties /before/ the
metaclass properties. Here is a no-frills implementation, mostly untested:
from operator import itemgetter
def constgetter(value):
def get(self):
return value
return get
def make_tuple(*names):
class TupleType(type):
pass
class T(tuple):
__metaclass__ = TupleType
def __new__(cls, *args):
if len(names) != len(args):
raise TypeError
return tuple.__new__(cls, args)
for index, name in enumerate(names):
setattr(T, name, property(itemgetter(index)))
for index, name in enumerate(names):
setattr(TupleType, name, property(constgetter(index)))
return T
Peter
More information about the Python-list
mailing list