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