Many newbie questions regarding python

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Thu Oct 7 20:27:21 EDT 2010


On Thu, 07 Oct 2010 20:10:14 -0300, Rogério Brito wrote:


> 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,



-- 
Steven



More information about the Python-list mailing list