class variables for subclasses tuple

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • alainpoint@yahoo.fr

    #1

    class variables for subclasses tuple

    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=superTupl e("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(*att ribute_names):
    " create and return a subclass of `tuple', with named attributes "
    # make the subclass with appropriate _ _new_ _ and _ _repr_ _
    specials
    typename='Super tuple'
    nargs = len(attribute_n ames)
    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(attri bute_names):
    setattr(supertu p, attr_name, property(itemge tter(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

    #2
    Re: class variables for subclasses tuple

    alainpoint@yaho o.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__(t ype):
    .... 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

    Comment

    • alainpoint@yahoo.fr

      #3
      Re: class variables for subclasses tuple


      Peter Otten wrote:[color=blue]
      > alainpoint@yaho o.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__(t ype):
      > ... 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(attri bute_names):
      setattr(__metac lass__,attr_nam e, property(lambda cls:idx)
      for idx, attr_name in enumerate(attri bute_names):
      setattr(T,attr_ name, property(lambda self:self[idx])

      Alain

      Comment

      • alainpoint@yahoo.fr

        #4
        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(*att ribute_names):
        nargs = len(attribute_n ames)
        class T(tuple):
        def __new__(cls, *args):
        return tuple.__new__(c ls, args)
        class __metaclass__(t ype):
        x=property(lamb da self:0)
        y=property(lamb da self:1)
        z=property(lamb da self:2)
        x=property(lamb da self:self[0])
        y=property(lamb da self:self[1])
        z=property(lamb da self:self[2])
        #for idx, attr_name in enumerate(attri bute_names):
        # print 'attr name',attr_name , idx
        # setattr(T.__met aclass__,attr_n ame, property(lambda cls:idx))
        #for idx, attr_name in enumerate(attri bute_names):
        # print 'attr name',attr_name
        # setattr(T,attr_ name, property(lambda self:self[idx]))
        return T
        if __name__ == '__main__':
        Point=superTupl e('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

        Comment

        • Peter Otten

          #5
          Re: class variables for subclasses tuple

          alainpoint@yaho o.fr wrote:
          [color=blue]
          >
          > Peter Otten wrote:[color=green]
          >> alainpoint@yaho o.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__(t ype):
          >> ... 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(attri bute_names):
          > setattr(__metac lass__,attr_nam e, property(lambda cls:idx)[/color]
          [color=blue]
          > for idx, attr_name in enumerate(attri bute_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__(t ype):
          .... pass
          .... for index, name in enumerate(names ):
          .... setattr(__metac lass__, 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(val ue):
          def get(self):
          return value
          return get

          def make_tuple(*nam es):
          class TupleType(type) :
          pass

          class T(tuple):
          __metaclass__ = TupleType
          def __new__(cls, *args):
          if len(names) != len(args):
          raise TypeError
          return tuple.__new__(c ls, args)
          for index, name in enumerate(names ):
          setattr(T, name, property(itemge tter(index)))

          for index, name in enumerate(names ):
          setattr(TupleTy pe, name, property(constg etter(index)))

          return T

          Peter

          Comment

          • alainpoint@yahoo.fr

            #6
            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

            Comment

            • Peter Otten

              #7
              Re: class variables for subclasses tuple

              alainpoint@yaho o.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

              Comment

              Working...