Python Newbie

Ian Kelly ian.g.kelly at gmail.com
Fri Feb 22 23:45:35 CET 2013


On Fri, Feb 22, 2013 at 2:37 PM,  <piterrr.dolinski at gmail.com> wrote:
> There seems to be a "heated" argument about Python's apparently intentional ambiguity in conditional statements. Specifically, the issue is, is it more appropriate to write (as an example)
>
> if (some statement):            # short form
>
> rather than
>
> if (some statement == true):    # long form

Nobody would advocate that particular comparison.  If the result of
"some statement" is already a boolean value, then just use that
expression in your if statement.  Checking "if True == True:" is a
pointlessly verbose comparison when you can just check "if True:".

The tension here is not between "short form" and "long form" if
statements, but between using conditional expressions that evaluate to
booleans versus using conditional expressions that are implicitly
interpreted as booleans.  Some people prefer only the former.  Others
see value in the latter for some (not all!) conditions.

The usual advice given for implicit interpretation is that it is a
test for "something" versus "nothing".  If I do "if x:" and it
evaluates as true, then I know there is something in x.  Otherwise, I
have nothing: None, or zero, or an empty sequence, etc.  Generally the
context will give you more information about what types are expected.
Personally, I find that this tends to be most useful as a test for
whether a sequence contains elements.

> Some 50(?) years ago, C was designed so that everything other than 0 evaluated to true and was false otherwise. Fast forward to recent memory, when C# was designed, Microsoft claims they reviewed all the features of C, C++ and Java, pulled the best features from each of these languages and designed a new language that would help minimize the potential for planting bugs. Say what you want about MS inventions, but my experience is that to require the long form notation was a good decision. For me the fact that the short notation is legal in Python is a stepback in language design. Python inventors, when creating what is after all considered a contemporary language, should have known better. Call me psychopath if you will (have seen this in one post), but I shall continue to use the aforementioned long form as I always have, and no Python is going to change that.

At least one part of the reason that Python does not specifically
require booleans in conditions is that the language did not originally
have a boolean type; 1 and 0 were generally used instead.  The bool
type was not added until version 2.3, and requiring booleans in
conditions at that point would have broken a large amount of code.

> Today I learned the hard way that all function parameters in Python are passed by reference (meaning whatever happens to them inside a function, new values are always passed to caller).

Not quite.  Python uses pass-by-object (also known as
"pass-by-sharing") semantics.  The argument seen by the function is
the same object that was passed to it.  The name bound to the object
inside the function is unrelated to the name bound to the object in
the caller's context, so that if you assign something else to the
name, it will not affect the object or its binding to the external
name.  Since it's the same object, though, you can mutate the object
and then later observe those changes in the external context.

Note that this is only relevant for mutable data types.  For immutable
types such as strings and ints, you cannot alter the passed-in object,
so it is semantically equivalent to pass-by-value without the overhead
of actually copying anything.

> Not good. I got caught up on this. To combat the mostly unwanted behavior, inside a function I have to reassign variables intended to be local to new variables.

Reassigning the objects to new variables would make no difference, as
you would still be dealing with the same objects.  You would have to
actually copy the objects in order that changes to them would only be
local to the function.  You would then be free to assign the copied
objects back to the original variable name, and then you would no
longer have any reference to the original objects within the function.

In other words, this will protect a list passed in from being mutated:

def foo(my_list):
    my_list = list(my_list)
    ...

This will not:

def foo(my_list):
    another_name_for_my_list = my_list
    ...

> A pain. Can anyone offer ONE reason why Python was designed that way?

How about because the overhead of copying every object passed into
every function would be inefficient?

What Python does here is not all that different from how .NET
reference types are passed by default.  The call semantics of these
two examples are basically the same:

# Python:
def foo(index, my_list):
    my_list[index] = 42

/* C Sharp */
void foo(int index, int[] my_list)
{
    my_list[index] = 42;
}


In both cases, reassigning index would have no effect outside the
function.  In C#, it's because the argument is passed by value; in
Python, it's because the assignment merely binds a different object to
the name.  In both cases, reassigning my_list would have no effect
outside the function, for the same reasons.

In both cases, modifying index without reassigning it would still have
no effect outside the function.  In C#, this is because int is a value
type; in Python, it's because ints are immutable in the first place.

Finally, in both cases, modifying the contents of my_list *does* have
a visible effect outside the function.  In C#, it's because arrays are
a reference type; in Python, it's because the list object is shared by
the caller and callee.

So with that in mind, I have a hard time understanding why you might
be finding this strange and unexpected.

> Out of curiosity, does anyone have any idea why function declarations are preceded by the keyword "def" rather than something more intuitive like "function" or at least "func", perhaps?

Because that's what Guido picked when he started writing the language
in 1989, and it's too late to change it.

> Does anyone know what the benefit of writing the cryptic "elif" to mean "else if" is? Curiously, the default statement in an if/else chain is preceded by "else" and not "el".

Lots of languages use "elif" or "elsif" or "elseif" or some variation
thereof.  Why does it matter?



More information about the Python-list mailing list