summaryrefslogtreecommitdiffstats
path: root/Doc/howto/doanddont.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Doc/howto/doanddont.tex')
-rw-r--r--Doc/howto/doanddont.tex332
1 files changed, 0 insertions, 332 deletions
diff --git a/Doc/howto/doanddont.tex b/Doc/howto/doanddont.tex
deleted file mode 100644
index b54f069..0000000
--- a/Doc/howto/doanddont.tex
+++ /dev/null
@@ -1,332 +0,0 @@
-\documentclass{howto}
-
-\title{Idioms and Anti-Idioms in Python}
-
-\release{0.00}
-
-\author{Moshe Zadka}
-\authoraddress{howto@zadka.site.co.il}
-
-\begin{document}
-\maketitle
-
-This document is placed in the public doman.
-
-\begin{abstract}
-\noindent
-This document can be considered a companion to the tutorial. It
-shows how to use Python, and even more importantly, how {\em not}
-to use Python.
-\end{abstract}
-
-\tableofcontents
-
-\section{Language Constructs You Should Not Use}
-
-While Python has relatively few gotchas compared to other languages, it
-still has some constructs which are only useful in corner cases, or are
-plain dangerous.
-
-\subsection{from module import *}
-
-\subsubsection{Inside Function Definitions}
-
-\code{from module import *} is {\em invalid} inside function definitions.
-While many versions of Python do not check for the invalidity, it does not
-make it more valid, no more then having a smart lawyer makes a man innocent.
-Do not use it like that ever. Even in versions where it was accepted, it made
-the function execution slower, because the compiler could not be certain
-which names are local and which are global. In Python 2.1 this construct
-causes warnings, and sometimes even errors.
-
-\subsubsection{At Module Level}
-
-While it is valid to use \code{from module import *} at module level it
-is usually a bad idea. For one, this loses an important property Python
-otherwise has --- you can know where each toplevel name is defined by
-a simple "search" function in your favourite editor. You also open yourself
-to trouble in the future, if some module grows additional functions or
-classes.
-
-One of the most awful question asked on the newsgroup is why this code:
-
-\begin{verbatim}
-f = open("www")
-f.read()
-\end{verbatim}
-
-does not work. Of course, it works just fine (assuming you have a file
-called "www".) But it does not work if somewhere in the module, the
-statement \code{from os import *} is present. The \module{os} module
-has a function called \function{open()} which returns an integer. While
-it is very useful, shadowing builtins is one of its least useful properties.
-
-Remember, you can never know for sure what names a module exports, so either
-take what you need --- \code{from module import name1, name2}, or keep them in
-the module and access on a per-need basis ---
-\code{import module;print module.name}.
-
-\subsubsection{When It Is Just Fine}
-
-There are situations in which \code{from module import *} is just fine:
-
-\begin{itemize}
-
-\item The interactive prompt. For example, \code{from math import *} makes
- Python an amazing scientific calculator.
-
-\item When extending a module in C with a module in Python.
-
-\item When the module advertises itself as \code{from import *} safe.
-
-\end{itemize}
-
-\subsection{Unadorned \function{exec} and friends}
-
-The word ``unadorned'' refers to the use without an explicit dictionary,
-in which case those constructs evaluate code in the {\em current} environment.
-This is dangerous for the same reasons \code{from import *} is dangerous ---
-it might step over variables you are counting on and mess up things for
-the rest of your code. Simply do not do that.
-
-Bad examples:
-
-\begin{verbatim}
->>> for name in sys.argv[1:]:
->>> exec("%s=1" % name)
->>> def func(s, **kw):
->>> for var, val in kw.items():
->>> exec("s.%s=val" % var) # invalid!
->>> exec(open("handler.py").read())
->>> handle()
-\end{verbatim}
-
-Good examples:
-
-\begin{verbatim}
->>> d = {}
->>> for name in sys.argv[1:]:
->>> d[name] = 1
->>> def func(s, **kw):
->>> for var, val in kw.items():
->>> setattr(s, var, val)
->>> d={}
->>> exec(open("handler.py").read(), d, d)
->>> handle = d['handle']
->>> handle()
-\end{verbatim}
-
-\subsection{from module import name1, name2}
-
-This is a ``don't'' which is much weaker then the previous ``don't''s
-but is still something you should not do if you don't have good reasons
-to do that. The reason it is usually bad idea is because you suddenly
-have an object which lives in two seperate namespaces. When the binding
-in one namespace changes, the binding in the other will not, so there
-will be a discrepancy between them. This happens when, for example,
-one module is reloaded, or changes the definition of a function at runtime.
-
-Bad example:
-
-\begin{verbatim}
-# foo.py
-a = 1
-
-# bar.py
-from foo import a
-if something():
- a = 2 # danger: foo.a != a
-\end{verbatim}
-
-Good example:
-
-\begin{verbatim}
-# foo.py
-a = 1
-
-# bar.py
-import foo
-if something():
- foo.a = 2
-\end{verbatim}
-
-\subsection{except:}
-
-Python has the \code{except:} clause, which catches all exceptions.
-Since {\em every} error in Python raises an exception, this makes many
-programming errors look like runtime problems, and hinders
-the debugging process.
-
-The following code shows a great example:
-
-\begin{verbatim}
-try:
- foo = opne("file") # misspelled "open"
-except:
- sys.exit("could not open file!")
-\end{verbatim}
-
-The second line triggers a \exception{NameError} which is caught by the
-except clause. The program will exit, and you will have no idea that
-this has nothing to do with the readability of \code{"file"}.
-
-The example above is better written
-
-\begin{verbatim}
-try:
- foo = opne("file") # will be changed to "open" as soon as we run it
-except IOError:
- sys.exit("could not open file")
-\end{verbatim}
-
-There are some situations in which the \code{except:} clause is useful:
-for example, in a framework when running callbacks, it is good not to
-let any callback disturb the framework.
-
-\section{Exceptions}
-
-Exceptions are a useful feature of Python. You should learn to raise
-them whenever something unexpected occurs, and catch them only where
-you can do something about them.
-
-The following is a very popular anti-idiom
-
-\begin{verbatim}
-def get_status(file):
- if not os.path.exists(file):
- print "file not found"
- sys.exit(1)
- return open(file).readline()
-\end{verbatim}
-
-Consider the case the file gets deleted between the time the call to
-\function{os.path.exists} is made and the time \function{open} is called.
-That means the last line will throw an \exception{IOError}. The same would
-happen if \var{file} exists but has no read permission. Since testing this
-on a normal machine on existing and non-existing files make it seem bugless,
-that means in testing the results will seem fine, and the code will get
-shipped. Then an unhandled \exception{IOError} escapes to the user, who
-has to watch the ugly traceback.
-
-Here is a better way to do it.
-
-\begin{verbatim}
-def get_status(file):
- try:
- return open(file).readline()
- except (IOError, OSError):
- print "file not found"
- sys.exit(1)
-\end{verbatim}
-
-In this version, *either* the file gets opened and the line is read
-(so it works even on flaky NFS or SMB connections), or the message
-is printed and the application aborted.
-
-Still, \function{get_status} makes too many assumptions --- that it
-will only be used in a short running script, and not, say, in a long
-running server. Sure, the caller could do something like
-
-\begin{verbatim}
-try:
- status = get_status(log)
-except SystemExit:
- status = None
-\end{verbatim}
-
-So, try to make as few \code{except} clauses in your code --- those will
-usually be a catch-all in the \function{main}, or inside calls which
-should always succeed.
-
-So, the best version is probably
-
-\begin{verbatim}
-def get_status(file):
- return open(file).readline()
-\end{verbatim}
-
-The caller can deal with the exception if it wants (for example, if it
-tries several files in a loop), or just let the exception filter upwards
-to {\em its} caller.
-
-The last version is not very good either --- due to implementation details,
-the file would not be closed when an exception is raised until the handler
-finishes, and perhaps not at all in non-C implementations (e.g., Jython).
-
-\begin{verbatim}
-def get_status(file):
- fp = open(file)
- try:
- return fp.readline()
- finally:
- fp.close()
-\end{verbatim}
-
-\section{Using the Batteries}
-
-Every so often, people seem to be writing stuff in the Python library
-again, usually poorly. While the occasional module has a poor interface,
-it is usually much better to use the rich standard library and data
-types that come with Python then inventing your own.
-
-A useful module very few people know about is \module{os.path}. It
-always has the correct path arithmetic for your operating system, and
-will usually be much better then whatever you come up with yourself.
-
-Compare:
-
-\begin{verbatim}
-# ugh!
-return dir+"/"+file
-# better
-return os.path.join(dir, file)
-\end{verbatim}
-
-More useful functions in \module{os.path}: \function{basename},
-\function{dirname} and \function{splitext}.
-
-There are also many useful builtin functions people seem not to be
-aware of for some reason: \function{min()} and \function{max()} can
-find the minimum/maximum of any sequence with comparable semantics,
-for example, yet many people write their own
-\function{max()}/\function{min()}.
-
-On the same note, note that \function{float()}, \function{int()} and
-\function{long()} all accept arguments of type string, and so are
-suited to parsing --- assuming you are ready to deal with the
-\exception{ValueError} they raise.
-
-\section{Using Backslash to Continue Statements}
-
-Since Python treats a newline as a statement terminator,
-and since statements are often more then is comfortable to put
-in one line, many people do:
-
-\begin{verbatim}
-if foo.bar()['first'][0] == baz.quux(1, 2)[5:9] and \
- calculate_number(10, 20) != forbulate(500, 360):
- pass
-\end{verbatim}
-
-You should realize that this is dangerous: a stray space after the
-\code{\\} would make this line wrong, and stray spaces are notoriously
-hard to see in editors. In this case, at least it would be a syntax
-error, but if the code was:
-
-\begin{verbatim}
-value = foo.bar()['first'][0]*baz.quux(1, 2)[5:9] \
- + calculate_number(10, 20)*forbulate(500, 360)
-\end{verbatim}
-
-then it would just be subtly wrong.
-
-It is usually much better to use the implicit continuation inside parenthesis:
-
-This version is bulletproof:
-
-\begin{verbatim}
-value = (foo.bar()['first'][0]*baz.quux(1, 2)[5:9]
- + calculate_number(10, 20)*forbulate(500, 360))
-\end{verbatim}
-
-\end{document}