Jan Kaliszewski wrote:
[originally from python-list@python.org,
 crossposted to python-id...@python.org]

04-09-2009 o 00:46:01 Ken Newton <krnew...@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

I like both suggestions. The dot notation is simpler than the dictionary one, in may cases.

struct is perhaps a name to avoid, as it is a standard module.

The result has similarities to the Pascal Record: http://uva.ulb.ac.be/cit_courseware/pascal/pas048.htm

Colin W.
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to