why python annoys me

Alex Martelli aleaxit at yahoo.com
Sat Apr 21 03:24:29 EDT 2001


"Oliver Korpilla" <korpo at 01019freenet.de> wrote in message
news:3AE0F802.3983C9DB at 01019freenet.de...
> >
>
> > Python does not force you in thinking OO, procedural or functional.
> > That's what I ment.
>
> What about functional ? Pyhon doesn't either ENABLE you to work
functional!!

It's surely not focused to the FP paradigm, but does enable
some use of it.

> apply, filter and map are 3 nice functions, and the data types are nice,
too,
> but without list comprehension or partial applicatiob, curried function
etc.
> you can't use them that much neither...

Arguably true, but, since Python does have list comprehensions,
how does this sentence support the previous one?


> Haskell Quicksort:
> qsort:: Ord a=> [a] -> [a]
> qsort [] = []
> qsort (x:xs) = [y | y <- xs, y <= x] ++ [x] ++ [y | y <- xs, y > x]

Hmmm, I think we're missing a couple of recursive calls on the
RHS of the last line; this way, you're only doing the "split" step,
not a full sort.

> without list comprehension it's impossible (IMHO, of course) to match this
> functional elegance.

Perhaps, but... with list comprehensions, this could be translated into
Python (assuming we do want a full sort, not just a split) as:

def qsort(aseq):
    if aseq==[]: return aseq
    x=aseq[0]; xs=aseq[1:]
    return qsort([y for y in xs if y<=x])+[x]+qsort([y for y in xs if y>x])

This is meant to be a reasonably faithful transliteration.  You don't
get pattern-matching: you have to explicitly use an if to test if the
argument is the empty list, assignments to get the head and tail,
and a return statement to indicate return.  And of course the list
comprehension syntax is slightly different, with 'for' in lie of '<-',
and explicit 'if', as is list concatenation, using a single '+' in lieu
of two.  But it still seems very close indeed to me.

> filter could suffice, but without
> partial application or the ability to use function-local variables in
> lambda-expression definitions, you cannot redo a functional, recursive,
pure
> solution.

Without list comprehensions to prepare the list arguments to the
recursive calls, you'd have to prepare these arguments differently.

lambda's are one possibility, but naming the filter functions may
make for more readable code; in Python 2.0 and earlier:

def qsort(aseq):
    if aseq==[]: return aseq
    def small(y, x=aseq[0]): return y<=x
    def big(y, x=aseq[0]): return y>x
    return qsort(filter(small, aseq[1:])) + [x] + \
        qsort(filter(big, aseq[1:]))

Here we have not introduced an arbitrary name 'xs' for the
sequence-tail, we have limited the arbitrary names 'x' and
'y' for sequence-head and generic-item to local scopes of
nested functions, but we _have_ introduced names (meant
not to be arbitrary:-) for our filtering criteria.  It does not
seem to me that these naming choices (which can be taken
in various ways -- this specific style seems best to me, but
others are surely also viable) destroys elegance -- hey,
doesn't one often use "let x=something in blah blah" or
equivalently 'blah blah where x=something" for the
_specific_ scope of introducing a name with local scope
in typical FP?!

In Python 2.2 (and 2.1 with nested-scopes enabled) you
get yet another choice of naming details if you wish, e.g.
in this last example you could alternatively code:

    def small(y): return y<=aseq[0]
    def big(y): return y>aseq[0]

to avoid introducing a name for sequence-head.  But does
this make such an epochal difference?  After all, you HAVE
introduced a name for sequence-head in your Haskell
code, and that does seem quite normal to me.  Looks
pretty trifling to me.

> This is just toys! Nice toys, sometimes.

This is definitely a defensible position, in that the
performance of this sort approach is going to be the
pits compared to that of lists' builtin sort method,
which works in-place AND is internally coded using
a very fast C algorithm.  But Python's abilities to
_express_ the FP version of qsort appear to be there
even if performance issues suggest alternatives.

> Do not take this as defying Python ! I love it. But keep non-functional,
as it
> is ;O)

Alternative approaches based on data-mutation rather
than FP are often going to be faster, and sometimes
even clearer, in Python.  And lazy evaluation isn't there,
you have to fake it -- perhaps the single biggest issue
(seems far bigger to me than the "I've gotta name this"
vs "I can leave this unnamed" one, for sure).  But a FP
slant is often going to be appropriate in several corners
of a Python program, and feasible though sub-optimal
in others.  So why not exploit it where it works well?


Alex






More information about the Python-list mailing list