Named functions version:
def _if(test):
def then_closure(expr_if_true):
def else_closure(expr_if_false):
if test:
delayed = delay(expr_if_true)
else:
delayed = delay(expr_if_false)
return delayed()
return else_closure
return then_closure
Walk it through in reverse.
fact = lambda n: _if(n <= 1)(1)(lambda: n * fact(n - 1)) fact(100)
The first function reduces to [ _if( 100 <= 1) ] and it selects between the two functions [ (1) ] and [ (lambda : n * fact(n-1)) ]. As already described True functions call the 2nd functions, False calls the first. So the second function is called and the lambda is evaluated as:
lambda: 100 * fact(99)
Note that the delay function effective does nothing for this case. The whole process starts over again with fact(99):
fact(99) = lambda n: _if(99 <= 1)(1)(lambda: 99 * fact(98))
The special case is fact(1):
fact(1) = lambda n: _if(1 <= 1)(1)(lambda: 1 * fact(0))
To learn more about Python, if you are an experienced programmer, I recommend going to Python.org and getting the documentation package, and paying particular attention to the Python Reference Manual and the Python Library Reference. , Python is less functional. Partially because lists are not conses, Python uses more methods that mutate list structure than Lisp, and to emphasize that they mutate, they tend to return None. This is true for methods like list.sort, list.reverse, and list.remove. However, more recent versions of Python have snuck functional versions back in, as functions rather than methods: we now have sorted and reversed (but not removed). , Here I've taken a blurb from Python.org and created two vesions of it: one for Python in blue italics and one for Lisp in green bold. The bulk of the blurb, common to both languages, is in black. , An important point for many people is the speed of Python and Lisp versus other languages. Its hard to get benchmark data that is relevent to your set of applications, but this may be useful:
def f(list, len): return list((len, len(list))) # # bad Python(define(f list length)(list length(length list)));;
bad Scheme
(defun f(list length)(list length(length list)));;
legal Common Lisp
def f(list, len): return list((len, len(list))) ## bad Python (define (f list length) (list length (length list))) ;; bad Scheme (defun f (list length) (list length (length list))) ;; legal Common Lisp
class C:
def f(self): return self.f # # bad Python
...
>>> parse("2 + 2")['eval_input', ['testlist', ['test', ['and_test', ['not_test', ['comparison',
['expr', ['xor_expr', ['and_expr', ['shift_expr', ['arith_expr', ['term',
['factor', ['power', ['atom', [2, '2']]]]
],
[14, '+'],
['term', ['factor',
['power', ['atom', [2, '2']]]
]]
]]]]]
]]]]], [4, ''], [0, '']]
(defparameter * grammar * '((sentence -> (noun-phrase verb-phrase)) (noun - phrase - > (Article Noun)) (verb - phrase - > (Verb noun - phrase)) (Article - > the a) (Noun - > man ball woman table) (Verb - > hit took saw liked)) "A grammar for a trivial subset of English.") (defun generate(phrase) "Generate a random sentence or phrase" (cond((listp phrase) (mappend # 'generate phrase)) ((rewrites phrase) (generate(random - elt(rewrites phrase)))) (t(list phrase)))) (defun generate - tree(phrase) "Generate a random sentence or phrase, with a complete parse tree. " (cond((listp phrase) (mapcar # 'generate-tree phrase)) ((rewrites phrase) (cons phrase(generate - tree(random - elt(rewrites phrase))))) (t(list phrase)))) (defun mappend(fn list) "Append the results of calling fn on each element of list. Like mapcon, but uses append instead of nconc. " (apply # 'append (mapcar fn list))) (defun rule - rhs(rule) "The right hand side of a rule." (rest(rest rule))) (defun rewrites(category) "Return a list of the possible rewrites for this category." (rule - rhs(assoc category * grammar * ))) (defun random - elt(choices) "Choose an element from a list at random." (elt choices(random(length choices))))
import random grammar = dict(# A grammar for a trivial subset of English.S = [ ['NP', 'VP'] ], NP = [ ['Art', 'N'] ], VP = [ ['V', 'NP'] ], Art = ['the', 'a'], N = ['man', 'ball', 'woman', 'table'], V = ['hit', 'took', 'saw', 'liked']) def generate(phrase): "Generate a random sentence or phrase" if isinstance(phrase, list): return mappend(generate, phrase) elif phrase in grammar: return generate(random.choice(grammar[phrase])) else: return [phrase] def generate_tree(phrase): "" "Generate a random sentence or phrase, with a complete parse tree. "" " if isinstance(phrase, list): return map(generate_tree, phrase) elif phrase in grammar: return [phrase] + generate_tree(random.choice(grammar[phrase])) else: return [phrase] def mappend(fn, iterable): "" "Append the results of calling fn on each element of iterbale. Like iterools.chain.from_iterable. "" " return sum(map(fn, iterable), [])
> (generate 'S) (the man saw the table)
>>> generate('S')['the', 'man', 'saw', 'the', 'table']
Like C++, Python is a multi-paradigm language that does not force programmers to follow a single pure style of programming. Python can be used as an imperative language, an object-oriented language, or a functional language. In practice, the three styles are often intermixed in complementary ways, allowing the programmer to use the best tool for the job at hand. , All of this, plus the reasons mentioned earlier, makes Python an excellent choice as a first programming language for a wide range of students. It's easy to learn, it's eminently practical, and it is infused with a generous helping of the concepts and techniques that computer scientists love. What more can you ask for in a programming language? ,For those familiar with functional programming, list comprehensions are a notation that combines, and largely obviates the need for, the traditional map and filter functions., Java can do similar manipulations using a Vector, or any class implementing the List interface. For instance:
Perhaps the single biggest difference between Python and Java, for beginners, is that Python is an interpreted language that allows almost any expression to be evaluated at the command line. Java is of course a compiled language, with the familiar code-compile-run cycle. The problem with this cycle is that it makes running programs a slower and more complex process, ultimately degrading the quality of feedback. The "Hello, world" program in Python is about as simple as it can get:
>>> print "Hello, world!"
Hello, world!
In Java, much more overhead is needed:
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
One of the most unusual features of Python, at least for experienced programmers, is Python's use of indentation to indicate blocks of code. Java uses "{" and "}" to explicitly mark the begin and end of code blocks, but Python relies on whitespace. The major advantage is that the compiler helps to enforce proper indentation, making it harder than normal to write poorly indented code. In other languages, indentation is an art that students must learn with no little or no automation. In Python, it's an intrinsic part of the language. As an example, here is a Python version of linear search:
def search(x, seq): "" " Returns true if x is seq, and false otherwise. "" " for item in seq: if x == item: return 1 # 1 means true return 0 # 0 means false
Java can do similar manipulations using a Vector, or any class implementing the List interface. For instance:
import java.util.Vector;
public class ListManipulation {
public static void main(String[] args) {
Vector lst = new Vector();
lst.add(new Integer(1));
lst.add("cat");
lst.add(new Integer(4));
lst.add("a");
lst.add("dog");
System.out.println(lst.get(0));
System.out.println(lst.subList(2, 4));
System.out.println(lst.subList(2, lst.size()));
System.out.println(lst.subList(0, 4));
System.out.println(lst.get(lst.size() - 1));
System.out.println(lst.subList(0, lst.size() - 2));
}
} // ListManipulation
import java.util.Vector; public class ListManipulation { public static void main(String[] args) { Vector lst = new Vector(); lst.add(new Integer(1)); lst.add("cat"); lst.add(new Integer(4)); lst.add("a"); lst.add("dog"); System.out.println(lst.get(0)); System.out.println(lst.subList(2, 4)); System.out.println(lst.subList(2, lst.size())); System.out.println(lst.subList(0, 4)); System.out.println(lst.get(lst.size() - 1)); System.out.println(lst.subList(0, lst.size() - 2)); } } // ListManipulation
1
[4, a]
[4, a, dog]
[1, cat, 4, a]
dog
[1, cat, 4]
You have come to Python from another OOP language such as Java or C# and want to know how to translate your knowledge of design patterns from that language into Python. In Python and other dynamically typed languages, many patterns common in statically typed OOP languages are “invisible or simpler,” as the author Peter Norvig put it.,Having first class functions in Python makes this very easy. In languages that lack them, or some statically typed languages that require type signatures for parameters, this can be harder. How would we do this if we had no first class functions?,So far, we’ve dealt with two very basic usages. The key observation for the rest of this article is that, in Python, there is a large range of things that can become parameters—more than in some other languages—and this makes it a very powerful technique.,The last two are the ones that are the most surprising, especially if you are coming from other languages, and they need some more discussion.
Here is some code that will draw a 100x100 square using turtle
:
from turtle
import Turtle
turtle = Turtle()
for i in range(0, 4):
turtle.forward(100)
turtle.left(90)
Suppose we now want to draw a different size square. A very junior programmer at this point would be tempted to copy-paste this block and modify. Obviously, a much better method would be to first extract the square drawing code into a function, and then make the size of the square a parameter to this function:
def draw_square(size):
for i in range(0, 4):
turtle.forward(size)
turtle.left(90)
draw_square(100)
An immediate issue with the code above is that draw_square
depends on a global variable. This has lots of bad consequences, and there are two easy ways to fix it. The first would be for draw_square
to create the Turtle
instance itself (which I’ll discuss later). This might not be desirable if we want to use a single Turtle
for all our drawing. So for now, we’ll simply use parameterization again to make turtle
a parameter to draw_square
:
from turtle
import Turtle
def draw_square(turtle, size):
for i in range(0, 4):
turtle.forward(size)
turtle.left(90)
turtle = Turtle()
draw_square(turtle, 100)
And just like all objects, we can assign functions to other variables:
> >> bar = foo >
>> bar()
'Hello from foo'
Note that bar
is another name for the same object, so it has the same internal __name__
property as before:
> >> bar.name
'foo'
> >> bar
<function foo at 0x7fc233d706a8>