Many newbie questions regarding python

  • Thread starter Rogério Brito
  • Start date
R

Rogério Brito

Hi there.

I am used to some languages like C, but I am just a complete newbie with Python
and, while writing some small snippets, I had encountered some problems, with
which I would sincerely appreciate any help, since I appreciate this language to
write my "running pseudocode in" and I am seriously thinking of using it to
teach some algorithms classes.

1 - The first issue that I am having is that I don't seem to be able to, say,
use something that would be common for people writing programs in C: defining a
one-dimensional vector and only initializing it when needed.

For instance, in C, I would write something like:

int v[20];
for (i = 0; i < 20; i++)
v = 0;

Note that I only define the vector v (and its size) at the beginning but
initialize it latter during the code per-se.

My first try to write it in Python was something like this:

v = []
for i in range(20):
v = 0

Unfortunately, this doesn't work, as I get an index out of bounds when trying to
index the v list. Of course, the main difference between the two snippets is
that, in C, I declared v to have 20 positions, while in python I initialized it
to be the empty list and, indeed, it has an empty set of indexes.

What is the Pythonic way of writing code like this? So far, I have found many
alternatives and I would like to write code that others in the Python community
would find natural to read. Some of the things that crossed my mind:

v = [0 for i in range(20)]

v = [0] * 20

v = []
for i in range(20): v.append(0)

What should I prefer? Any other alternative?

If possible, I would like to simply declare the list and fill it latter in my
program, as lazily as possible (this happens notoriously when one is using a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling of the
array).


2 - If I declare a class with some member variables, is is strictly necessary
for me to qualify those members in a method in that class? For instance, if I
define:

class C:
f = 1
def g(self):
return f

I get an annoying message when I try to call the g method in an object of type
C, telling me that there's no global symbol called f. If I make g return self.f
instead, things work as expected, but the code loses some readability.

Is there any way around this or is that simply "a matter of life"?

I have some other questions, but I will save them for latter.

Please, keep in mind that I am a newbie in Python. Despite that, I am enjoying
the little that I know.


Thank you very much in advance,
 
C

Carl Banks

    v = [0 for i in range(20)]

    v = [0] * 20

    v = []
    for i in range(20): v.append(0)

What should I prefer? Any other alternative?

The Pythonic way is to not to preinitialize the list at all. Don't
put anything in the list until you have the data you need.
If possible, I would like to simply declare the list and fill it latter in my
program, as lazily as possible (this happens notoriously when one is using a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling of the
array).

So, if I understand you, you are thinking of your list as a table with
dynamically calculated entries, and want to calculate the entries upon
request.

Three possibilities:

1. Initialize the list using v = [None]*n (I recomment using None
instead of 0 for this, in most cases)

2. Use a dict instead. Dict items pop into existence if you assign
with a key that doesn't exist.

v = {}

Then you can do

v[1] = a
v[10] = n
v[999] = c

3. Consider numpy, which allows preallocation of lists:

v = np.zeros(100)


[snip]
For instance, if I
define:

class C:
    f = 1
    def g(self):
        return f

I get an annoying message when I try to call the g method in an object of type
C, telling me that there's no global symbol called f. If I make g return self.f
instead, things work as expected, but the code loses some readability.

Is there any way around this or is that simply "a matter of life"?

Matter of life. It's that way by design.


Carl Banks
 
A

Andreas Waldenburger

I am used to some languages like C, but I am just a complete newbie
with Python and, while writing some small snippets, I had encountered
some problems, with which I would sincerely appreciate any help,
since I appreciate this language to write my "running pseudocode in"
and I am seriously thinking of using it to teach some algorithms
classes.
Let me congratulate you on your choice.

1 - The first issue that I am having is that I don't seem to be able
to, say, use something that would be common for people writing
programs in C: defining a one-dimensional vector and only
initializing it when needed.
[snip]
I could be cheeky here and ask "Do you really need this? REALLY?". And
I will: Really? ;)
Note that I only define the vector v (and its size) at the beginning
but initialize it latter during the code per-se.

[snip]

What is the Pythonic way of writing code like this? So far, I have
found many alternatives and I would like to write code that others in
the Python community would find natural to read. Some of the things
that crossed my mind:

v = [0 for i in range(20)]
Pretty good.

