In college, my favorite class was the introductory programming class. It was amazing. We used Scheme and touched upon almost every programming topic under the sun, including compilers, streams, lambda calculus, and object-oriented programming. (So, it wasn't an ordinary intro class and we didn't use no ordinary textbook.)
I haven't used Scheme much these days, but a few days ago, a colleague asked me if I knew of ways to improve the performance of Scheme code. He was wondering if there was software analogous to Python calling C or Fortran code.
I found a good discussion of fast Scheme compilers at this forum. Apparently, Bigloo allows communication between C code and Scheme code. There are also some really fast Scheme compilers like Chicken, Gambit and Chez.
One thing I've wondered is how to translate loop-heavy C/Fortran code into Scheme. My programming class hardly even discussed loops. I did find a short discussion on how to write a loop in Scheme at the MIT ab-initio wiki.
I don't have any reason to look further into this right now, but these compilers could be useful someday in the future.
Showing posts with label python. Show all posts
Showing posts with label python. Show all posts
05 October 2008
22 June 2008
Python mutable defaults
In the short time that I've learning Python, the most annoying "feature" is Python's mutable defaults. You can define a default parameter for a variable in a function, but if the variable happens to be mutable (like a list), you get strange side effects. The book Learning Python by Mark Lutz gives a detailed explanation on pages 373-374. I will follow some of Lutz's discussion with a few of my own comments.
Suppose you write the following function.
def saver(x=[]):
... x.append(1)
... print x
...
Then you run it like so:
>>> saver([2])
[2, 1]
>>> saver()
[1]
>>> saver()
[1,1]
The third output is probably not what you wanted. You probably wanted [1]. The problem is that the default parameter is only evaluated once, when the function definition is evaluated. A common solution is to stick an if statement at the beginning of the function body.
def saver3(x=[]):
... if x is None
... x = []
... x.append(1)
... print x
...
Another solution is to use an or statement.
def saver3(x=[]):
... x = x or []
... x.append(1)
... print x
...
Both solutions give the same behavior because they force the default parameter to be evaluated for every function execution, rather than just once as with saver(). It's really confusing, isn't it? The x in if x is None evaluates the default value, but the x in x.append(1) doesn't. I can't really think of any logical way to remember this difference. I guess I just have to memorize it.
However, as Lutz notes in his book, saver2() and saver3() aren't quite the same because if you pass an empty list, saver2([]) keeps the passed list whereas saver3([]) creates a new empty list.
Suppose you write the following function.
def saver(x=[]):
... x.append(1)
... print x
...
Then you run it like so:
>>> saver([2])
[2, 1]
>>> saver()
[1]
>>> saver()
[1,1]
The third output is probably not what you wanted. You probably wanted [1]. The problem is that the default parameter is only evaluated once, when the function definition is evaluated. A common solution is to stick an if statement at the beginning of the function body.
def saver3(x=[]):
... if x is None
... x = []
... x.append(1)
... print x
...
Another solution is to use an or statement.
def saver3(x=[]):
... x = x or []
... x.append(1)
... print x
...
Both solutions give the same behavior because they force the default parameter to be evaluated for every function execution, rather than just once as with saver(). It's really confusing, isn't it? The x in if x is None evaluates the default value, but the x in x.append(1) doesn't. I can't really think of any logical way to remember this difference. I guess I just have to memorize it.
However, as Lutz notes in his book, saver2() and saver3() aren't quite the same because if you pass an empty list, saver2([]) keeps the passed list whereas saver3([]) creates a new empty list.
24 May 2008
EAFP vs LBYL
I've been learning Python in the last few weeks. Many of my friends have switched to using it, making me think that it's the scientific programming language of the future (if not now).
I've been working my way through the official Python tutorial. I was amused to find the following in the tutorial glossary:
I've been working my way through the official Python tutorial. I was amused to find the following in the tutorial glossary:
EAFPAnd what is LBYL, you may ask?
Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style that is common in many other languages such as C.
LBYL
Look before you leap. This coding style explicitly tests for pre-conditions before making calls or lookups. This style contrasts with the EAFP approach and is characterized by the presence of many if statements.
Subscribe to:
Posts (Atom)