possible attribute-oriented class

Jan Kaliszewski zuo at chopin.edu.pl
Fri Sep 4 09:01:02 EDT 2009


[originally from python-list at python.org,
  crossposted to python-ideas at python.org]

04-09-2009 o 00:46:01 Ken Newton <krnewton at gmail.com> wrote:

> I have created the following class definition with the idea of making
> a clean syntax for non-programmers to created structured data within a
> python environment.
>
> I would appreciate comments on this code. First, is something like
> this already done? Second, are there reasons for not doing this?  If
> this seems OK, how could I clean up the string conversion to have
> indented format.
>
> The expected use would have all items in the structure be simple
> python types or AttrClass types. Code written in python could walk the
> structure in a simple way to locate any desired values. Code in a
> C/C++ extension should also be able to walk the structure to use any
> value in the structure.
>
> class AttrClass(object):
>     """AttrClass lets you freely add attributes in nested manner"""
>
>     def __init__(self):
>         pass
>     def __setitem__(self, key, value):
>         return self.__dict__.__setitem__(key, value)
>     def __repr__(self):
>         return "%s(%s)" % (self.__class__.__name__,  
> self.__dict__.__repr__())
>     def __str__(self):
>         ll = ['{']
>         for k,v in self.__dict__.iteritems():
>             ll.append("%s : %s" % (k, str(v)))
>         return '\n'.join(ll) + '}'
[snip]

I find the idea interesting and close to my own needs in many
situations, if I could alter it a bit.

Of course, we always can use an empty class ('class MyStruct: pass')
or simply use a dict... But both methods are inconvinient in some
ways.

In the case of dict we are convicted -- even when we need static
access -- to mapping notation (obj['member']) which is less
convenient and (what's more important) more error-prone than
attribute dot-notation.

In the case of empty class/object we can use convenient attr
dot-notation but dynamic access is less natural...

IMHO there could be -- in collections module or even as a built-in
factory function -- something (somehow) similar to namedtuple, but
mutable and more dict-like. I'am less focused on nesting such
structures, and more on making it a namespace-like objects with
convenience-and-today-usage features. Please consider the code:


   class AttrDict(dict):  # (or maybe from OrderedDict)
       "It's only a model. (Shhh!)"

       def __getattr__(self, name):
           if name.startswith('_'):
               raise AttributeError("AttrDict's key can't "
                                    "start with underscore")
           else:
               return self[name]

       def __setattr__(self, name, value):
           self[name] = value

       def __delattr__(self, name):
           del self[name]

       def __repr__(self):
           return '{0}({1})'.format(self.__class__.__name__,
                                      dict.__repr__(self))
       def __str__(self):
           return self._as_str()

       def _gen_format(self, indwidth, indstate):
           indst = indstate * ' '
           ind = (indstate + indwidth) * ' '
           yield ('\n' + indst + '{' if indstate else '{')
           for key, val in self.items():
               valstr = (str(val) if not isinstance(val, AttrDict)
                         else val._as_str(indwidth, indstate + indwidth))
               yield '{ind}{key}: {valstr}'.format(ind=ind, key=key,
                                                   valstr=valstr)
           yield indst + '}'

       def _as_str(self, indwidth=4, indstate=0):
           return '\n'.join(self._gen_format(indwidth, indstate))

       def _as_dict(self):
           return dict.copy(self)


   # Test code:
   if __name__ == '__main__':
       struct = AttrDict()
       struct.first = 1
       struct.second = 2.0
       struct.third = '3rd'
       struct.fourth = [4]
       print(struct)
       # output:
       # {
       #     'second': 2.0
       #     'fourth': [4]
       #     'third': '3rd'
       #     'first': 1
       # }

       del struct.fourth

       print(repr(struct))
       # output:
       # AttrDict({'second': 2.0, 'third': '3rd', 'first': 1})

       print(struct.first)  # (static access)
       # output:
       # 1

       for x in ('first', 'second', 'third'):
           print(struct[x])  # (dynamic access)
       # output:
       # 1
       # 2.0
       # 3rd

       struct.sub = AttrDict(a=1, b=2, c=89)
       print(struct._as_dict())
       # output:
       # {'second': 2.0, 'sub': AttrDict({'a': 1, 'c': 89, 'b': 2}),\
       #                                  'third': '3rd', 'first': 1}

       print(struct._as_str(8))
       # output:
       # {
       #         second: 2.0
       #         sub:
       #         {
       #                 a: 1
       #                 c: 89
       #                 b: 2
       #         }
       #         third: 3rd
       #         first: 1
       # }


What do you think about it?

Cheers,
*j

-- 
Jan Kaliszewski (zuo) <zuo at chopin.edu.pl>



More information about the Python-list mailing list