v = [0] * 20
This will break on you if you replace the zeros with mutable objects.
Try it, you'll be unpleasantly surprised.

I guess it's OK for numbers, though. Or tuples, if need be.

v = []
for i in range(20): v.append(0)
That's the older (pre list comp) way, I guess. No need for it anymore,
unless the initialization is more complicated than this.

If possible, I would like to simply declare the list and fill it
latter in my program, as lazily as possible (this happens notoriously
when one is using a technique of programming called dynamic
programming where initializing all positions of a table may take too
much time in comparison to the filling of the array).
Nah, don't worry too much about performance. You can do that when your
program is too slow.

I know that this isn't too satisfying, but seriously: Try to write
programs for humans, not for the computer. (I'm talking about Python
here; in C it's certainly par for the course to try to think like a
computer does.)

2 - If I declare a class with some member variables, is is strictly
necessary for me to qualify those members in a method in that class?
For instance, if I define:

class C:
f = 1
def g(self):
return f

I get an annoying message when I try to call the g method in an
object of type C, telling me that there's no global symbol called f.
If I make g return self.f instead, things work as expected, but the
code loses some readability.
No it doesn't.

(... pedagogical pause ...)

Python kind of forces you to be *very* explicit about which f you mean.
And this is a good thing. If you mean the global f, then say f. If you
mean the instance attribute of the current instance then say self.f and
if you mean the class attribute then say C.f (or, if you fear you're
going to be renaming C a lot, self.__class__.f).

Note here that self.f refers to the f as accessible by the
specific *instance* of the class, *not* the class attribute C.f. If you
don't change f on the instance, then they'll coincide, otherwise they
won't. Example (warning: not Python 3 compatible!):

[wildemar@localhost ~]$ ipython
Python 2.5.2 (r252:60911, Sep 30 2008, 15:41:38)
Type "copyright", "credits" or "license" for more information.

IPython 0.8.4 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.

In [1]: class C:
...: f = 1
...: def g(self):
...: return self.f
...:
...:

In [2]: c = C();

In [3]: print c.g()
1

In [4]: C.f = 2

In [5]: print c.g()
2

In [6]: c.f = 3

In [7]: print c.g()
3

In [8]: print C.f
2


Is there any way around this or is that simply "a matter of life"?
Yes.


I have some other questions, but I will save them for latter.
Keep 'em coming. But be prepared for hearing "get used to it" many a
time. Or, from the more harsh folks, "don't try to write C in
Python". :)

Please, keep in mind that I am a newbie in Python. Despite that, I am
enjoying the little that I know.
Really? I never enjoy knowing just a little. ;)
 
G

gregfull

Hi there.

I am used to some languages like C, but I am just a complete newbie with Python
and, while writing some small snippets, I had encountered some problems, with
which I would sincerely appreciate any help, since I appreciate this language to
write my "running pseudocode in" and I am seriously thinking of using it to
teach some algorithms classes.

1 - The first issue that I am having is that I don't seem to be able to, say,
use something that would be common for people writing programs in C: defining a
one-dimensional vector and only initializing it when needed.

For instance, in C, I would write something like:

int v[20];
for (i = 0; i < 20; i++)
    v = 0;

Note that I only define the vector v (and its size) at the beginning but
initialize it latter during the code per-se.

My first try to write it in Python was something like this:

v = []
for i in range(20):
    v = 0

Unfortunately, this doesn't work, as I get an index out of bounds when trying to
index the v list. Of course, the main difference between the two snippets is
that, in C, I declared v to have 20 positions, while in python I initialized it
to be the empty list and, indeed, it has an empty set of indexes.

What is the Pythonic way of writing code like this? So far, I have found many
alternatives and I would like to write code that others in the Python community
would find natural to read. Some of the things that crossed my mind:

    v = [0 for i in range(20)]

    v = [0] * 20

    v = []
    for i in range(20): v.append(0)

What should I prefer? Any other alternative?

If possible, I would like to simply declare the list and fill it latter in my
program, as lazily as possible (this happens notoriously when one is using a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling of the
array).

2 - If I declare a class with some member variables, is is strictly necessary
for me to qualify those members in a method in that class? For instance, if I
define:

class C:
    f = 1
    def g(self):
        return f

I get an annoying message when I try to call the g method in an object of type
C, telling me that there's no global symbol called f. If I make g return self.f
instead, things work as expected, but the code loses some readability.

