472,354 Members | 2,131 Online

# Python is Considered Harmful

I present to you the final and ultimate proof of Python's
brain-damage:

As you may remember,

flist = []

for i in range(3)
f = lambda x: x + i
flist.append(f)

[f(1) for f in flist]

produces [3, 3, 3] in Python.

In Haskell, we would express this as follows:

map (\f -> f 1) [\x -> x + i | i <- [0..2]]

This, of course, evaluates to the expected [1, 2, 3]

As you might have heard, the ever so generous GvR allowed us write
the same in Python (literal translation, really):

map(lambda f: f(1), [lambda x: x + 1 for i in range(3)])

What do you think this evaluates to: also [1, 2, 3] or [3, 3, 3]
as before?

Guess again, it's [2, 2, 2] !

ROTFLMFAO!

Pythonista, you are all very welcome to learn Haskell.
You will find the syntax very familiar. Haskell is short
too (compare one line above that gives the correct
result to several Python lines that surprise you)

All this Python bashing is starting to feel like mocking
a retarded child...

420
Jul 18 '05 #1
25 2774
On Sun, 26 Oct 2003 22:25:41 -0800 (PST)
mi*****@ziplip.com wrote:

I present to you the final and ultimate proof of mike420's
brain-damage:

In Haskell, we would express this as follows:

map (\f -> f 1) [\x -> x + 1 | i <- [0..2]]

This, of course, evaluates to the expected [2, 2, 2]

map(lambda f: f(1), [lambda x: x + 1 for i in range(3)])

What do you think this evaluates to: also [1, 2, 3] or [3, 3, 3]
as before?

It's [2, 2, 2] !

-

You are a blatant troll and now a public moron to boot. Will you please
go away? You may consider coming back when you learn 1+1=2.
Jul 18 '05 #2
mi*****@ziplip.com writes:
I present to you the final and ultimate proof of Python's
brain-damage:
-1, Troll.
map(lambda f: f(1), [lambda x: x + 1 for i in range(3)]) Guess again, it's [2, 2, 2] !
Yes, 1+1 == 2 for usual values of 1.
Pythonista, you are all very welcome to learn Haskell.
...
All this Python bashing is starting to feel like mocking
a retarded child...

Well, the Haskell community seems like a friendly bunch, at least.

--
Ville Vainio http://www.students.tut.fi/~vainio24
Jul 18 '05 #3
Hmm...I think the Haskell syntax looks like crap. ;) Seriously, I can't even
guess how it works without some kind of manual. And of course the Python result
is only 'surprising' if you don't know the rules of name binding.

I'm not bashing Haskell, of course. I'm just saying I already don't like it...

- Kef

Jul 18 '05 #4
>>>>> "mike420" == mike420 <mi*****@ziplip.com> writes:

mike420> As you might have heard, the ever so generous GvR allowed us
mike420> write the same in Python (literal translation, really):

mike420> map(lambda f: f(1), [lambda x: x + 1 for i in range(3)])

mike420> What do you think this evaluates to: also [1, 2, 3] or [3, 3,
mike420> 3] as before?

mike420> Guess again, it's [2, 2, 2] !

Did you really mean

map(lambda f: f(1), [lambda x: x+i for i in range(3)])

? If so, it does return [3, 3, 3]. The only problem here is that Python
variables are name lookups over dictionaries, and as such the value of "i"
is not coined into the lambda. Rather it is "external", binded dynamically.
I believe the behaviour can be fixed rather easily by some directives, say
making it

map(lambda f: f(1), [lambda x: x+(*i) for i in range(3)])

where the * construct would get the reference of i at function definition
time rather than at function invocation time (anyone can point me to an
PEP?). On the other hand, I basically never use lambda this way.

mike420> Pythonista, you are all very welcome to learn Haskell. You
mike420> will find the syntax very familiar. Haskell is short too
mike420> (compare one line above that gives the correct result to
mike420> several Python lines that surprise you)

Yes, tried. Failed, unluckily. It is clear that I'm not the kind of people
who will map every programming problem into a mathematical problem and solve
it that way. So I hate maps and reduces. I hate that I cannot assign a new
value to an existing value to change its binding. I hate having to remember
the unintuitive meanings of all the symbols. I hate having to guess when
variables will get its bindings and when functions will be invoked during
lazy evaluation. There is no way that anyone can turn me to Haskell.
Basically every strong point Haskellers talk about turn me off. This is
very unlucky.

