[Edu-sig] Python for Fun

Dethe Elza delza@alliances.org
Fri, 25 May 2001 21:10:04 -0700


Hi Chris

> We're still on Python 1.5.3 mainly because we have so much code in
> running systems that upgrading involves a lot of regression
> testing. Try for this summer for sure. Lots of stuff out there that
> assumes 2.0 as a base. Zope, Vpython, wxPython, etc. A year ago we
> upgraded from 3.0 and had some glitches - mostly with comparisons
> where one value was None.

Actually, Zope still uses Python 1.5.x for much the same reasons: lots of
code to evaluate.  The next release will be for 2.0, I think.  Likewise,
wxPython and VPython were running on 1.5 until recently, so there should
either be a 1.5 branch of the current version, or an older install which
will work for you to play with.  RedHat Linux (and others, I'm sure) still
seems to be shipping/using 1.5 (RedHat uses Python for their installer and
lots of utilities), and it has a tremendous installed base, so lots of folks
still support it in their tools.

>> Just for fun:  tweaking logic.py Connector class with 2.1 idioms:
>> 
>> def connect (self, inputs) :
>> if type(inputs) != type([]) : inputs = [inputs]
>> self.connects += inputs  # <-- here
>> 
> This is a nice new feature (+= etc.). Does it save time and
> evaluate the left hand address only once? Or is it just syntactic
> sugar? If the calculation is complex, it can make a real difference
> in program speed. Like
> 
> array[n][nextSlot(whatever)] += 1
> Or in our case we are very often incrementing (or the like) an
> object attribute, which is a really a dict lookup. Don't want to do
> the lookup twice.

Augmented assignments ( x += y instead of x = x + y, etc.) were done as part
of PEP 203 (Python Enhancement Proposal), and according to that the
left-hand side is indeed evaluated only once.

http://python.sourceforge.net/peps/pep-0203.html

>> def set (self, value) :
>> if self.value == value : return      # Ignore if no change
>> self.value = value
>> if self.activates : self.owner.evaluate()
>> if self.monitor :
>> print "Connector %s-%s set to %s" % \
>> (self.owner.name,self.name,self.value)
>> [con.set(value) for con in self.connects]  # <-- and here
>> 
> This should also save time, I would think, since the list is not
> constantly resized? Can't test it. Don't work on 1.5.3

Not sure what the issue is here.

>> Could also go:
>> 
>> self.connects.extend(inputs)  (is that 1.5 or later?)
>> 
> Is this actually different from .append ?

I believe extend adds a list to a list, making a list which is the union.
Append would take the additional list and make it a single node of the first
list (lengthening by one rather than by the length of the added list).

>> I find it interesting that you can define lists simply for
>> their side-effects, with the list itself saved nowhere.  Indeed,
>> you can stick [1,2,3] (no assignment to a variable) anywhere
>> a method and nothing happens -- __repr__ isn't triggered
>> except at the command line.
>> 
> That's kind of cool. I had never tried it. Replace 1,2,3 with
> function calls and off they go, left to right. This reminds me of
> the old Lisp "PROG" that would evaluate its arguments just for the
> side effects.
> 
>> I did have
>> 
>> map(lambda con: con.set(value), self.connects)
>> 
>> which makes use of nested scopes (value in lambda is getting a
>> pointer from the surrounding method), but list comprehension
>> doesn't see this as a case of scope nesting i.e. variables
>> within the brackets are locally scoped already.
>> 
> 
> I tried this and it seemed to work
>>>> 
>>>> class con :
> ...     def __init__ (self) :
> ...             self.x = 5
> ...     def prnt (selfi,c) :
> ...             print self.x + c
> ...
>>>> a = con()
>>>> b = [a,a,a]
>>>> map(lambda x: x.prnt(4), b)
> 9
> 9
> 9
> [None, None, None]
>>>> 
> Speaking of scoping. If you get around to Lisp in Python, there's a
> section on dynamic scoping with an example.
> 
> Chris
> 

-- 

Dethe Elza
Chief Mad Scientist
Burning Tiger Technologies