<br><br><div class="gmail_quote">On Thu, Sep 3, 2009 at 4:30 PM, Steven D'Aprano <span dir="ltr"><<a href="mailto:steve@remove-this-cybersource.com.au" target="_blank">steve@remove-this-cybersource.com.au</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>On Thu, 03 Sep 2009 15:46:01 -0700, Ken Newton wrote:<br>
<br>
> I have created the following class definition with the idea of making a<br>
> clean syntax for non-programmers to created structured data within a<br>
> python environment.<br>
<br>
</div>What do you expect non-programmers to do with this class, without<br>
programming? How can they even use it?<br></blockquote><div><br></div><div>A couple extra details: The users are scientists, and technically sophisticated.</div><div>They are used to specifying complicated sets of parameters and this structured</div>

<div>form matches the way they are used to thinking about their work. Though they</div><div>are not programmers, they can define expressions to represent the desired</div><div>calculations for this project and occasionally write small programs in the course</div>

<div>of their work. However, they will not like a long learning curve and will want to be</div><div>isolated from most of the details in good programming design (error handling, </div><div>creating supporting infrastructure, etc.)  In this case, Python will be used as</div>

<div>a scripting language with most of the details specified by simple function expressions </div><div>or defining structured data or specifying (linear) sequences of actions. </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


...<br>
<div>> The expected use would have all items in the structure be simple python<br>
> types or AttrClass types. Code written in python could walk the<br>
> structure in a simple way to locate any desired values. Code in a C/C++<br>
> extension should also be able to walk the structure to use any value in<br>
> the structure.<br>
<br>
</div>I don't see the purpose of it. Nested data structures are generally<br>
harder for people to understand than non-nested ones, hence the Python<br>
Zen: "flat is better than nested". For example, a list is easier to grasp<br>
than a tree. This especially applies to non-programmers.<br>
<br>
I don't see how this is simple enough for non-programmers, or useful for<br>
programmers. For programmers, just nest objects:<br>
<br>
class Parrot(object):<br>
    pass<br>
<br>
obj = Parrot()<br>
obj.x = 1<br>
obj.y = Parrot()<br>
obj.y.z = 2<br>
obj.y.z.zz = Parrot()</blockquote><div><br></div><div>This is close to what I started with when I started exploring this idea. </div><div>But I felt I needed a way to create some additional support, that is </div><div>the str and repr functions.  These structures will be created and </div>
<div>populated once and saved in a python source file, which will be </div><div>loaded from the embedding C++ program.  The (scientist) users will</div><div>need a way to review the structure and current values while </div>
<div>interactively changing a few of the values to observe their effect on</div><div>the system.  My recursive __str__() and __repr__() functions were</div><div>intended to provide that support.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
> class AttrClass(object):<br>
>     """AttrClass lets you freely add attributes in nested manner"""<br>
<br>
</div>You don't actually need a special class for that, unless you're providing<br>
extra functionality. A bare subclass of object will let you freely add<br>
attributes in a nested manner.<br>
<br>
It seems to me that you're combining two different sets of functionality,<br>
but only describing one. The first is, nested attributes -- but you get<br>
that for free with any class. The second is the ability to set (but<br>
strangely not retrieve!) attributes using dictionary-like syntax. But<br>
that's implied by the code, you haven't mentioned it in your description<br>
or documentation.<br>
<br>
<br>
>     def __init__(self):<br>
>         pass<br>
<br>
If the __init__ method doesn't do anything, you don't need it.</blockquote><div><br></div><div>Good point. This was a placeholder. My intention was to add some </div><div>code to initialize the class from a dict. But didn't get around to </div>
<div>implementing that. Or the ideas I tried (couple years ago) didn't work.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
>     def __setitem__(self, key, value):<br>
>         return self.__dict__.__setitem__(key, value)<br>
<br>
</div>Simpler to just say:<br>
<div><br>
def __setitem__(self, key, value):<br>
</div>    self.__dict__[key] = value<br>
<br>
You don't strictly need the return, because methods return None by<br>
default, and dict.__setitem__ always returns None (unless it raises an<br>
exception).<br></blockquote><div><br></div><div>Now, I can't remember why I ended up with my strange syntax.  Unless</div><div>it was related to the fact that I started doing this in IronPython and this </div><div>made it work better in that context or on the C# side of things.  I'm now</div>
<div>planning this for a CPython embedding situation.  And, perhaps as  you</div><div>pointed out, the __setitem__ isn't needed at all in the code I showed.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
This method allows you to set attributes using dict syntax:<br>
<br>
    instance['key'] = 123  # same as instance.key = 123<br>
<br>
But you don't have corresponding __getitem__ or __delitem__ methods, so<br>
you can't do these:<br>
<br>
    value = instance['key']  # fails<br>
    del instance['key']  # fails</blockquote><div> </div><div>The getitem and delete behaviors are not expected to be common uses. </div><div>But if I continue with this approach, should be implemented for completeness.</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
>     def __repr__(self):<br>
>         return "%s(%s)" % (self.__class__.__name__,<br>
>         self.__dict__.__repr__())<br>
<br>
</div>This strongly implies that you should be able to create a new instance<br>
using that format:<br>
<br>
AttrClass({'key': 123, 'another_key': 456})<br>
<br>
but that fails. As a general rule, the repr() of a class should (if<br>
possible) work correctly if passed to eval(). This doesn't. That's not<br>
entirely wrong, but it is unusual and confusing.<br></blockquote><div><br></div><div>Yes, as mentioned above, I would like to initialize from a dict. Then the</div><div>given repr syntax would be a better fit. Appending a dict or concatenating </div>
<div>two or more objects might also be useful.  I'd also consider serializing to </div><div>an XML file, or a variation of the ConfigFile or *.ini  file formats if the data</div><div>is kept to only a depth of 2 levels.</div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">--<br>
Steven<br></blockquote><div><br></div><div>Thanks for all your comments.  </div><div><br></div><div>Ken</div><div><br></div></div>