Is there any way around this or is that simply "a matter of life"?

I have some other questions, but I will save them for latter.

Please, keep in mind that I am a newbie in Python. Despite that, I am enjoying
the little that I know.

Thank you very much in advance,


How about:

v = [None] * 20

That way, you're not initializing with an artifical value like 0.
 
M

MRAB

Hi there.

I am used to some languages like C, but I am just a complete newbie with Python
and, while writing some small snippets, I had encountered some problems, with
which I would sincerely appreciate any help, since I appreciate this language to
write my "running pseudocode in" and I am seriously thinking of using it to
teach some algorithms classes.

1 - The first issue that I am having is that I don't seem to be able to, say,
use something that would be common for people writing programs in C: defining a
one-dimensional vector and only initializing it when needed.

For instance, in C, I would write something like:

int v[20];
for (i = 0; i< 20; i++)
v = 0;

Note that I only define the vector v (and its size) at the beginning but
initialize it latter during the code per-se.

My first try to write it in Python was something like this:

v = []
for i in range(20):
v = 0

Unfortunately, this doesn't work, as I get an index out of bounds when trying to
index the v list. Of course, the main difference between the two snippets is
that, in C, I declared v to have 20 positions, while in python I initialized it
to be the empty list and, indeed, it has an empty set of indexes.

What is the Pythonic way of writing code like this? So far, I have found many
alternatives and I would like to write code that others in the Python community
would find natural to read. Some of the things that crossed my mind:

v = [0 for i in range(20)]

v = [0] * 20

v = []
for i in range(20): v.append(0)

What should I prefer? Any other alternative?

If possible, I would like to simply declare the list and fill it latter in my
program, as lazily as possible (this happens notoriously when one is using a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling of the
array).

Python doesn't have declarations. The code:

v = []

simply creates an empty list and binds the name 'v' to it. If you want
to create a list containing 20 zeros then:

v = [0] * 20

is the Pythonic way. Which one you do depends on the particular problem
you're working on; do whichever makes the most sense.
2 - If I declare a class with some member variables, is is strictly necessary
for me to qualify those members in a method in that class? For instance, if I
define:

class C:
f = 1
def g(self):
return f

I get an annoying message when I try to call the g method in an object of type
C, telling me that there's no global symbol called f. If I make g return self.f
instead, things work as expected, but the code loses some readability.

Is there any way around this or is that simply "a matter of life"?
The name 'f' in that case is an attribute of the class itself. If you
want it to be an attribute of an instance of the class then do
something like this:

class C:
def __init__(self):
self.f = 1
def g(self):
return self.f

You should write Python code in the Python idiom and not try to look
for the Python equivalent of a C idiom. In other words, don't try to
write a C program in Python! You might want to read "The Zen of
Python". Just type:

help("this")

at the Python prompt.
 
T

Tim Harig

1 - The first issue that I am having is that I don't seem to be able to, say,
use something that would be common for people writing programs in C: defining a
one-dimensional vector and only initializing it when needed.

For instance, in C, I would write something like:

int v[20];
for (i = 0; i < 20; i++)
v = 0;

Note that I only define the vector v (and its size) at the beginning but
initialize it latter during the code per-se.


You are reserving enough space to be defined as an array of 20 integers.
Note that after you declare it, you *can* access those memory locations
even before you initialize them. They therefore still contain something
even if you have not yet defined what that something is. Note that
uninitialized variables are a common C error.

Python is dynamic. You never need to allocate memory for something, you
simply assign something and the system takes care of the allocation for
you. Before something is assigned, it cannot be addressed. Nothing takes
up memory before it is assigned.
Unfortunately, this doesn't work, as I get an index out of bounds when trying to
index the v list. Of course, the main difference between the two snippets is
that, in C, I declared v to have 20 positions, while in python I initialized it
to be the empty list and, indeed, it has an empty set of indexes.

What is the Pythonic way of writing code like this? So far, I have found many
alternatives and I would like to write code that others in the Python community
would find natural to read. Some of the things that crossed my mind:

v = [0 for i in range(20)]

v = [0] * 20

v = []
for i in range(20): v.append(0)

What should I prefer? Any other alternative?