Regards,
Isaac.
Jul 18 '05 #5
Ville Vainio <vi********************@spamtut.fi> wrote:
mi*****@ziplip.com writes:
I present to you the final and ultimate proof of Python's
brain-damage:

-1, Troll. [...] Well, the Haskell community seems like a friendly bunch, at least.

You're right, he's a troll. As a user of Haskell, I think such postings
do an inexcusable amount of damage. Please ignore him, and don't
judge the Haskell community by people like him.

- Dirk

[F'up to poster]

Jul 18 '05 #6
On Mon, 2003-10-27 at 07:28, Lulu of the Lotus-Eaters wrote:
mi*****@ziplip.com wrote previously:
|All this Python bashing is starting to feel like mocking
|a retarded child...

Y'know... a few dozen letters to 'a****@ziplib.com' certainly couldn't
do any harm in troll management. It might not help... but it might.

--
Martin Franklin <mf********@gatwick.westerngeco.slb.com>
Jul 18 '05 #7
Isaac To wrote:
...
Did you really mean

map(lambda f: f(1), [lambda x: x+i for i in range(3)])

? If so, it does return [3, 3, 3]. The only problem here is that Python
variables are name lookups over dictionaries, and as such the value of "i"
is not coined into the lambda. Rather it is "external", binded
dynamically. I believe the behaviour can be fixed rather easily by some
directives, say making it

map(lambda f: f(1), [lambda x: x+(*i) for i in range(3)])

where the * construct would get the reference of i at function definition
time rather than at function invocation time (anyone can point me to an
PEP?). On the other hand, I basically never use lambda this way.

No new "directive" needed: it's easy to get "snap-shots" of current
values of names into a lambda or other function:

map(lambda f: f(1), [lambda x, i=i: x+i for i in range(3)])

The "i=i" gets the (outer) value of i at function-definition time and
injects it as local variable i in the lambda. You can also rename just
as easily (and sometimes it's clearer):

map(lambda f: f(1), [lambda x, k=i: x+k for i in range(3)])

Alex

Jul 18 '05 #8
mi*****@ziplip.com wrote in message news:<D5**************************************@zip lip.com>...

I present to you the final and ultimate proof of Python's
brain-damage:

As you may remember,

flist = []

for i in range(3)
f = lambda x: x + i
flist.append(f)

[f(1) for f in flist]

produces [3, 3, 3] in Python.

In Haskell, we would express this as follows:

map (\f -> f 1) [\x -> x + i | i <- [0..2]]
First, let's remove the list comprehension syntactical sugar. This is
actually:

map (\f -> f 1) (map (\i -> (\x -> x + i)) [0..2])

So, as you can see clearly without the sugar, you're basically
creating closures, since a new lexical scope is introduced at function
creation.
This, of course, evaluates to the expected [1, 2, 3]
Expected by functional programmers who expect new lexical scopes to be
created at every block, sure. But Python isn't a functional
programming language, and doesn't create a new lexical scope in every
block.
As you might have heard, the ever so generous GvR allowed us write
the same in Python (literal translation, really):

map(lambda f: f(1), [lambda x: x + 1 for i in range(3)
Others have pointed out your typo here; I'll assume you meant "lambda
x: x + i" instead of 1.

Again, let's remove the syntactical sugar here:

L = []
for i in range(3):
L.append(lambda x: x + i)
map(lambda f: f(1), L)

The observed result, [3, 3, 3] is perfectly in keeping with the fact
that Python does not create a new lexical scope in for suites (or if
suites, or any other non-class, non-function suite).
Pythonista, you are all very welcome to learn Haskell.
You will find the syntax very familiar. Haskell is short
too (compare one line above that gives the correct
result to several Python lines that surprise you)
The Python result is only surprising to those who try to impose other
languages' semantics on Python.
All this Python bashing is starting to feel like mocking
a retarded child...

You, sir, are a poor representative of the Haskell community.

Jeremy
Jul 18 '05 #9
On Sun, 26 Oct 2003 22:25:41 -0800 (PST), mi*****@ziplip.com wrote:

I present to you the final and ultimate proof of Python's
brain-damage:

[text snipped]

ROTFLMFAO!

Pythonista, you are all very welcome to learn Haskell.
You will find the syntax very familiar. Haskell is short
too (compare one line above that gives the correct
result to several Python lines that surprise you)

All this Python bashing is starting to feel like mocking
a retarded child...

420

Trolls are not welcomed, get lost.

G. Rodrigues
Jul 18 '05 #10

Bengt Richter wrote:
On Mon, 27 Oct 2003 11:14:52 GMT, Alex Martelli <al***@aleax.it> wrote:

...
No new "directive" needed: it's easy to get "snap-shots" of current
values of names into a lambda or other function:

map(lambda f: f(1), [lambda x, i=i: x+i for i in range(3)])

The "i=i" gets the (outer) value of i at function-definition time and
injects it as local variable i in the lambda. You can also rename just
as easily (and sometimes it's clearer):

map(lambda f: f(1), [lambda x, k=i: x+k for i in range(3)])

I think it would be nice if we could inject a value as a local variable
without being part of the calling signature for the function. E.g., if
the parameter list had a way to delimit "injected" values so that they
weren't part of the parameter list per se. E.g., using '|' to separate
local-variable presets,

map(lambda f: f(1), [lambda x|k=i: x+k for i in range(3)])

Well then, AFAIU, the

lambda x, k = 1: ...

idiom serves to introduce an optional lambda bound variable.
I.e. something that in CL has been there since 1984 and earlier. Your
suggestion is instead along the lines of the &AUX lambda parameter
already present in Common Lisp (another non surprise) since 1984 and before.

But this begs the question. The bottom line is that Python needs to get
proper lambda expressions. The extra "quote" local "unquote" argument
is not what you'd expect.

Cheers
--
Marco Antoniotti

Jul 18 '05 #11
Thank you, Alex, for clarifing this issue for me..

So this was actually like the famous equation
"9*6=42"
:-)
It is correct (or incorrect) if you look at it in the right (or wrong) way.

Best,
Miklós

--
PRISZNYÁK Miklós
---
Jegenye 2001 Bt. ( mailto:je*********@parkhosting.com )
Custom software development, consulting
http://jegenye2001.parkhosting.com
Alex Martelli <al***@aleax.it> wrote in message
news:M6***********************@news2.tin.it...
Isaac To wrote:
...
Did you really mean

map(lambda f: f(1), [lambda x: x+i for i in range(3)])

? If so, it does return [3, 3, 3]. The only problem here is that Python variables are name lookups over dictionaries, and as such the value of "i" is not coined into the lambda. Rather it is "external", binded
dynamically. I believe the behaviour can be fixed rather easily by some
directives, say making it

map(lambda f: f(1), [lambda x: x+(*i) for i in range(3)])

No new "directive" needed: it's easy to get "snap-shots" of current
values of names into a lambda or other function:

map(lambda f: f(1), [lambda x, i=i: x+i for i in range(3)])

The "i=i" gets the (outer) value of i at function-definition time and
injects it as local variable i in the lambda. You can also rename just
as easily (and sometimes it's clearer):

map(lambda f: f(1), [lambda x, k=i: x+k for i in range(3)])

Alex

Jul 18 '05 #12
Marco Antoniotti wrote:
But this begs the question. The bottom line is that Python needs to get
proper lambda expressions. The extra "quote" local "unquote" argument
is not what you'd expect.

Unfortunately, Guido (van Rossum) has many times over voiced his
non-support for functional constructs in Python.
In other words, I guess he'd rather pull lambdas from Python than add
"proper" support for them.

And again, how do you define "proper"?

Mauro

Jul 18 '05 #13
>
So this was actually like the famous equation
"9*6=42"
:-)
It is correct (or incorrect) if you look at it in the right (or wrong) way.

Nope, it's flat out wrong. The idea that it was true in a different base didn't
even occur to Douglas Adams, if that's what you're suggesting. :) However, the
analogy still works if you just pretend otherwise.

- Kef
Jul 18 '05 #14
Jeremy Fincher wrote:
Expected by functional programmers who expect new lexical scopes to be
created at every block, sure. But Python isn't a functional
programming language, and doesn't create a new lexical scope in every
block.

The Python result is only surprising to those who try to impose other
languages' semantics on Python.

Yes, that's true but functional programmers come from a "carry your semantics
on your sleave" angle at things. Let's see how we build this in Scheme. If I
understand Python's semantics properly, a for-iterator has this semantics:

(define-syntax python-for
(syntax-rules (in range)
[(_ x in (range n) exp ...)
(let ([x #f])
(for-each (lambda (i) (set! x i) exp ...) (build-list n identity)))]))

It sets up an iteration variable and then mutates the iteration variable for
each iteration. Then you evaluate the body of the for. A Schemer wouldn't cut
the overhead and write/expect something like that:

(define-syntax scheme-for
(syntax-rules (in range)
[(_ x in (range n) exp ...)
(for-each (lambda (x) exp ...) (build-list n identity))]))

Here we just iterate over the specified variable. (I have the iteration order of
the number sequence backwards. That's intended to skip a small bit of syntactic

Now depending on which of these for's you use you get different results for

(define flist '())

(define f #f)

(for i in (range 3)
(set! f (lambda (x) (+ x i)))
(set! flist (cons f flist)))

(map (lambda (f) (f 1)) flist)

Nothing surprising here for someone who studies language semantics. Things are
as they are. But to someone who compares these things, I must admit that I am
astonished that Python chose the first, complicated (not on your sleave)
semantics and rejected the second one.

-- Matthias

Jul 18 '05 #15
On Mon, 27 Oct 2003 19:39:40 +0100, rumours say that "Jegenye 2001 Bt"
<je*********@fw.hu> might have written:
Thank you, Alex, for clarifing this issue for me..

So this was actually like the famous equation
"9*6=42"
:-)

Nope, the left part of the equation is yet to be defined.
--
TZOTZIOY, I speak England very best,
Ils sont fous ces Redmontains! --Harddix
Jul 18 '05 #16
Jegenye 2001 Bt wrote:
Thank you, Alex, for clarifing this issue for me..

So this was actually like the famous equation
"9*6=42"
:-)
It is correct (or incorrect) if you look at it in the right (or wrong)
way.

Do you mean, implicitly using base 13? I know of no programming
language that lets you set the number base to be used for literals
(except presumably ones with particularly 'powerful' macros...?-)
and I hope I never have to contend with one.
Alex

Jul 18 '05 #17
Alex Martelli <al***@aleax.it> writes:

Do you mean, implicitly using base 13? I know of no programming
language that lets you set the number base to be used for literals Forth. (except presumably ones with particularly 'powerful' macros...?-)
and I hope I never have to contend with one.
You might be lucky :-).

/Justin

Alex

--

Jul 18 '05 #18
On Tue, 28 Oct 2003 11:35:25 GMT,
Alex Martelli <al***@aleax.it> wrote:
Do you mean, implicitly using base 13? I know of no programming
language that lets you set the number base to be used for
literals (except presumably ones with particularly 'powerful'
macros...?-) and I hope I never have to contend with one.

have data (e.g., in a file generated by someone else) in a non-10
base.

Regards,
Heather

--
Heather Coppersmith
That's not right; that's not even wrong. -- Wolfgang Pauli
Jul 18 '05 #19
Justin Pearson wrote:
Alex Martelli <al***@aleax.it> writes:

Do you mean, implicitly using base 13? I know of no programming
language that lets you set the number base to be used for literals

Forth.
(except presumably ones with particularly 'powerful' macros...?-)

and I hope I never have to contend with one.

You might be lucky :-).

Actually, I did work in Forth (it was the in-ROM language of a
neat computer I once bought, called "Jupiter ACE"; and also of a
special-purpose image processing PC card I once used at work),
but never came across that "feature" (assuming those dialects of
Forth in those ROMs supported it, that is). Guess I was lucky
that in those special cases I wasn't sharing code w/others:-).
Alex

Jul 18 '05 #20
Alex Martelli wrote:
Jegenye 2001 Bt wrote:
So this was actually like the famous equation
"9*6=42"
:-)
It is correct (or incorrect) if you look at it in the right (or wrong)
way.

Do you mean, implicitly using base 13? I know of no programming
language that lets you set the number base to be used for literals
(except presumably ones with particularly 'powerful' macros...?-)
and I hope I never have to contend with one.

In Icon you can write 13r9 * 13r6. Icon is a decent, although weakly known
language, without any "particularly 'powerful' macros", which permits to
choose the base of literals. Nothing horrible.
Jerzy Karczmarczuk

Jul 18 '05 #21
Jerzy Karczmarczuk wrote:
Alex Martelli wrote:
Jegenye 2001 Bt wrote:
So this was actually like the famous equation
"9*6=42"
... Do you mean, implicitly using base 13? I know of no programming

... In Icon you can write 13r9 * 13r6. Icon is a decent, although weakly known
language, without any "particularly 'powerful' macros", which permits to
choose the base of literals. Nothing horrible.

Yes, I used to love Icon (the coroutines and backtracking and all, cool!)
but notice it uses EXPLICIT indications of non-10 base. There is, indeed,
nothing at all horrible with that.

Besides, the problem is not with 9 or 6, which happen to have the same
value in either base 10 or 13:-). The problem is with that result...:)
Alex

Jul 18 '05 #22
In article <yj***********************@news2.tin.it>, Alex Martelli wrote:

Actually, I did work in Forth (it was the in-ROM language of a
neat computer I once bought, called "Jupiter ACE"; and also of a
special-purpose image processing PC card I once used at work),
but never came across that "feature" (assuming those dialects of
Forth in those ROMs supported it, that is). Guess I was lucky
that in those special cases I wasn't sharing code w/others:-).

Well the Jupiter ACE (of which I'm still a proud owner) suppored it,
it's in the '79 standard after all. E.g. just do '16 base !', for
hexadecimal input for example. Makes writing an assembler in Forth,
or the usual combination of Forth and assembly simpler if nothing else.

As everything Forth, judicious use is key.

Stefan,
--
Stefan Axelsson (email at http://www.cs.chalmers.se/~sax)
Jul 18 '05 #23
Isaac To <kk**@csis.hku.hk> wrote in message news:<7i************@enark.csis.hku.hk>...
I believe the behaviour can be fixed rather easily by some directives, say
making it

map(lambda f: f(1), [lambda x: x+(*i) for i in range(3)])

where the * construct would get the reference of i at function definition
time rather than at function invocation time (anyone can point me to an
PEP?).

We can essentially do this by passing i to a function that then returns the
desired function. So to make flist with the functions that mike420 wanted,
we can use:

flist = map(lambda i: (lambda x: x+i), range(3))

Now [f(1) for f in flist] is [1, 2, 3] as he expected.
Jul 18 '05 #24

Alan Offer wrote:
Isaac To <kk**@csis.hku.hk> wrote in message news:<7i************@enark.csis.hku.hk>...

I believe the behaviour can be fixed rather easily by some directives, say
making it

map(lambda f: f(1), [lambda x: x+(*i) for i in range(3)])

where the * construct would get the reference of i at function definition
time rather than at function invocation time (anyone can point me to an
PEP?).

We can essentially do this by passing i to a function that then returns the
desired function. So to make flist with the functions that mike420 wanted,
we can use:

flist = map(lambda i: (lambda x: x+i), range(3))

Now [f(1) for f in flist] is [1, 2, 3] as he expected.

This is good and I stand corrected then. At least you can achieve this
with Python.

Cheers
--
marco

Jul 18 '05 #25
>>>>> "Alan" == Alan Offer <al********@hotmail.com> writes:

Alan> Isaac To <kk**@csis.hku.hk> wrote in message
Alan> news:<7i************@enark.csis.hku.hk>...
I believe the behaviour can be fixed rather easily by some
directives, say making it

map(lambda f: f(1), [lambda x: x+(*i) for i in range(3)])

where the * construct would get the reference of i at function
definition time rather than at function invocation time (anyone can
point me to an PEP?).

Alan> We can essentially do this by passing i to a function that then
Alan> returns the desired function. So to make flist with the functions
Alan> that mike420 wanted, we can use:

Alan> flist = map(lambda i: (lambda x: x+i), range(3))

Alan> Now [f(1) for f in flist] is [1, 2, 3] as he expected.

Ah... that means

map(lambda f: f(1), [(lambda i: lambda x: x+i)(i) for i in range(3)])

Seems make sense to me.

Regards,
Isaac.
Jul 18 '05 #26

This thread has been closed and replies have been disabled. Please start a new discussion.