alainpoint@yahoo.fr wrote:
[color=blue]
>
> Peter Otten wrote:[color=green]
>>
alainpoint@yahoo.fr wrote:
>>[color=darkred]
>> > 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.[/color]
>>
>> A quick check:
>>[color=darkred]
>> >>> class T(tuple):[/color]
>> ... class __metaclass__(type):
>> ... x = property(lambda cls: 0)
>> ... x = property(lambda self: self[0])
>> ...[color=darkred]
>> >>> t = T("abc")
>> >>> t.x[/color]
>> 'a'[color=darkred]
>> >>> T.x[/color]
>> 0
>>
>> So possible it is. Come back if you're stuck generalizing the above.
>>
>> Peter[/color]
>
> Thanks for your magic answer.
> But i am not so good at magic ;-)[/color]
Once I grokked that a class is just an instance of its metaclass all magic
magically vanished :-)
[color=blue]
> 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)[/color]
[color=blue]
> for idx, attr_name in enumerate(attribute_names):
> setattr(T,attr_name, property(lambda self:self[idx])
>
> Alain[/color]
I'm not getting syntax errors:
[color=blue][color=green][color=darkred]
>>> names = "xyz"
>>> class T(tuple):[/color][/color][/color]
.... class __metaclass__(type):
.... pass
.... for index, name in enumerate(names):
.... setattr(__metaclass__, name, property(lambda cls,
index=index: index))
.... del index
.... del name
....[color=blue][color=green][color=darkred]
>>> for index, name in enumerate(names):[/color][/color][/color]
.... 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