You are on page 1of 5

• Instances or Objects.

The attribute is a data field used to store the state of the


object, or a method defined for the object
• Instances of Built-in types (such as List or Dictionary). Again the attribute can be
a data field or, more commonly, a function (method) defined as part of the type
• Modules. The attribute is a data value or function defined in the module.

Qualified names serve much the same purpose as name scopes. By insisting that names
be qualified by a base, they limit the poliferation of names in the broader scope.
Similarly, the same name can be used in more than one qualified fashion, and will refer to
the attribute appropriate to the base.

Much of the mechanism associated with name scopes is built using simple dictionaries.
For example, the current local name scope can always be found using the function
locals(), and the current global scope using the function globals(). Classes store their
name space in a field named __dict__, as do modules. All of these values can be
examined by the programmer, although modifications to these values should only be
performed with great care.

class A(object):
x = 1
def foo(self):
return 'foo'
def bar(self):
return X

>>> print A.__dict__


{'__module__': '__main__', 'bar': <function bar at 0x4b470>,
'__dict__': <attribute '__dict__' of 'A' objects>, 'x': 1, 'foo':
<function foo at 0x4b3f0>, '__weakref__': <attribute '__weakref__' of
'A' objects>, '__doc__': None}

Modules

We have been using modules since chapter 3, and yet we have not explained what a
module is or showed how to create your own modules. Now, with the benefit of an
understanding of name spaces, we can do both.

The construction of a module is very simple. A module is simply a Python file, exactly
the same as the program files you have been building since Chapter 2. What is different is
the handling of the names in the module. This occurs during the execution of the import
statement.

The import statement scans a file and executes each statement in the program, in exactly
the same fashion as occurs when the file is given as argument to the Python interpreter.
The only difference is that rather than using the standard local dictionary, the names of all
values defined within the module are stored in their own dictionary. This dictionary is
then held by a value of type module. Referencing a qualified name, modName.x, is in
fact shorthand for the dictionary reference modName.__dict__[‘x’].

Exploring Python – Chapter 10: Name spaces and Modules 6

https://E-next.in
You can see this if you examine the type associated with a module name after executing
the import statement:

>>> import string


>>> print type(string)
<type 'module'>
>>> print string.__dict__['split']
<function split at 0x6b270>

It is now easy to explain the meaning of the from statement in terms of name spaces.
When a from statement is encountered the effect is to first import the specified module,
constructing the module dictionary. The given attribute from this dictionary is then
copied into the local dictionary. Thereafter, the attribute can be used without
qualification, exactly as if it had been defined in the local space.

from modName import attribute

The difference between a simple import and a from import can have an important effect
on execution time. Suppose you are using only the function bar from module foo. One
approach would be to import the module:

import foo

You could then use the function bar by means of the qualified name, foo.bar(). However,
each time you use this expression there are two run-time lookups performed. The first is
to find the meaning for the variable foo in the current name space. Next, a run-time
lookup is performed to find the data field named bar is the dictionary associated with the
value foo. If, on the other hand, you import just a single function:

from foo import bar

Then the function bar is placed in the local name space. The function can then be invoked
without qualification, as bar(). Discovering the meaning of this name only requires one
search, since the name is found in the local name space.

Most of the time the difference in execution is not noticeable. However, if imported
functions are used within a loop and executed many times the difference in execution can
be significant.

Avoiding Namespace Collisions when Importing Modules


It is possible to use a wildcard character (the * character) to import everything from a
module into the current name space. However, this should be done with care because any
name in the current environment that matches a name in the imported namespace will be
overridden. For example, suppose you have sometime stored in a variable named e and
then import everything from the math module:

>>> e = 42

Exploring Python – Chapter 10: Name spaces and Modules 7

https://E-next.in
>>> from math import *
>>> print e
2.71828182846

The math module defines the value e. (It is the base of the natural logarithms). This
definition has now replaced the earlier value associated with the name.

One way to avoid namespace collisions when performing an import is to use the optional
as clause on the from import statement. This clause allows the programmer to import a
value, but give it a new name in the local space.

>>> e = 42
>>> from math import e as eConst
>>> print e
42
>>> print eConst
2.71828182846

