Python newbie

M

Mladen Gogala

I am a Python newbie who decided to see what that Python fuss is all about.
Quite frankly, I am a bit perplexed. After having had few months of
experience with Perl (started in 1994 with Perl v4, and doing it ever
since) , here is what perplexes me:

perl -e '@a=(1,2,3); map { $_*=2 } @a; map { print "$_\n"; } @a;'

The equivalent in Python looks like this:

Python 2.5.1 (r251:54863, Jun 15 2008, 18:24:51)
[GCC 4.3.0 20080428 (Red Hat 4.3.0-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
a=[1,2,3]
map((lambda x: 2*x),a) [2, 4, 6]
map((print),a)
File "<stdin>", line 1
map((print),a)
^
SyntaxError: invalid syntax....
1
2
3....
1
2
3
There are several questions:

1) Why is the array "a" unchanged after undergoing a transformation with
map?
2) Why is it illegal to pass a built-in function "print" to map?
3) Why is the array "a" unchanged after undergoing an explicit
transformation with the "for" loop?
4) Is there an equivalent to \$a (Perl "reference") which would allow me to
decide when a variable is used by value and when by reference?

PHP also allows changing arrays with "foreach" loop:
#!/usr/local/bin/php
<?php
$a=array(1,2,3);
foreach($a as &$x) { $x=$x*2; }
array_walk($a,create_function('$a','print("$a\n"); '));
?>

How can I make sure that
for x in a: x=2*x

actually changes the elements of the array "a"?


http://mgogala.freehostia.com
 
S

Steve Holden

Mladen said:
I am a Python newbie who decided to see what that Python fuss is all about.
Quite frankly, I am a bit perplexed. After having had few months of
experience with Perl (started in 1994 with Perl v4, and doing it ever
since) , here is what perplexes me:

perl -e '@a=(1,2,3); map { $_*=2 } @a; map { print "$_\n"; } @a;'

The equivalent in Python looks like this:

Python 2.5.1 (r251:54863, Jun 15 2008, 18:24:51)
[GCC 4.3.0 20080428 (Red Hat 4.3.0-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
a=[1,2,3]
map((lambda x: 2*x),a) [2, 4, 6]
map((print),a)
File "<stdin>", line 1
map((print),a)
^
SyntaxError: invalid syntax...
1
2
3...
1
2
3

There are several questions:

1) Why is the array "a" unchanged after undergoing a transformation with
map?

Because you evaluated an expression in which a was a variable, giving an
entirely new object as a result.
2) Why is it illegal to pass a built-in function "print" to map?

Because at present "print" isn't a built-in function, it's a keyword
designating a specific statement type. Try using sys.stdout.write instead.
3) Why is the array "a" unchanged after undergoing an explicit
transformation with the "for" loop?

Because you aren't transforming a. You are extracting references to a's
elements into a separate variable and rebinding that variable to a new
value, leaving the references in a's elements pointing to the original
objects.
4) Is there an equivalent to \$a (Perl "reference") which would allow me to
decide when a variable is used by value and when by reference?
No. Python implicitly dereferences all names when using them to compute
values, and only uses them as references on the left-hand side of an
assignment.

Please note the above statement is contentious, and will likely bring a
horde of screaming fanatics of various flavors down on my head for
terminological inexactitude.
PHP also allows changing arrays with "foreach" loop:
#!/usr/local/bin/php
<?php
$a=array(1,2,3);
foreach($a as &$x) { $x=$x*2; }
array_walk($a,create_function('$a','print("$a\n"); '));
?>

How can I make sure that
for x in a: x=2*x

actually changes the elements of the array "a"?
By saying something like

a = [2*x for x in a]

You don't modify the individual elements, you create a new list and
rebind a to that. AIf you insist on changing the elements of a, a more
cumbersome alternative is

for i, x in enumerate(a):
a = 2+x

regards
Steve
 
M

Marc 'BlackJack' Rintsch

There are several questions:

1) Why is the array "a" unchanged after undergoing a transformation with
map?

Because `map()` creates a new list and doesn't change the elements in `a`.
2) Why is it illegal to pass a built-in function "print" to map?

Because ``print`` isn't a function but a keyword. This will be changed
in Python 3.0. On the other hand this use case is discouraged because
`map()` builds a new list with the return value of the given function.
So you would build a list full of `None`\s just for the side effect.
3) Why is the array "a" unchanged after undergoing an explicit
transformation with the "for" loop?

Because there is no explicit transformation. The loop binds elements to
the name `x` in your example and within the loop you rebind that name to
another value. Neither the name `x` nor the objects bound to it have any
idea that the object might be referenced in some container object.
4) Is there an equivalent to \$a (Perl "reference") which would allow me
to decide when a variable is used by value and when by reference?

No, variables in Python are always name to object bindings. Don't think
of variables as boxes with names on it where you put objects in, or
references to another box. Think of objects and sticky notes with names
on it.
How can I make sure that
for x in a: x=2*x

actually changes the elements of the array "a"?

Well, actually change the elements. ;-)

Either:

for index, item in enumerate(sequence):
sequence[index] = func(item)

Or:

sequence[:] = map(func, sequence)

But the need to do so doesn't seem to be that frequent. Usually one just
builds a new list instead of altering an existing one.

