possible attribute-oriented class

2009-09-03 Thread Ken Newton
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) + '}'

def test():
atr = AttrClass()
atr.first = 1
atr.second = 2
atr.third = 'three'

atrsub = AttrClass()
atrsub.aaa = 'AAA'
atrsub.bbb = 'BBB'

atr.fourth = atrsub
atr.fifth = 5

print atr
print
print repr(atr)
print
print atr.fourth.aaa
=
 test() gives the following output:

{
second : 2
fifth : 5
fourth : {
aaa : AAA
bbb : BBB}
third : three
first : 1}

AttrClass({'second': 2, 'fifth': 5, 'fourth': AttrClass({'aaa': 'AAA',
'bbb': 'BBB'}), 'third': 'three', 'first': 1})

AAA


Ken Newton
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: possible attribute-oriented class

2009-09-03 Thread Ken Newton
On Thu, Sep 3, 2009 at 4:30 PM, Steven D'Aprano <
st...@remove-this-cybersource.com.au> wrote:

> On Thu, 03 Sep 2009 15:46:01 -0700, Ken Newton 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.
>
> What do you expect non-programmers to do with this class, without
> programming? How can they even use it?
>

A couple extra details: The users are scientists, and technically
sophisticated.
They are used to specifying complicated sets of parameters and this
structured
form matches the way they are used to thinking about their work. Though they
are not programmers, they can define expressions to represent the desired
calculations for this project and occasionally write small programs in the
course
of their work. However, they will not like a long learning curve and will
want to be
isolated from most of the details in good programming design (error
handling,
creating supporting infrastructure, etc.)  In this case, Python will be used
as
a scripting language with most of the details specified by simple function
expressions
or defining structured data or specifying (linear) sequences of actions.

...
> > 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.
>
> I don't see the purpose of it. Nested data structures are generally
> harder for people to understand than non-nested ones, hence the Python
> Zen: "flat is better than nested". For example, a list is easier to grasp
> than a tree. This especially applies to non-programmers.
>
> I don't see how this is simple enough for non-programmers, or useful for
> programmers. For programmers, just nest objects:
>
> class Parrot(object):
>pass
>
> obj = Parrot()
> obj.x = 1
> obj.y = Parrot()
> obj.y.z = 2
> obj.y.z.zz = Parrot()


This is close to what I started with when I started exploring this idea.
But I felt I needed a way to create some additional support, that is
the str and repr functions.  These structures will be created and
populated once and saved in a python source file, which will be
loaded from the embedding C++ program.  The (scientist) users will
need a way to review the structure and current values while
interactively changing a few of the values to observe their effect on
the system.  My recursive __str__() and __repr__() functions were
intended to provide that support.


> > class AttrClass(object):
> > """AttrClass lets you freely add attributes in nested manner"""
>
> You don't actually need a special class for that, unless you're providing
> extra functionality. A bare subclass of object will let you freely add
> attributes in a nested manner.
>
> It seems to me that you're combining two different sets of functionality,
> but only describing one. The first is, nested attributes -- but you get
> that for free with any class. The second is the ability to set (but
> strangely not retrieve!) attributes using dictionary-like syntax. But
> that's implied by the code, you haven't mentioned it in your description
> or documentation.
>
>
> > def __init__(self):
> > pass
>
> If the __init__ method doesn't do anything, you don't need it.


Good point. This was a placeholder. My intention was to add some
code to initialize the class from a dict. But didn't get around to
implementing that. Or the ideas I tried (couple years ago) didn't work.



> > def __setitem__(self, key, value):
> > return self.__dict__.__setitem__(key, value)
>
> Simpler to just say:
>
> def __setitem__(self, key, value):
> self.__dict__[key] = value
>
> You don't strictly need the return, because methods return None by
> default, and dict.__setitem__ always returns None (unless it raises an
> exception).
>

Now, I can't remember why I ended up with my strange syntax.  Unless
it was related to the fact that I started doing this in IronPython and this
made it work better in that context or on the C# side of things.  I'm now
planning this for a CPython embedding situation.  And, perhaps as  you
pointed out, the __setitem__ isn't needed at all in the code I showed.


>
> This method allows you to set attributes using dict syntax:
>
>instance['key'] = 123  # same as instance.key = 123
>
> But you don't have corresponding __getitem__ or __delitem__ methods, so
> you can't do these

Re: possible attribute-oriented class

2009-09-04 Thread Ken Newton

I like this version very much. I'm ready to put this into practice to see
how it
works in practice.

A minor point: I envision this to be used in a context where all key values
are
strings (legal attribute identifiers). But constructing an AttrClass from a
dict
or setting values directly with the dict syntax can allow any valid item as
a
dict key -- specifically numbers, tuples, etc. If the user of this class
chooses
to do this, a number of the items become inaccessible to the attribute
syntax.
In my case, I think this won't be a problem since I anticipate that values
will
always be set by the attribute syntax, but it might be an issue for other
uses.


On Fri, Sep 4, 2009 at 6:01 AM, Jan Kaliszewski  wrote:

> [originally from python-list@python.org,
>  crossposted to python-id...@python.org]
>
[snip]

>  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) 
>
> --
> http://mail.python.org/mailman/listinfo/python-list
>
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: possible attribute-oriented class

2009-09-04 Thread Ken Newton
On Fri, Sep 4, 2009 at 9:49 PM, Steven
D'Aprano wrote:
...
>
>> The old discussion, the above link points to, shows that such a
>> dot-accessible dict-like class is something that many people need and
>> repeatedly implemet it (more or less perfectly) for themselves.
>
> I think it's something which people copy from other languages because
> that's what they're used to, not because they need it.
>
> It's just a change in syntax. Whether you write x.key or x['key'] is a
> matter of convenience. Attribute access is optimized for when you know
> the key names at compile time, key access is optimized for when you don't
> know the names until runtime. Compare:
>
> # You know the key when you write the code.
> x.key versus x['key']
>
> # You don't know the key until runtime.
> s = get_key()
> getattr(x, s) versus x[s]
...

I would think this is much more than just copy from other language styles or
'just' a syntax change -- the apparent widespread use would hint at a deeper
need.  For my use, the need is the significant simplification in interactive use
(less and easier typing for x.key than x['key']).  Even for the cases where
my anticipated users will save lines of code in a script or module, they will
do this in a context where they do generally know the keys when they write
their code. ...And they will appreciate the simpler semantics of the attribute
access.  In my case also, execution speed will not be critical. This class will
be used as a set of configuration parameters that will generally not be applied
in time critical loops, but in occasional use generation of parameterized
method sequences to control a main application coded in C/C++.

The C interface is a reason that it would be nice to see this as a
basic type rather
than an add-on module.  Having an API pre-defined on the C side for this would
also be directly useful in my case.

Ken
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: possible attribute-oriented class

2009-09-07 Thread Ken Newton
On Mon, Sep 7, 2009 at 6:02 PM, Jan Kaliszewski wrote:
...
>
> I think it depends how often people need to implement such boiler-plate
> code for themselves. Now I see that this thread is not very popular, so
> indeed maybe you are right... Though it'd be nice to have OOTB such
> a factory in `collections` module...
>
...

How about, if this is not judged to be popular enough to become part of core
or other standard module, at least put a version into a FAQ for easy future
access by those of us that have a use for it?  The suggestions here (and
past versions) are much better than my first do-it-myself version - a standard
peer-reviewed recipe would have been very nice to find.
-- 
http://mail.python.org/mailman/listinfo/python-list