Connecting Tech Pros Worldwide Help | Site Map

class variables for subclasses tuple

alainpoint@yahoo.fr
Guest
 
Posts: n/a
#1: Mar 8 '06
Hello,

I have got a problem that i can't readily solve.
I want the following:
I want to create a supertuple that behaves both as a tuple and as a
class.
It should do the following:
Point=superTuple("x","y","z") # this is a class factory
p=Point(4,7,9)
assert p.x==p[0]
assert p.y==p[1]
assert p.z==p[2]
I already found a recipe to do that (recipe 6.7 in the Python
cookbook). I reproduce the code hereunder:
def superTuple(*attribute_names):
" create and return a subclass of `tuple', with named attributes "
# make the subclass with appropriate _ _new_ _ and _ _repr_ _
specials
typename='Supertuple'
nargs = len(attribute_names)
class supertup(tuple):
_ _slots_ _ = ( ) # save memory, we don't need
per-instance dict
def _ _new_ _(cls, *args):
if len(args) != nargs:
raise TypeError, '%s takes exactly %d arguments (%d
given)' % (
typename, nargs, len(args))
return tuple._ _new_ _(cls, args)
def _ _repr_ _(self):
return '%s(%s)' % (typename, ', '.join(map(repr, self)))
# add a few key touches to our new subclass of `tuple'
for index, attr_name in enumerate(attribute_names):
setattr(supertup, attr_name, property(itemgetter(index)))
supertup._ _name_ _ = typename
return supertup

Now my problem is: i would like to extend this supertuple with class
variables so that i can obtain the following:
assert Point.x==0
assert Point.y==1
assert Point.z==2
while still having:
assert p.x==p[0]
assert p.y==p[1]
assert p.z==p[2]
This is not the case unfortunately:
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.
Alain

Peter Otten
Guest
 
Posts: n/a
#2: Mar 8 '06

re: class variables for subclasses tuple


alainpoint@yahoo.fr wrote:
[color=blue]
> 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=blue][color=green][color=darkred]
>>> class T(tuple):[/color][/color][/color]
.... class __metaclass__(type):
.... x = property(lambda cls: 0)
.... x = property(lambda self: self[0])
....[color=blue][color=green][color=darkred]
>>> t = T("abc")
>>> t.x[/color][/color][/color]
'a'[color=blue][color=green][color=darkred]
>>> T.x[/color][/color][/color]
0

So possible it is. Come back if you're stuck generalizing the above.

Peter

alainpoint@yahoo.fr
Guest
 
Posts: n/a
#3: Mar 8 '06

re: class variables for subclasses tuple



Peter Otten wrote:[color=blue]
> alainpoint@yahoo.fr wrote:
>[color=green]
> > 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=green][color=darkred]
> >>> class T(tuple):[/color][/color]
> ... class __metaclass__(type):
> ... x = property(lambda cls: 0)
> ... x = property(lambda self: self[0])
> ...[color=green][color=darkred]
> >>> t = T("abc")
> >>> t.x[/color][/color]
> 'a'[color=green][color=darkred]
> >>> T.x[/color][/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 ;-)
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

alainpoint@yahoo.fr
Guest
 
Posts: n/a
#4: Mar 8 '06

re: class variables for subclasses tuple


As an supplement to my previous post, please find hereunder a snippet
for my unsuccessful attempt (commented out snippet does not work):
def superTuple(*attribute_names):
nargs = len(attribute_names)
class T(tuple):
def __new__(cls, *args):
return tuple.__new__(cls, args)
class __metaclass__(type):
x=property(lambda self:0)
y=property(lambda self:1)
z=property(lambda self:2)
x=property(lambda self:self[0])
y=property(lambda self:self[1])
z=property(lambda self:self[2])
#for idx, attr_name in enumerate(attribute_names):
# print 'attr name',attr_name, idx
# setattr(T.__metaclass__,attr_name, property(lambda cls:idx))
#for idx, attr_name in enumerate(attribute_names):
# print 'attr name',attr_name
# setattr(T,attr_name, property(lambda self:self[idx]))
return T
if __name__ == '__main__':
Point=superTuple('x','y','z')
p=Point(4,7,9)
assert p.x==p[0]
assert p.y==p[1]
assert p.z==p[2]
assert Point.x==0
assert Point.y==1
assert Point.z==2

Alain

Peter Otten
Guest
 
Posts: n/a
#5: Mar 8 '06

re: class variables for subclasses tuple


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

alainpoint@yahoo.fr
Guest
 
Posts: n/a
#6: Mar 8 '06

re: class variables for subclasses tuple


Thank you Peter, this does the job.
In passing, I have another question: where can I read up more on
metaclasses?
Alain

Peter Otten
Guest
 
Posts: n/a
#7: Mar 8 '06

re: class variables for subclasses tuple


alainpoint@yahoo.fr wrote:
[color=blue]
> In passing, I have another question: where can I read up more on
> metaclasses?[/color]

Well, in "Python in a Nutshell" Alex Martelli manages to pack the practical
information that lets you work with metaclasses into just four pages,
including a two-page example. You may have seen posts by Alex on c.l.py
that are longer...

Peter
Closed Thread