Ciao,
Marc 'BlackJack' Rintsch
 
S

Steven D'Aprano

I am a Python newbie who decided to see what that Python fuss is all
about. Quite frankly, I am a bit perplexed.

Naturally you will be perplexed if you assume that Python is just Perl
with a more verbose syntax. It isn't.

After having had few months
of experience with Perl (started in 1994 with Perl v4, and doing it ever
since) , here is what perplexes me:

perl -e '@a=(1,2,3); map { $_*=2 } @a; map { print "$_\n"; } @a;'

The equivalent in Python looks like this:

Actually, no it doesn't. The equivalent looks more like this:


$ python -c 'a=[1,2,3]; a=[2*x for x in a];
for x in a:
print x'
2
4
6



Now, to go on with your questions:


1) Why is the array "a" unchanged after undergoing a transformation with
map?


Because it hasn't undergone a transformation at all. The list (not array)
a remains unchanged, because map returns a new list.


2) Why is it illegal to pass a built-in function "print" to map?

Because print is not a function, it is a statement. However, in Python 3,
that design wart has been corrected.

3) Why is the array "a" unchanged after undergoing an explicit
transformation with the "for" loop?


Because the list a hasn't undergone any such transformation. Rebinding a
name is not an explicit transformation to the object that used to be
bound to the name. And if that sentence is gobbledygook to you, that
demonstrates that Python is not Perl and you shouldn't assume a one-to-
one semantic relationship between syntactical elements.


4) Is there an equivalent to \$a (Perl "reference") which would allow me
to decide when a variable is used by value and when by reference?

Python is neither call-by-reference nor call-by-value, although you will
have many people swear black and blue that it is one or the other. With
respect to all of them, they are wrong. Python's calling model is "call
by object". See here for more detail:

http://effbot.org/zone/call-by-object.htm


If you insist on a false dichotomy between call-by-reference and call-by-
value, then you won't often go wrong if you think of Python:

- being almost always call-by-reference, except for some odd corner cases
which look almost, but not quite, like call-by-value;

- being almost always call-by-value, but only if you think of the values
as pointers.

How can I make sure that
for x in a: x=2*x

actually changes the elements of the array "a"?

By explicitly changing the elements of the list. Here's one very old-
fashioned way of doing so:
a = [1,2,3]
for i in range(len(a)):
.... a = a*2
....[2, 4, 6]


Here's a more Pythonic alternative:
a = [1,2,3]
a = [2*x for x in a]
 
S

Steven D'Aprano

Please note the above statement is contentious, and will likely bring a
horde of screaming fanatics of various flavors down on my head for
terminological inexactitude.

A pox on you and your descendants onto the tenth generation!


*wink*
 
T

Tim Golden

Mladen said:
Actually, I am not a "screaming fanatic". I just want to learn.

I'm sure Steve can speak for himself, but just to clarify:
the "screaming fanatics" referred to are those within the
Python community whose opinions of the terminology used are
at variance with Steve's. I think it was a comment which would
mean more to those of us who've seen such terminology-battles
come and go over the years.

But thanks for introducing yourself anyway. Knowing more about
where a poster is coming from never hurts when trying to answer
their questions. :)

TJG
 
K

kaer

Naturally you will be perplexed if you assume that Python is just Perl
with a more verbose syntax. It isn't.

Indeed, it isn't ... at all:
$ python -c 'for s in [2*x for x in (1, 2, 3)]: print s'
2
4
6

And it's always (a lot) more readable :)

kb
 
P

Peter Pearson

perl -e '@a=(1,2,3); map { $_*=2 } @a; map { print "$_\n"; } @a;'

The equivalent in Python looks like this:

Actually, no it doesn't. The equivalent looks more like this:


$ python -c 'a=[1,2,3]; a=[2*x for x in a];
for x in a:
print x'
2
4
6

Good job, SD'A.

A note for Mladen Gogala: the [...for...] construction in

a=[2*x for x in a];

is called a list comprehension, and is wonderful for shortening
and clarifying code. One of the pleasures of following this
group is watching the old hands answer noob questions with one
or two list comprehensions.
 
B

bearophileHUGS

Mladen Gogala:

Welcome to Python, you will need only one or few weeks to be able to
write useful Python programs. But even with the help of a good book
(that I suggest you to read) you may need several months or one year
to master it :)
2) Why is it illegal to pass a built-in function "print" to map?

Maybe because one of the few original design mistakes of Python. The
new Python 3.0 "fixes" that problem, in Python 3 print is now a
function, so you can use it where you can use functions.
But in general I think it's better to not give map() a function that
has side effects like print().
So you want to use a list comp there instead, and create a new list:
[2 * el for el in a]

In Python (and several other modern languages, like Scala, plus some
more functional languages) you will find that people often prefer to
create new data structures instead of modifying old ones. This may
sound like a waste of memory and time, but using a more immutable-data
style has several advantages (often in code clarity) that are a bit
complex to explain here.

As you probably know, the good thing of learning new languages is that
they carry some principles, and they are the expression of some ideas
of the computer science. So learning Python may show you some new
ideas, or new ways to look at old computer science ideas you already
know. I think Alan J. Perlis said "A language that doesn't affect the
way you think about programming, is not worth knowing."

Bye,
bearophile
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top