It really would help to know what you are trying to with v. If we knew
that, we might be able to make better suggestions. Usually in Python,
there is no need to initialize elements in a list as you can simply add
them as you need them.
If possible, I would like to simply declare the list and fill it latter in my
program, as lazily as possible (this happens notoriously when one is using a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling of the
array).

What I *think* you *might* be looking for is a kind of sparse list. You
can achieve this by using a dictionary with numeric keys rather then a
list. Not that when you do this, you recreate the C problem of trying to
access something that has not been allocated. You either need to make sure
that a key exists before trying to access it or catch and handleKeyError.
2 - If I declare a class with some member variables, is is strictly necessary
for me to qualify those members in a method in that class? For instance, if I
define:

class C:
f = 1
def g(self):
return f

Note that you have assigned f to the class object and not to the instance
objects. This is a common pitfall for new Python programmers. I suggest
assigning f in the constructor unless you are really sure that you want to
assign it to the class object which will be shared among the instance
objects.
I get an annoying message when I try to call the g method in an object of type
C, telling me that there's no global symbol called f. If I make g return self.f
instead, things work as expected, but the code loses some readability.

Is there any way around this or is that simply "a matter of life"?

Each member functions has its own scope. The object itself is not part of
this scope. Therefore, you must use the self object reference to access
other members of the object containing the function.

I don't really see the readability problem; but, you could work around it
by creating a reference to the member at the start of the function:

def g(self):
f = self.f

For this to work, f must be mutable. If f is not mutable then you can wrap
f inside of a class in such a way that it is mutable. Do this at your own
risk. In doing this, you are starting to play with fire.
 
S

Steven D'Aprano

What is the Pythonic way of writing code like this? So far, I have
found many alternatives and I would like to write code that others in
the Python community would find natural to read. Some of the things
that crossed my mind:

v = [0 for i in range(20)]

Absolutely not. Such a code snippet is very common, in fact I've done it
myself, but it is a "hammer solution" -- to a small boy with a hammer,
everything looks like a nail that needs hammering. Writing such a list
comprehension is a "list comp solution".

v = [0] * 20

Yes, this is the solution. But given your earlier explanation that you
want to lazily initialise v, I don't think it applies, because it
initialises it all at once. (Of course, such initialisation is cheap, but
it does happen all at once.)

If you are writing this:

v = [] # declare v as an empty list
do_something()
do_something_else()
v = [0]*20 # now initialise v before using it
do_something_with(v)


then such declarations are not necessary and are discouraged in Python.
Having an unused, empty variable v floating around doing nothing is
pointless in Python. Just write:

do_something()
do_something_else()
v = [0]*20 # create v before using it
do_something_with(v)


v = []
for i in range(20): v.append(0)

I would never write that literally. It's as bad as the list comp, only it
takes up more space. It too also fails to be lazy initialisation.
However, using append is the correct way when you have a situation where
you need to dynamically grow the list, e.g.:


v = []
for i in range(20):
v.append(0)
do_something_with(v)



Two more alternatives:

v = list(range(20)) # in Python 2.x you can leave out the call to list()

or

v = []
v.extend(range(20))

both initialise v to [0, 1, 2, 3, ... , 19] instead of [0, 0, ..., 0].



2 - If I declare a class with some member variables, is is strictly
necessary for me to qualify those members in a method in that class? For
instance, if I define:

In Python, we generally refer to "attributes" rather than "members".

class C:
f = 1
def g(self):
return f

By the way, you have created a class attribute f which is shared by all
instances. You probably want:

class C:
def __init__(self):
self.f = 1
def g(self):
return self.f


I get an annoying message when I try to call the g method in an object
of type C, telling me that there's no global symbol called f.

No you don't. You get a message that there is no global NAME called f.

You might think I'm being pedantic, but I'm not. If you're thinking in
terms of C language, you probably think that there is a symbol table
created by the compiler so that Python can look at a reference "f" and
say "oh, that's a member variable" at compile time, and only the correct
value needs to be looked up at runtime. But that's not Python's execution
model. *Everything* in Python is looked up dynamically at runtime in
namespaces. (The only exceptions are statements.) So when you write "f",
Python *cannot* know at compile time whether it is a local variable, a
non-local, a global, an attribute (member) or something else. It must
look the name up in one or more namespaces at runtime.


(Of course, you might already know this, in which case, yes, I'm just
being pedantic *grins* )


