possible attribute-oriented class

Colin J. Williams cjw at ncf.ca
Fri Sep 4 11:12:51 EDT 2009


Jan Kaliszewski wrote:
> [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
> 
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.



More information about the Python-list mailing list