Python execution speed

Marco Antoniotti marcoxa at cs.nyu.edu
Tue Nov 20 23:19:56 CET 2001


"Morten W. Petersen" <morten at thingamy.net> writes:

> On Mon, 19 Nov 2001, Peter Hansen wrote:
> 
	...
> > I understand these issues, but I really wanted to know why the *OP*
> > thought he needed more speed (which I inferred was the only serious=20
> > advantage he felt he'd found with LISP over Python).
> 
> It's one of the advantages I see, if true.  Another is macros (which I
> don't fully understand the scope of yet).

The power of macros in CL comes from what is known as "read/write"
consistency.  A paraphrase of this is "what you READ you can PRINT"
and "what you PRINT you can READ" (with some precise exceptions).  In
some ways the 'pickle' modules do a similar thing, but not quite (the
CL package SAVE-OBJECTS is the more or less equivalent of 'pickle').

So, in CL

cl-prompt> (print 123)
123   <= what got printed
123   <= the value of the expression

cl-prompt> (print (make-array '(2 2)
                              :initial-contents '((#C(0 1) 0) (0 #C(0 1)))))

#2A((#C(0 1) 0) (0 #C(0 1))) 
#2A((#C(0 1) 0) (0 #C(0 1)))

cl-prompt> (read)
#2A((#C(0 1) 0) (0 #C(0 1)))   <= what I typed in 
#2A((#C(0 1) 0) (0 #C(0 1)))   <= the value returned by 'read'.

Of course this works for lists, which are also CL programs.

cl-print> (print '(defun fact (n)
                    (if (zerop n)
                       1
                       (* n (fact (1- n))))))
(defun fact (n) (if (zerop n) 1 (* n (fact (1- n))))) 
(defun fact (n) (if (zerop n) 1 (* n (fact (1- n)))))

and `read' works in the same way (note the irrelevance of the
formatting).

cl-prompt> (read)
(defun fact (n) (if (zerop n) 1 (* n (fact (1- n)))))
(defun fact (n) (if (zerop n) 1 (* n (fact (1- n)))))

This is a major CL point de resistance.

Note that since programs are lists you can manipulate them in a very
easy way.  E.g.

cl-prompt> (defvar vector-form (cons 'vector (list 1 2 3 4 5)))
vector-form

cl-prompt> vector-form
(vector 1 2 3 4 5)

Of course I can `eval' this.  But that is beyond the point.  I can
sneak in this "list construction" operations ad read and at compile
time by declaring a macro

cl-prompt> (defmacro my-vector-constructor (&rest forms)
              (cons 'vector forms))
my-vector-constructor

cl-prompt> (my-vector-constructor 1 2 3 4 (* 3 #C(2 4)))
#(1 2 3 4 #C(6 12))

Voila`. 'my-vector-constructor' *looks* like regular code, but it is a
macro.  Of course the example is stupid.  To appreciate a better
example just look at CL `defclass' macro or (not for the faint of
heart) CL `loop' macro (built on top of more basic - and uglier - loop
constructs).  Just for a taste...

WARNING! UNREADABLE CODE AHEAD.
cl-prompt> (macroexpand-1 '(loop for x across "zut" collect (char-code c)))
(let ((c nil)
      (#:g3635 "zut")
      (#:g3636 0))
  (declare (type fixnum #:g3636)
           (type (or (member nil) vector) #:g3635))
  (ansi-loop::with-loop-list-collection-head (#:g3637 #:g3638)
    (block nil
      (ansi-loop::loop-body
       nil
       (nil
	(ansi-loop::loop-really-desetq c (aref #:g3635 #:g3636))
	nil
	(ansi-loop::loop-really-desetq #:g3636 (1+ #:g3636)))
       ((ansi-loop::loop-collect-rplacd (#:g3637 #:g3638)
					(list (char-code c))))
       ((when (>= #:g3636 3)
	  (go ansi-loop::end-loop))
	(ansi-loop::loop-really-desetq c (aref #:g3635 #:g3636))
	nil
	(ansi-loop::loop-really-desetq #:g3636 (1+ #:g3636)))
       ((return-from nil (ansi-loop::loop-collect-answer #:g3637)))))))


where things like `ansi-loop::with-loop-list-collection-head' and
'ansi-loop::loop-collect-rplacd' are yet other macros waiting to be
expanded.  Of course (admittedly with a small trick) I could take the
result of the macro-expansion and execute it directly (which is what
similar to what the compiler does).

> There's an underlying question here though, and that is how fast is the
> Python community able to adapt and implement good ideas.

Like multiple dispatch on methods?

To put it bluntly, CL is a much better suited language to "import"
good ideas, since it is one of its main raisons d'etre.  The joke
"Lisp is like a ball of mud: it does not matter how much mud you throw
at it, it still looks like a ball of mud" has a core of truth about
the overall beauty of CL.  The macro facility is at the core of such
beauty: it attracts mud.

> One of Python's advantages is a consistent (simple) design, (not counting
> small quirks like 'def function(): return 1' and 'function =3D =20
> lambda: 1'.  Consistent design says 'less complexity' in my ears, along
> the same lines of the simpleness (ease of maintenance, readability,
> portability) of a python application if it can always be coded in Python.

Python has had the advantage of hindsight on many accounts.  This is
its main advantage.  But the overall CL design and its ANSI standard
(http://www.alu.org) are an amazing achievement of clarity, simplicity
and depth.

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.



More information about the Python-list mailing list