If I make
g return self.f instead, things work as expected, but the code loses
some readability.

On the contrary, it increases readability, because it explicitly tells
the reader that you are accessing an attribute f rather than a local
variable.

Remember that Python uses nested namespaces. Inside the method C.g above
the namespaces that are searched are:

local variables
any non-local (nested) functions or closures (none in this example)
global variables
built-ins

in that order. Each namespace is independent, and Python will never try
to guess that f is an attribute of the instance or class unless you
explicitly tell it so. For example, an attribute instance.len will never
block access to the built-in function len().

(Actually, there is one exception... when a class statement is executed
for the first time, creating the class, local variables of the class
block are identified as attributes. This is a case of practicality beats
purity, since otherwise Python would need extra syntax for creating
methods and class attributes.)


Attributes have their own search order:

instance attributes
class attributes
attributes of any base classes

When you refer to instance.attribute, the namespaces are searched in that
order for the name "attribute". The locals and globals are not searched.



Hope this helps,
 
A

alex23

    v = [0 for i in range(20)]

Absolutely not. Such a code snippet is very common, in fact I've done it
myself, but it is a "hammer solution" -- to a small boy with a hammer,
everything looks like a nail that needs hammering. Writing such a list
comprehension is a "list comp solution".
    v = [0] * 20

Yes, this is the solution.

But the list comp version will work as expected for mutable types,
whereas the 'solution' only works for immutable types.

If anything, I feel like the list comp version is the correct solution
because of its reliability, whereas the multiplication form feels like
either a lucky naive approach or relies on the reader to know the type
of the initialising value and its mutability.
 
J

Jean-Michel Pichavant

Rogério Brito said:
class C:
f = 1
def g(self):
return f

I get an annoying message when I try to call the g method in an object of type
C, telling me that there's no global symbol called f. If I make g return self.f
instead, things work as expected, but the code loses some readability.

Is there any way around this or is that simply "a matter of life"?
class C:
f =1

creates the 'C.f ' name. When 'f' is used in g, you'll get then an error.

class C:
f = 1
def g(self):
return C.f


is the obvious solution. However it can be slightly improved. f is a
class attribute, meaning it's common to all instances of the C class.
Thus g would be a class method, and is here declared liek a instance
method (the instance being self).

class C:
f = 1
@classmethod
def g(cls):
return cls.f

c1 = C()
c2 = C()

print c1.f, c2.f # f is not an attribute of c1 nor c2, thus the lookup
will try in the class and find C.f
1 1

c1.f = 10 # this create the c1 instance attribute f != class attribute f
c2.f = 20 # this create the c2 instance attribute f != class attribute f

print c1.f, c2.f, c1.g(), c2.g(), C.f
10 20 1 1 1

Cheers,

JM
 
B

BartC

My first try to write it in Python was something like this:

v = []
for i in range(20):
v = 0

Unfortunately, this doesn't work, as I get an index out of bounds when
trying to
index the v list.


Python can't grow a list by assigning to out-of-bound elements (although,
being the language it is, there is probably a way of achieving that by
redefining how [] works...)
What is the Pythonic way of writing code like this? So far, I have found
many
v = [0 for i in range(20)]

v = [0] * 20

v = []
for i in range(20): v.append(0)

What should I prefer? Any other alternative?

v=[0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0]

will also work. But none of these appeal too much. I would probably do:

def newlist(length,init=0):
return [init]*length
....
v=newlist(1000)

(with the proviso that someone mentioned when the init value is complex: you
might not get unique copies of each).
If possible, I would like to simply declare the list and fill it latter in
my
program, as lazily as possible (this happens notoriously when one is using
a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling
of the
array).

A sparse array? Even if an array could be constructed by assigning to
arbitrary elements, the gaps created would still need filling in with None
or Unassigned.
2 - If I declare a class with some member variables, is is strictly
necessary

This is where I bail out...
 
N

nn

Hi there.

I am used to some languages like C, but I am just a complete newbie with Python
and, while writing some small snippets, I had encountered some problems, with
which I would sincerely appreciate any help, since I appreciate this language to
write my "running pseudocode in" and I am seriously thinking of using it to
teach some algorithms classes.

1 - The first issue that I am having is that I don't seem to be able to, say,
use something that would be common for people writing programs in C: defining a
one-dimensional vector and only initializing it when needed.

