Using a class as a structure/container

Discussion in 'Python' started by david.car7@gmail.com, Feb 6, 2008.

  1. Guest

    Is it appropriate to use a class as a simple container in order to
    access attributes using a series of dot operators? Is their a more
    Pythonic way of doing this? For instance, I have a "container" class
    which is never instantiated directly, but only through another class.
    Access to certain attributes would be something like:

    main_class.a.b.x

    where row and v1 are instances of the container class which are
    instantianted by main_class. I know I can use dictionaries, but this
    syntax is a little clearer as long as the number of dot operators is
    not too lengthy. Some code would be something like:

    class container(object):
    def __init__(self):
    pass

    class main_class(object):
    def __init__(self):
    self.a = container()
    settatr(self.a, 'b', container())
    settatr(self.a.b, 'x', 2)

    Thanks in advance.
     
    , Feb 6, 2008
    #1
    1. Advertising

  2. Guest

    On Feb 5, 9:59 pm, wrote:
    > Is it appropriate to use a class as a simple container in order to
    > access attributes using a series of dot operators?  Is their a more
    > Pythonic way of doing this?  For instance, I have a "container" class
    > which is never instantiated directly, but only through another class.
    > Access to certain attributes would be something like:
    >
    >   main_class.a.b.x
    >
    > where row and v1 are instances of the container class which are
    > instantianted by main_class.  I know I can use dictionaries, but this
    > syntax is a little clearer as long as the number of dot operators is
    > not too lengthy.  Some code would be something like:
    >
    > class container(object):
    >     def __init__(self):
    >         pass
    >
    > class main_class(object):
    >     def __init__(self):
    >         self.a = container()
    >         settatr(self.a, 'b', container())
    >         settatr(self.a.b, 'x', 2)
    >
    > Thanks in advance.


    Oops. I meant "where a and b are instances..." instead of "where row
    and v1 are instances..." above. Sorry for the confusion.
     
    , Feb 6, 2008
    #2
    1. Advertising

  3. En Wed, 06 Feb 2008 00:59:48 -0200, <> escribi�:

    > Is it appropriate to use a class as a simple container in order to
    > access attributes using a series of dot operators? Is their a more
    > Pythonic way of doing this? For instance, I have a "container" class
    > which is never instantiated directly, but only through another class.
    > Access to certain attributes would be something like:
    >
    > main_class.a.b.x
    >
    > where row and v1 are instances of the container class which are
    > instantianted by main_class. I know I can use dictionaries, but this
    > syntax is a little clearer as long as the number of dot operators is
    > not too lengthy. Some code would be something like:
    >
    > class container(object):
    > def __init__(self):
    > pass


    You can omit the __init__ method if it's empty

    > class main_class(object):
    > def __init__(self):
    > self.a = container()
    > settatr(self.a, 'b', container())
    > settatr(self.a.b, 'x', 2)


    Usually written as:
    self.a.b = container()
    self.a.b.x = 2

    Nothing in the language forbids doing what you do, but I'd ask if the
    attributes may be split logically between the various containers, or it is
    an artificial division and they really should be attributes of the
    main_class.
    There are documentation problems too: such generic container cannot tell
    which attributes are valid or not; introspection tools cannot tell very
    much about the class; perhaps some code completion tools get confused. I
    don't like a long sequence of dots either.
    Using such a deep structure you are violating the Law of Demeter "Don't
    talk to strangers" http://en.wikipedia.org/wiki/Law_of_Demeter (altough I
    don't follow it strictly, things like xobj.parent.connection.user.name
    look wrong to me)

    Another problem of such generic container is that you don't get any
    meaningful information when printing it. You may find the NamedTuples
    recipe useful; look into the Python Cookbook
    http://www.activestate.com/ASPN/Python/Cookbook/ - or perhaps using this
    class:

    class Record(object):
    def __init__(self, **kw):
    self.__dict__.update(kw)

    def __repr__(self):
    values = ['%s=%r' % item
    for item in sorted(self.__dict__.iteritems())]
    return '%s(%s)' % (self.__class__.__name__, ','.join(values))

    __str__ = __repr__


    x = Record(a=1, b=2.0, c="three")
    print x
    # output: Record(a=1,b=2.0,c='three')



    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 6, 2008
    #3
  4. Guest

    On Feb 6, 2:18 am, "Gabriel Genellina" <> wrote:
    > En Wed, 06 Feb 2008 00:59:48 -0200, <> escribi�:
    >
    >
    >
    > > Is it appropriate to use a class as a simple container in order to
    > > access attributes using a series of dot operators?  Is their a more
    > > Pythonic way of doing this?  For instance, I have a "container" class
    > > which is never instantiated directly, but only through another class.
    > > Access to certain attributes would be something like:

    >
    > >   main_class.a.b.x

    >
    > > where row and v1 are instances of the container class which are
    > > instantianted by main_class.  I know I can use dictionaries, but this
    > > syntax is a little clearer as long as the number of dot operators is
    > > not too lengthy.  Some code would be something like:

    >
    > > class container(object):
    > >     def __init__(self):
    > >         pass

    >
    > You can omit the __init__ method if it's empty
    >
    > > class main_class(object):
    > >     def __init__(self):
    > >         self.a = container()
    > >         settatr(self.a, 'b', container())
    > >         settatr(self.a.b, 'x', 2)

    >
    > Usually written as:
    >          self.a.b = container()
    >          self.a.b.x = 2
    >
    > Nothing in the language forbids doing what you do, but I'd ask if the  
    > attributes may be split logically between the various containers, or it is  
    > an artificial division and they really should be attributes of the  
    > main_class.
    > There are documentation problems too: such generic container cannot tell  
    > which attributes are valid or not; introspection tools cannot tell very  
    > much about the class; perhaps some code completion tools get confused. I  
    > don't like a long sequence of dots either.
    > Using such a deep structure you are violating the Law of Demeter "Don't  
    > talk to strangers"http://en.wikipedia.org/wiki/Law_of_Demeter(altough I  
    > don't follow it strictly, things like xobj.parent.connection.user.name  
    > look wrong to me)
    >
    > Another problem of such generic container is that you don't get any  
    > meaningful information when printing it. You may find the NamedTuples  
    > recipe useful; look into the Python Cookbook  http://www.activestate.com/ASPN/Python/Cookbook/- or perhaps using this  
    > class:
    >
    > class Record(object):
    >      def __init__(self, **kw):
    >          self.__dict__.update(kw)
    >
    >      def __repr__(self):
    >          values = ['%s=%r' % item
    >                    for item in sorted(self.__dict__.iteritems())]
    >          return '%s(%s)' % (self.__class__.__name__, ','.join(values))
    >
    >      __str__ = __repr__
    >
    > x = Record(a=1, b=2.0, c="three")
    > print x
    > # output: Record(a=1,b=2.0,c='three')
    >
    > --
    > Gabriel Genellina


    Hi Gabriel,

    Thanks for the information. The reason why I was taking this approach
    was more from a user interface perspective. What I have is a file
    that contains certain geometric objects, lets call them geo. Each geo
    object has 4 possible surfaces: ps, ss, le, te. Each surface has
    x,y,z coordinates. It is not known apriori if any of these surfaces
    exist in the file. So I created a geo_reader class that is passed a
    filename in its argument list. It then parses the file, creating a
    container class for each geo object and assigning the name geo0, geo1,
    geo2, etc... as an attribute of the geo_reader class. The geo_reader
    class also stores global attributes concerning the file, i.e. the
    number of geo objects, etc... Then for each geo container I bind
    another container class for each surface that I find for each geo
    object, i.e. the ps, ss, le, te surfaces. Then the coordinates for
    each of the surfaces becomes an attribute of each of their
    corresponding containers. The user then can access the data as such:

    my_geo = geo_reader("thefilename")

    # get the number of geo objects in the file
    print my_geo.number_of_objects

    # get the number of surfaces for the geo0 object
    print my_geo.geo0.number_of_surfaces

    # get the x-coordinates for the ps surface of the geo0 object
    if has_attr(my_geo.geo0, 'ps', False): x_coords = my_geo.geo0.ps.x

    I can also bind certain attributes to the container class to tell
    whether its a geo object or surface, etc. I just didn't want the user
    to have to use the dictionary syntax like this:

    x_coords = my_geo['geo0']['ps']['x']

    It just seems a little more natural to use the dot operator approach
    for users to interface with. I wasn't aware of the Law of Demeter and
    I agree with all your concerns. I'm just not sure which one a user
    would rather interface with from the command line. The dot operators
    are quicker to type.

    Thanks for hyperlinks. Great reading. All the best

    -------
    David Car
     
    , Feb 7, 2008
    #4
  5. a écrit :
    (snip)
    > Thanks for the information. The reason why I was taking this approach
    > was more from a user interface perspective. What I have is a file
    > that contains certain geometric objects, lets call them geo. Each geo
    > object has 4 possible surfaces:


    You mean it has one of the 4 surfaces, or it has them all ?

    > ps, ss, le, te. Each surface has
    > x,y,z coordinates. It is not known apriori if any of these surfaces
    > exist in the file. So I created a geo_reader class that is passed a
    > filename in its argument list. It then parses the file, creating a
    > container class for each geo object and assigning the name geo0, geo1,
    > geo2, etc... as an attribute of the geo_reader class.


    You want an indexed ordered collection (ie: something like a list) here.

    > The geo_reader
    > class also stores global attributes concerning the file, i.e. the
    > number of geo objects,


    a list handle this.

    > etc... Then for each geo container I bind
    > another container class for each surface that I find for each geo
    > object, i.e. the ps, ss, le, te surfaces. Then the coordinates for
    > each of the surfaces becomes an attribute of each of their
    > corresponding containers.


    Err... Why don't you actually take time to write the Geo and Surface
    classes ? It will *really* save you time in the long run.

    > I can also bind certain attributes to the container class to tell
    > whether its a geo object or surface, etc.


    You definitively want to write the appropriate classes.

    > I just didn't want the user
    > to have to use the dictionary syntax like this:
    >
    > x_coords = my_geo['geo0']['ps']['x']


    As far as I'm concerned, I'd use a list-like interface for my_geo, ie:

    my_geo[0].ps.x

    And I'd define the four surface attributes of the Geo object, default
    them to either None or a NullSurface object (whose x and y attribs have
    the None value).

    > It just seems a little more natural to use the dot operator approach
    > for users to interface with.


    wrt/ attribute access, yes, indeed. wrt/ what is clearly an ordered
    collection, there's already a well defined interface !-)

    And anyway, this doesn't mean you should not properly define your
    classes - this is no more complex than what you're doing here, and it
    will make your code *way* more readable, maintainable and usable - even
    for your users, since they'll be able to introspect your objects type,
    print the docstrings (if you write them of course), eventually use
    autocompletion (cf the rlcompleter module) etc.

    > I wasn't aware of the Law of Demeter and
    > I agree with all your concerns. I'm just not sure which one a user
    > would rather interface with from the command line. The dot operators
    > are quicker to type.


    Indeed. Now if you have such concern, why not go all the way ?-)

    My 2 cents
     
    Bruno Desthuilliers, Feb 7, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. BCC
    Replies:
    1
    Views:
    353
    Karl Heinz Buchegger
    Jul 24, 2003
  2. Vivi Orunitia
    Replies:
    11
    Views:
    4,488
    Martijn Lievaart
    Feb 4, 2004
  3. Maitre Bart
    Replies:
    2
    Views:
    529
    Maitre Bart
    Feb 11, 2004
  4. Steven T. Hatton
    Replies:
    4
    Views:
    3,916
    Rob Williscroft
    Dec 5, 2004
  5. Replies:
    4
    Views:
    806
    Daniel T.
    Feb 16, 2006
Loading...

Share This Page