Creating your own Module

Creating your own module is surprisingly easy. A module is exactly like a Python
program, simply a list of Python statements in a file. The only difference is that the
module is loaded using an import statement, rather than by being given directly to the
Python interpreter.

Normally files that are used as modules contain only class and function definitions.
However, this is just convention, and nothing in the language prevents the user from
placing other types of statements in the module. All the statements will be executed when
the module is loaded by the import statement.

The following illustrates a typical module. Here the module simply defines three
functions for common data structures (a stack, a queue, and a set).

#
# Module for simple collection classes
#

class Stack(object):
def __init__ (self):
self.storage = [ ]

def push (self, newValue):


self.storage.append(newValue)

def top (self):


return self.storage[len(self.storage) - 1]

def pop (self):


result = self.top()
self.storage.pop()
return result

Exploring Python – Chapter 10: Name spaces and Modules 8

https://E-next.in
def isEmpty (self):
return len(self.storage) == 0

class Queue(object):
def __init__ (self):
self.storage = [ ]

def add (self, newValue):


self.push = self.storage.append(newValue)

def front (self):


return self.storage[0]

def removeFront (self):


result = front()
del self.storage[0]
return result

def isEmpty (self):


return len(self.storage) == 0

class Set(object):
def __init__ (self):
self.storage = [ ]

def add (self, newValue):


if not newValue in self.storage:
self.storage.append(newValue)

def contains (self, testValue):


return testValue in self.storage

def remove (self, testValue):


i = self.storage.find(testValue)
if i:
del(self.storage[i])

Testing the Namespace within a Module

Frequently a program can be used either as a stand-alone application or as a module for a


larger system. For example, the calculator program we developed in Chapter 9 works as
an application using a textual interface. However, we can also reuse the code for this
application in another system that uses a GUI interface, as we will see in Chapter x.

When this occurs there are usually statements that you do not want to execute when the
program is loaded as a module. Fortunately, the name of the current module is held in an
internal variable called __name__. The top-level program executed by the Python
interpreter is given the name __main__. Testing this value provides a means to
conditionally execute statements. In our Calculator program from Chapter 9, for
example, we could replace the final statements with the following:

# only execute if we are being run as top level program


if __name__ == "__main__":

Exploring Python – Chapter 10: Name spaces and Modules 9

https://E-next.in
calc = Calculator()
calc.run()

Now the commands that begin the application will only be executed when the program is
selected as the top-level command from the Python interpreter, not when the file is
loaded as a module.

An Emphasis on Reuse

The biggest feature that distinguishes modern software development from earlier
approaches in an increased emphasis on software reuse. Rather than expecting that every
program will be written entire new from the first line to the last, applications are now
almost always constructed from reusable software libraries. These libraries can be as
simple as our data structure module described earlier, or much more complicated systems
for performing network connections or parsing XML files.

One of the features that distinguishes Python is that it provides an extremely rich set of
existing modules that can be reused in any new application. We have seen a number of
these already. A few more will be used in the case studies in the second part of this book.
Many more are documented on the Python website, at www.python.org.

Equally important, Python makes it easy, almost trivial, to create your own modules. A
module is nothing more than a Python program stripped of the main driving statements.

As you advance in your Python programming you will learn about many more useful
modules. You should also strive to acquire a mindset that recognizes and values reusable
code in your own programs. When you find a set of classes or functions that you think are
general enough to be used for two or more different applications, package them as a
module and use the same code in each of the new programs. Doing so will make you
more productive, and make your programs more reliable and error-free.

Exercises
1. Consider the following program fragment. Imagine execution has reached the
print statement. Assign a letter from LEGB to each of the following identifiers
according to whether the name is Local, from an Enclosing Scope, Global or
Built-in.

2. Try creating a simple function, such as the following, and print out the values in
the locals dictionary. What values do you see? Are you surprised at any of the
entries in this dictionary? What values are stored in the dictionary returned by the
function globals() at the point where the locals dictionary is being displayed?

Exploring Python – Chapter 10: Name spaces and Modules 10

https://E-next.in

You might also like