For instance, in C, I would write something like:

int v[20];
for (i = 0; i < 20; i++)
    v = 0;

Note that I only define the vector v (and its size) at the beginning but
initialize it latter during the code per-se.

My first try to write it in Python was something like this:

v = []
for i in range(20):
    v = 0

Unfortunately, this doesn't work, as I get an index out of bounds when trying to
index the v list. Of course, the main difference between the two snippets is
that, in C, I declared v to have 20 positions, while in python I initialized it
to be the empty list and, indeed, it has an empty set of indexes.

What is the Pythonic way of writing code like this? So far, I have found many
alternatives and I would like to write code that others in the Python community
would find natural to read. Some of the things that crossed my mind:

    v = [0 for i in range(20)]

    v = [0] * 20

    v = []
    for i in range(20): v.append(0)

What should I prefer? Any other alternative?

If possible, I would like to simply declare the list and fill it latter in my
program, as lazily as possible (this happens notoriously when one is using a
technique of programming called dynamic programming where initializing all
positions of a table may take too much time in comparison to the filling of the
array).


Just to emphasize what Andreas said:
While
v = [0] * 20
is nice and good,

don't do this
v = [ [] ] * 20

or this
v = [ {} ] * 20

until you have played around with it on the interactive prompt to
understand how it works.

The difference of behavior of mutable vs immutable objects is one of
the main pitfalls for beginners in Python. Everything is very
consistent once you understand the assignment semantics, but it really
confuses people accustomed to other languages that work differently.
 
T

Tim Harig

A sparse array? Even if an array could be constructed by assigning to

I agree, what the OP seems to want (whether he actually needs it or not) is
a sparse array.
A sparse array? Even if an array could be constructed by assigning to
arbitrary elements, the gaps created would still need filling in with None
or Unassigned.

That is only true when attempting to address elements based on their
position rather then something like rank. You could create an object
with some kind of index attribute that you could search for built in.
When you needed to access the element, you simply walked the list until
you find the matching identifier. The spaces no longer need filling since
you are not matching based on absolute position in the list. This is of
course inefficient for large lists, and while there are several methods
of making this method more efficient (indexing, skip linking, b-tree,
etc), you can get what you want very efficiently most of the time by
simply using the built in dictionary with integer keys instead of a list.
 
G

Grant Edwards

If possible, I would like to simply declare the list and fill it
latter in my program, as lazily as possible (this happens notoriously
when one is using a technique of programming called dynamic
programming where initializing all positions of a table may take too
much time in comparison to the filling of the array).

At first you say you want a list, later you say you want an array.
They're two different things. Arrays are variable-length and can be
heterogeneous. If what you really want is a fixed-length, homogeneous
array, then use an array instead of a list:

http://docs.python.org/library/array.html
If I declare a class with some member variables, is is strictly
necessary for me to qualify those members in a method in that class?
Yes.

I get an annoying message when I try to call the g method in an
object of type C, telling me that there's no global symbol called f.
If I make g return self.f instead, things work as expected, but the
code loses some readability.

That's a matter of opinion. Some of us _like_ self.f since it
explicitly shows the reader that f isn't a global or local but a class
or instance variable. Any time you make the reader/maintainer guess
what something is, that's a bug waiting to happen.
Is there any way around this or is that simply "a matter of life"?

Well, that's how Python works. I won't comment on "life".
 
G

Grant Edwards

At first you say you want a list, later you say you want an array.
They're two different things. Arrays are variable-length and can be
heterogeneous.

I meant _Lists_ are fixed-length and homogeneous
If what you really want is a fixed-length, homogeneous array, then
use an array instead of a list:

http://docs.python.org/library/array.html

Actually, that's not the right link either. I was thinking more of
NumPy arrays, where you can create an arbitrary sized homogeneous
array of a desired type (either uninitialized or filled with zeros or
ones):

http://www.scipy.org/Tentative_NumPy_Tutorial#head-d3f8e5fe9b903f3c3b2a5c0dfceb60d71602cf93

If you're crunching so many numbers that initializing a list is
a problem, then you probably ought to be using NumPy.
 
G

Grant Edwards

I meant _Lists_ are fixed-length and homogeneous

Damn. I should give up and go golfing.

_Lists_ are variable-length and can be heterogenous.

