05/25/2001 1:55:29 PM, Kirby Urner <pdx4d@teleport.com> wrote: Hi Kirby, 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.
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.
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
Could also go:
self.connects.extend(inputs) (is that 1.5 or later?)
Is this actually different from .append ?
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.
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
I tried this and it seemed to work section on dynamic scoping with an example. Chris
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.
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
I tried this and it seemed to work section on dynamic scoping with an example.
Chris
-- Dethe Elza Chief Mad Scientist Burning Tiger Technologies
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.
Considerable effort now under way to bring and Python into sync - looking like Zope 2.4 with Python 2.1. On Windows Zope installs with its own Python included. So I gather that starting from Zope 2.4 this will include Python 2.1 Meanwhile Python 1.5.2 appears to be the default, most widely installed etc. Looks like 6-9 months of mild versionitis up ahead until Python 2.1 [or later] becomes richly used and the fully supported reference. Since installing Python is so easy I do not see there is much problem. The admin issue is keepiing up with the upgrades in a clean quick manner. Particualrly all the additional modules one has. Zope now has an $INSTANCE_HOME variable one can asign to different directory, located whrever you wish,to store any the non-standard modules, Zope 'products' etc. This is a big improvement. Convenient, maintainable, flexible. How do you recommned smooth handling of Python modules placement, path assignment, for miminimizing upgrade pain. ? I usually use brute copy and paste of folders, then fix any version errors when prompted. But it is messy and makes me feel dumb. ./Jason
Could also go:
self.connects.extend(inputs) (is that 1.5 or later?)
Is this actually different from .append ?
It's different with later versions because in those append only accepts a single argument e.g.:
a = [1,2,3] a.append([4,5,6]) a [1, 2, 3, [4, 5, 6]] a = [1,2,3] a.extend([4,5,6]) a [1, 2, 3, 4, 5, 6]
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]
If I use the following as my def of set in the Connector class: 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) map(lambda con: con.set(value), self.connects) Then upon import I get the warning: d:\program files\python21\ocn\logic.py:25: SyntaxWarning: local name 'value' in 'set' shadows use of 'value' as global in nested scope 'lambda' self.value = value And the program crashes when using test4Bit:
test4Bit('1001','1110') Connector F0-Cin set to 0 Traceback (most recent call last): File "<pyshell#40>", line 1, in ? test4Bit('1001','1110') File "d:\program files\python21\ocn\logic.py", line 124, in test4Bit F0.Cin.set(0) File "d:\program files\python21\ocn\logic.py", line 32, in set map(lambda con: con.set(value), self.connects) File "d:\program files\python21\ocn\logic.py", line 32, in <lambda> map(lambda con: con.set(value), self.connects) NameError: global name 'value' is not defined
However, if I insert: from __future__ import nested_scopes at the top of logic.py, then the code reloads w/o warnings and runs fine, because with nested scopes, lambda is perfectly able to see the value of 'value' without needing to have that passed explicitly, as in: map(lambda con, value=value: con.set(value), self.connects) ...which works OK without the nested_scopes feature (probably in 1.5.3 as well then). It's this value=value stuff that the nested scopes feature is designed to avoid/obviate. Another experiment: if I write a test module named test2.py with the following function only: def test(x): y=5 return map(lambda x: x+y, [x]) then on import I get the warning:
import test2 d:\program files\python21\ocn\test2.py:1: SyntaxWarning: local name 'y' in 'test' shadows use of 'y' as global in nested scope 'lambda' def test(x):
but if I add the line: from __future__ import nested_scopes to the top of the test2.py module and reload, then y is captured in the lambda. No warnings, function works:
test2.test(10) [15]
What I find interesting is that I can't make the above function work in IDLE if I enter it at the command line, even if I enter from __future__ import nested_scopes. In other words, whereas adding this 2.1-only import statement to the top of a module suppresses the warning and makes the code OK, entering this import statement at the command line doesn't salvage the code.
Speaking of scoping. If you get around to Lisp in Python, there's a section on dynamic scoping with an example.
Chris
I did study the Lisp example for awhile. I'm always awed by LISP and all that tail recursion. Yet the LISP _does_ have looping syntax in the versions I've seen. It's Scheme that stays purist about using only recursion for looping, no?
From what I understand of all this, Python isn't really tail recursive under the hood. Am I right about that?
Building more complicated circuits with your logic gates would be fun. I've got this 'Beebop to the Boolean Boogie' book that'd make a good guide for testing out some other circuits. Dunno when/if I'll get to do it. Kirby
participants (4)
-
Chris Meyers
-
Dethe Elza
-
Jason Cunliffe
-
Kirby Urner