Credit: Hamish Lawson
In Python, all variables are expected
to be defined before use. The None
object is a
value you often assign to signify that you have no real value for a
variable, as in:
try: x except NameError: x = None
Then it’s easy to test whether a variable is bound
to None
:
if x is None: some_fallback_operation( ) else: some_operation(x)
Python doesn’t have a specific function to test
whether a variable is defined, since all variables are expected to
have been defined before use, even if initially assigned the
None
object. Attempting to access a variable that
hasn’t previously been defined raises a
NameError
exception (which you can handle with
a try
/except
statement, as you
can for any other Python exception).
It is considered unusual in Python not to know whether a variable has
already been defined. But if you are nevertheless in this situation,
you can make sure that a given variable is in fact defined (as
None
, if nothing else) by attempting to access it
inside a try
clause and assigning it the
None
object if the access raises a
NameError
exception. Note that
None
is really nothing magical, just a built-in
object used by convention (and returned by functions that exit
without returning anything specific). You can use any other value
suitable for your purposes to initialize undefined variables; for a
powerful and interesting example, see Recipe 5.24.
Instead of ensuring that a variable is initialized, you may prefer to test whether it’s defined where you want to use it:
try: x except NameError: some_fallback_operation( ) else: some_operation(x)
This is a perfectly acceptable alternative to the code in the recipe,
and some would say it’s more Pythonic. Note,
however, that if you choose this alternative, you have to code things
in this order: the anomalous, error case first, then the normal,
no-error case. With the recipe’s approach, you may
want to invert the guard condition to if x is not None
and code the normal case first. These points are
minutiae, to be sure, but sometimes clarity can be improved this way.
Furthermore, you must be careful to avoid the variation in this
alternative:
try: x some_operation(x) except NameError: some_fallback_operation( )
In this variation, the call to some_operation
is
also covered by the exception handler, so if there is a bug in the
some_operation
function, or in any function called
from it, this code would mask the bug and apparently proceed to
operate normally when it should fail with an error message. You
should always be careful that your try
clauses (in
try
/except
statements) do not
accidentally cover more code than you actually intend to cover, which
might easily mask bugs. The else
clause in the
try
/except
statement is for
code that should execute only if no exception was raised but should
not itself be covered by the exception handler, because you do not
expect exceptions from it and want to diagnose the problem
immediately if exceptions do occur.
Many situations that you might think would naturally give rise to
undefined variables, such as processing configuration files or web
forms, are handled better by employing a dictionary and testing for
the presence of a key (with the has_key
method, a
try
/except
, or the
get
or setdefault
methods of
dictionary objects). For example, instead of dealing with a user
configuration file this way:
execfile('userconfig') try: background_color except NameError: background_color = 'black' try: foreground_color except NameError: foreground_color = 'white' ...
do it this way:
config = dict(globals( )) execfile('userconfig', config) background_color = config.get('background_color', 'black') foreground_color = config.get('foreground_color', 'white') ...
dict
requires Python 2.2, but you can get a
similar effect in earlier versions of Python by using config = globals().copy( )
instead.
Using an explicitly specified
dictionary for exec
, eval
, and
execfile
is advisable anyway, to keep your
namespace under control. One of the many benefits of using such an
explicitly specified dictionary is, as shown here, that you
don’t need to worry about undefined variables but
can simply use the dictionary’s
get
method to fetch each key with an explicitly
specified default value to be used if the key is not present in the
dictionary.
If you know for sure which namespace the variable is in (i.e.,
specifically locals
or specifically
globals
), you can also use methods such as
has_key
or get
on the relevant
dictionary. However, variables that are in neither
locals
nor globals
may exist
(thanks to the nested scopes feature that is optional in Python 2.1,
but is always on in Python 2.2 and later). Also, the special
namespace directories returned by locals
and
globals
are not suitable for mutating methods such
as setdefault
, so you’re still
better off arranging to use your own explicit dictionary rather than
the local or global namespaces, whenever that’s
feasible.
Get Python Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.