_Arrays_ are homogenous and sort-of fixed length.
[...] I was thinking more of NumPy arrays, where you can create an
arbitrary sized homogeneous array of a desired type (either
uninitialized or filled with zeros or ones):

http://www.scipy.org/Tentative_NumPy_Tutorial#head-d3f8e5fe9b903f3c3b2a5c0dfceb60d71602cf93

If you're crunching so many numbers that initializing a list is
a problem, then you probably ought to be using NumPy.
 
A

Andreas Waldenburger

    v = [0 for i in range(20)]

Absolutely not. Such a code snippet is very common, in fact I've
done it myself, but it is a "hammer solution" -- to a small boy
with a hammer, everything looks like a nail that needs hammering.
Writing such a list comprehension is a "list comp solution".
    v = [0] * 20

Yes, this is the solution.

But the list comp version will work as expected for mutable types,
whereas the 'solution' only works for immutable types.

If anything, I feel like the list comp version is the correct solution
because of its reliability, whereas the multiplication form feels like
either a lucky naive approach or relies on the reader to know the type
of the initialising value and its mutability.

The "correct" solution is the one that works the way you want it to
work (that's my definition, anyway). There is nothing "lucky" about
building a list via [value]*count. It repeats (but not so much
duplicates!) "value" "count" times. It is well defined (and, I think,
justified) behavior.

It ceases to be as useful when mutable types are involved, but so what?
Use something else, then.

And I think it is not too much to ask of a reader of Python to know
that integers are immutable. There are enough pitfalls that make this
knowledge rather important to have. (I'm actually not convinced that
this works as an argument, but there you go.)

TL;DR: Don't say "correct", say "appropriate".

/W
 
S

Steven D'Aprano

    v = [0 for i in range(20)]

Absolutely not. Such a code snippet is very common, in fact I've done
it myself, but it is a "hammer solution" -- to a small boy with a
hammer, everything looks like a nail that needs hammering. Writing such
a list comprehension is a "list comp solution".
    v = [0] * 20

Yes, this is the solution.

But the list comp version will work as expected for mutable types,
whereas the 'solution' only works for immutable types.

Yes, that is a good point. Repeating the same mutable object may give
surprising results.

If anything, I feel like the list comp version is the correct solution
because of its reliability, whereas the multiplication form feels like
either a lucky naive approach or relies on the reader to know the type
of the initialising value and its mutability.

And how often do you have an list that you are creating where you don't
know what items you have to initialise the list with?

There are three common use-cases for the idiom the OP was describing:
initialising a list with zeroes (or sometimes some other numeric value),
initialising it with None, or creating a list-of-lists (or more rarely, a
list-of-dicts). The first one is *far* more common than the next two.

You are right to point out that the third case is a Python gotcha: [[]]*n
doesn't behave as expected by the naive or inexperienced Python
programmer. I should have mentioned it, and pointed out that in that case
you do want a list comp [[] for i in range(n)].

But that doesn't mean that the list comp is the general purpose solution.
Consider the obvious use of the idiom:

def func(arg, count):
# Initialise the list.
L = [arg for i in range(count)]
# Do something with it.
process(L, some_function)

def process(L, f):
# Do something with each element.
for item in enumerate(L):
f(item)


Looks good, right? But it isn't, because it will suffer the exact same
surprising behaviour if f modifies the items in place. Using a list comp
doesn't save you if you don't know what the object is.
 
H

Hrvoje Niksic

alex23 said:
If anything, I feel like the list comp version is the correct solution
because of its reliability, whereas the multiplication form feels like
either a lucky naive approach or relies on the reader to know the type
of the initialising value and its mutability.

Other than list comp being slower, I'd like to point out that in some
cases the multiplication is far from being naive. Consider this
pattern:

def in_groups_of(n, iterable):
"""Yield items of iterable packed in tuples of size n."""
return itertools.izip(*[iter(iterable)] * n)
.... print a, b, c
....
0 1 2
3 4 5
6 7 8

In the call to itertools.izip we are actually counting on list
repetition to refer to the same object. Rewriting it as the list
comprehension would break it:

def in_groups_of(n, iterable):
return itertools.izip(*[iter(iterable) for _ in xrange(n)])
.... print a, b, c
....
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
 

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

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,997
Latest member
mileyka

Latest Threads

Top