Good code patterns in Python

  • Thread starter Will Stuyvesant
  • Start date
W

Will Stuyvesant

If you know that your source code is going to be used
later by others, then I feel that code with the pattern:

if some_condition:
some_name = some_value
else:
some_name = other_value

is often a mistake. Much better, safer, would be:

some_name = some_value
if not some_condition:
some_name = other_value

Why?

Because those people reusing your code might decide to
change or adapt the "if" part of the first example. Or
the "else" part for that matter. And then they could end
up with "some_name" being undefined, crashing other code
maybe 1000's of lines away. This could happen for example
because they use exceptions in the "if" part that jump out
of it, etc.

There is the small overhead of assigning something twice
to some_name in the safer example, so if performance is
*that* important then the first example is better, but I
feel there should be comments with warnings around it:
**CREATING A NEW OBJECT REFERENCE HERE!** Hmm, now that
makes code ugly :)

What are your thoughts about this? I am interested in
current large scale software development practice, and
guidelines that are used there, especially for dynamically
typed languages like Python.

There must be a lot of advisable code design patterns (I
can't find a good name in English) like this for use in
software development with many programmers. Perhaps a
collection with good documentation would be interesting?
Or a tool like pychecker that flags "bad" patterns?
 
T

Terry Reedy

Will Stuyvesant said:
If you know that your source code is going to be used
later by others, then I feel that code with the pattern:

if some_condition:
some_name = some_value
else:
some_name = other_value

is often a mistake. Much better, safer, would be:

some_name = some_value
if not some_condition:
some_name = other_value

If, bool(some_value) == True, I personally would use the near-ternary
idiom

some_name = some_condition and some_value or other_value

(or equivalent form for bool(other_value)== True or either == False).

This is both safe and efficient, avoiding both
Because those people reusing your code might decide to
change or adapt the "if" part of the first example. Or
the "else" part for that matter. And then they could end
up with "some_name" being undefined, crashing other code
maybe 1000's of lines away.
and

There is the small overhead of assigning something twice

(I acknowledge that some think this ugly and worse and would not be
caught dead writing such an 'abomination', so flame repetition is not
necessary ;-)

Terry J. Reedy
 
J

Jiri Barton

One, there has been a proposal for a ternary operator on python.org. You
know that kind of (cond) ? (eval1) : (eval2) stuff.

Two, no need to guard that code. Passing and assigning a paramater should
always make you THINK about what's happening.

Three, how about
a = 1
b = 0
......
if b == 0:
a = 0
else:
a = a/b
? You cannot replace it with your pattern. Sure enough, there are far more
examples of this -- when you cannot evaluate the first expression.

Jiri Barton
 
S

Steven Taschuk

Quoth Will Stuyvesant:
If you know that your source code is going to be used
later by others, then I feel that code with the pattern:

if some_condition:
some_name = some_value
else:
some_name = other_value

is often a mistake. Much better, safer, would be:

some_name = some_value
if not some_condition:
some_name = other_value

I join the Ms in disagreeing strongly. The visual parallelism of
the first reflects the conceptual parallelism of the two cases,
while the second obscures it.
Because those people reusing your code might decide to
change or adapt the "if" part of the first example. Or
the "else" part for that matter. And then they could end
up with "some_name" being undefined, crashing other code
maybe 1000's of lines away. This could happen for example
because they use exceptions in the "if" part that jump out
of it, etc.

I assume you're not speaking of local variables here -- a function
thousands of lines long would be unconscionable.

Presumably you're speaking of attributes, and the danger is that
an exception in one branch would cause the object's invariants be
broken. But I don't see how this would happen in practice, in a
way which would (a) leave the attribute undefined and (b) imply to
the caller that everything was fine. Do you have an example?

(Much more serious and more common is the danger that after an
exception is raised, the function has done half its work and left
the object in a broken state. But this has nothing to do with
what you're talking about.)
There is the small overhead of assigning something twice

Too minor to worry about:

$ timeit -s'def foo(): global a; a = 1' 'foo()'
100000 loops, best of 3: 5.51 usec per loop
$ timeit -s'def foo(): global a; a = 1; a = 1' 'foo()'
100000 loops, best of 3: 6.1 usec per loop

If I'm running the code a million times, and everything else in
the loop takes less than a microsecond, this might be worth
thinking about.
 
L

Lulu of the Lotus-Eaters

|[email protected] (Will Stuyvesant) wrote:
|> if some_condition:
|> some_name = some_value
|> else:
|> some_name = other_value
|> is often a mistake. Much better, safer, would be:
|> some_name = some_value
|> if not some_condition:
|> some_name = other_value

(e-mail address removed) (Michele Simionato) wrote previously:
|I am sorry, but I feel that the first form is MUCH more readable than the
|second one; the first form is crystal clear to me, whereas I must read
|the second form two or three times to understand what it is going on.

Moreover, actual code often assigns from computations, not simply one
name to another. The harder-to-read form risks bad side effects (or
simply a performance hit):

some_name = some_computation()
if not some_condition:
some_name = other_computation()

The straightforward if/else form avoids superfluous computations.

Yours, Lulu...
 
D

Dennis Lee Bieber

Will Stuyvesant fed this fish to the penguins on Tuesday 01 July 2003
02:49 am:
some_name = some_value
if not some_condition:
some_name = other_value
Ugh... Shades of old BASIC...

10 sn = sv
20 if sc then 40
30 sn = ov
40 ...

--
 
K

Kirk Job-Sluder

Will Stuyvesant said:
If you know that your source code is going to be used
later by others, then I feel that code with the pattern:

if some_condition:
some_name = some_value
else:
some_name = other_value

is often a mistake. Much better, safer, would be:

some_name = some_value
if not some_condition:
some_name = other_value

Why?

My personal opinion is that it depends on context. The first idiom
is more clear when you are dealing with some kind of a switch. The
second idiom works better if you have a default value that needs to be
overridden in some cases.
Because those people reusing your code might decide to
change or adapt the "if" part of the first example. Or
the "else" part for that matter. And then they could end
up with "some_name" being undefined, crashing other code
maybe 1000's of lines away. This could happen for example
because they use exceptions in the "if" part that jump out
of it, etc.

Of course, another alternative is to combine both approaches by setting
a default value:

#set default for some_value
some_value = []
if condition1:
some_value = function1()
else:
some_value = function2()

And then if you really want to be safe the functions using
some_value should do reality checks as well.
def function3(some_value=[]):
if len(some_value):
do something
else:
do something else.

I think that an argument for the readability of if-else is that because
the logic is made more clear, it can be more effectively replaced.

There is the small overhead of assigning something twice
to some_name in the safer example, so if performance is
*that* important then the first example is better, but I
feel there should be comments with warnings around it:
**CREATING A NEW OBJECT REFERENCE HERE!** Hmm, now that
makes code ugly :)

The problem here is that ***creating a new object reference*** is not
only ugly, but its ambiguous as well. (What kind of object, what is it
used for?) If indeed some_name is an important variable in your program,
then provide a full description.

#some_value (string) is used to hold the widgit that will
#be passed to a wadget and eventually passed
#to standard output.
 
E

Erik Max Francis

Kirk said:
My personal opinion is that it depends on context. The first idiom
is more clear when you are dealing with some kind of a switch. The
second idiom works better if you have a default value that needs to be
overridden in some cases.

I presume the "mistake" he's referring to with the first snippet is the
potential problem that could happen if the variable is named
incorrectly:

if condition:
variable = someValue
else:
varaible = otherValue # [sic] note the typo!

When you really want an atomic assignment of one singular variable. The
complete solution to this would probably be a conditional expression,
e.g.:

variable = (if condition: someValue else: otherValue)

eliminating the duplication which can lead to errors. (Python, of
course, doesn't have such a construct, and the silence after the
conditional expression PEP vote and the long silence thereafter suggests
that it never will.)

I still don't think this significant of a risk to warrant widespread
conversion of statements to the form Will suggests, especially when you
have things like PyChecker that can check for (probable) typos. It's a
slightly unfortunate wart in dynamic languages without conditional
operators, but I don't think it rises to the level of something that
should be corrected via such (what seems to me) a heavy-handed style.
 
B

Bernhard Herzog

Erik Max Francis said:
The
complete solution to this would probably be a conditional expression,
e.g.:

variable = (if condition: someValue else: otherValue)

eliminating the duplication which can lead to errors. (Python, of
course, doesn't have such a construct, and the silence after the
conditional expression PEP vote and the long silence thereafter suggests
that it never will.)

Guido broke his silence at EuroPython: The ternary operator will not be
added to Python.

Bernhard
 
B

Ben Finney

Actually Guido made it pretty clear that he will be very careful about
adding language features especially at the syntax level.

Thank goodness the Boolean type made it in, then. (Not a syntax-level
change, but still a pretty fundamental one.)
 

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

Similar Threads

Good code patterns in Python 2
Exception Handling Practices / Patterns 7
Pointers in python? 1
I Need Fix In Code 1
AttributeError in pygame code 4
Code efficiency 3
Help in identifying code 2
Code help please 4

Members online

No members online now.

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top