Modules#

Having now introduced the idea that objects can have attributes and associated methods, as we saw with date and datetime type objects, let’s briefly discuss modules, which provide users access to functions and objects for carrying out particular tasks before we see how to define our own object types in the next chapter.

modules & imports#

Modules are files that store python code that can be imported into your Namespace for use. Specifically, in the last chapter we imported from the datetime module without really discussing what that meant. We’ll pause here to ensure that we understand what modules are, what modules are available to you, and how imports work.

A module is a set of Python code with functions, classes, etc. available in it. A Python package is a directory of modules.

In hte last chapter when we specified from datetime import date this indicated that we wanted to import, meaning make available in my current Namespace the date object. However, we need to indicate to python where t find the class definition for that object type. In this statement we indicated that it could be found in the datetime module. Upon executing this import statement, one can then use the date type object.

Why import?#

import is a keyword to import external code into the local namespace.

There is a lot of Python code out in the world, with different people using Python for vastly different tasks. For example, the functions/classes used by a neuroscientist analyzing brain imaging data would be vastly different than the functions/classes being used by a software engineer developing an app. Therefore, you wouldn’t want Python to make all code ever written available on installation. First, that would take a long time, making python take a long time to open up. Second, there are only so many different function names. Certain modules/packages could have functions/classes with the same names. If they were all installed at once, it would be hard to figure out exactly which function/class had been imported most recently, and thus would break programs.

To avoid these issues, Python only front-loads those functions and object types that are commonly used across all Python programmers (i.e. range, len, type, list, int, etc.), requiring any additional functionality to be imported prior to use.

What’s available?#

Some modules are available with every single python installation. These tend to be general use modules, or things that many different Python programmers will find useful, regardless of their specific field. These modules and the functionality within them can be imported at any time so long as Python has been installed. These modules are said to be part of the Python standard library. All of these modules are listed here; however, we’ll note a few of the most-commonly used here and describe when they’re helpful:

  • random - to “generate psuedo-random numbers” and carry out tasks with randomness (i.e. selecting a value at random from a collection)

  • collections - for common operations with collections (dict, tuple, list, etc.)

  • datetime - for operating with dates

  • math - for carrying out mathematical operations

  • os - for interfacing with your operating system (including file system)

  • re - for operating on regular expressions

These, and all modules that are part of the standard library can be imported, after which their functionality is available in your current Namespace.

How to import?#

Prior to importing a module, its functionality will not be available in your namespace. For example, prior to importing the math module if you ask what type of object math is, an error will be returned, as math is not yet in your current Namespace:

# we haven't imported the module yet
# this code fails if you haven't yet imported math
type(math)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-0a474bb83797> in <module>
      1 # we haven't imported the module yet
      2 # this code fails if you haven't yet imported math
----> 3 type(math)

NameError: name 'math' is not defined

To access the math module, it must first be imported into your current Namespace. Most simply this can be done with the general syntax: import module_name. For example, to import the math module, you could use the following:

import math

The above imports the math module into your current namespace, such that if you, at this point, check for the type of math, an error is no longer returned, as math has been imported.

# Check the type of math
type(math)
module

By importing, we now have access to the functionality within this module. For example, the math module includes a function sqrt for calculating the square root of a number.

To execute a function from a module, you must first specify the module name, followed by a . and then the function to be executed:

math.sqrt(9)
3.0

What functionality is available?#

While it can be intimidating at first, much of the functionality in these commonly-used modules will become familiar over time. However, you can always look up what’s available within a module using the dir() function, which returns all available attributes, functions, and methods of a given module/function/class.

For example, for the math module, we see a handful of different functions/attributes, including sqrt(), which we used above. (We’ll ignore the “dunder”s (double underscores) for now.)

dir(math)
['__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'acos',
 'acosh',
 'asin',
 'asinh',
 'atan',
 'atan2',
 'atanh',
 'ceil',
 'copysign',
 'cos',
 'cosh',
 'degrees',
 'e',
 'erf',
 'erfc',
 'exp',
 'expm1',
 'fabs',
 'factorial',
 'floor',
 'fmod',
 'frexp',
 'fsum',
 'gamma',
 'gcd',
 'hypot',
 'inf',
 'isclose',
 'isfinite',
 'isinf',
 'isnan',
 'ldexp',
 'lgamma',
 'log',
 'log10',
 'log1p',
 'log2',
 'modf',
 'nan',
 'pi',
 'pow',
 'radians',
 'remainder',
 'sin',
 'sinh',
 'sqrt',
 'tan',
 'tanh',
 'tau',
 'trunc']

imports: from & as#

Above we specified import module_name and then provided access to all functionality within the module specified. However, sometimes you know there’s only a single function or single object type that you want to use in your code. In those cases, there’s no need to import the entire module. Instead, we can use from to only import the objects we intend to use in our code.

from allows us to decide exactly what objects to import into our Namespace

For example, if the only thing we wanted to use from the random module was the choice function, rather than using the import statement import random, which would provide access to the entire random module in our Namespace, we can instead use the general syntax from module_name import function:

from random import choice

When we specify specifically what it is we want to import, when we go to execute (use) this function, we no longer have to first specify the module name. Rather, we can call the function directly:

choice(['a', 'b', 'c', 'd', 'e'])
'a'

Note that the above function chooses a value at random from the list. Thus, if you’re following along, you likely won’t see the same specific output value; however, the value you see will be a character between ‘a’ and ‘e’ as those are the values from which choice is choosing one at random.

Similarly, as allows for users to specify what name should be used in your code for an object that is imported. This can be helpful when 1) the names of an object to be used is really long and 2) when there are multiple objects with the same name, avoiding confusion.

as allows us to decide exactly what name to use for a module's functionality in our Namespace.

For example, collections is a bit long. If you wanted to import all the functionality from that module into your Namespace, but didn’t want to have to type collections every time you wanted to use an object from that module, you could instead import the module as follows:

import collections as cols

The above would import all the functionality from the collections module into your Namespace; however, it would use the name cols, instead of collections. Thus, if you attempted to access the functionality by referring to collections, the following would error (as collections has not been imported by that name):

# this will produce an error
dir(collections)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-10-830361e86375> in <module>
      1 # this will produce an error
----> 2 dir(collections)

NameError: name 'collections' is not defined

However, the following would provide you with information about the functionality in the collections module, since it was imported using the short name cols:

dir(cols)
['ChainMap',
 'Counter',
 'OrderedDict',
 'UserDict',
 'UserList',
 'UserString',
 '_Link',
 '_OrderedDictItemsView',
 '_OrderedDictKeysView',
 '_OrderedDictValuesView',
 '__all__',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__getattr__',
 '__loader__',
 '__name__',
 '__package__',
 '__path__',
 '__spec__',
 '_chain',
 '_collections_abc',
 '_count_elements',
 '_eq',
 '_heapq',
 '_iskeyword',
 '_itemgetter',
 '_nt_itemgetters',
 '_proxy',
 '_recursive_repr',
 '_repeat',
 '_starmap',
 '_sys',
 'abc',
 'defaultdict',
 'deque',
 'namedtuple']

Note that from import and as can be used in concert. For example,

from string import punctuation as punc

the above statement imports the punctuation object from the string module, giving it the short name punc in our current Namespace.

Warning: The order will always be `from` -> `import` -> `as`. import ascii_letters from string, for example, will provide an error, as the from statement comes after the import statement.

* imports#

Occasionally you will see from module_name import *, where the * acts as a wildcard, meaning “everything”. The statement from module_name import * should be read as “import everything from module_name”; however, this is generally bad practice. The reason for this is because later in your code when you refer to and use an object from the module, it will be unclear where that function came from, given the use of the wildcard.

Warning: * imports are to be avoided.
import random 
dir(random)
['BPF',
 'LOG4',
 'NV_MAGICCONST',
 'RECIP_BPF',
 'Random',
 'SG_MAGICCONST',
 'SystemRandom',
 'TWOPI',
 '_BuiltinMethodType',
 '_MethodType',
 '_Sequence',
 '_Set',
 '__all__',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 '_acos',
 '_bisect',
 '_ceil',
 '_cos',
 '_e',
 '_exp',
 '_inst',
 '_itertools',
 '_log',
 '_os',
 '_pi',
 '_random',
 '_sha512',
 '_sin',
 '_sqrt',
 '_test',
 '_test_generator',
 '_urandom',
 '_warn',
 'betavariate',
 'choice',
 'choices',
 'expovariate',
 'gammavariate',
 'gauss',
 'getrandbits',
 'getstate',
 'lognormvariate',
 'normalvariate',
 'paretovariate',
 'randint',
 'random',
 'randrange',
 'sample',
 'seed',
 'setstate',
 'shuffle',
 'triangular',
 'uniform',
 'vonmisesvariate',
 'weibullvariate']

Exercises#

Q1. Which of the following is NOT a valid Python import statement?

  • A) import collections as col

  • B) from statistics import mean as average

  • B) from os import path

  • D) from random import choice, choices

  • E) import ascii_letters from string

Q2. If the statement import random were used, how would one specify use of the sample function from that module?

  • A) import sample

  • B) random.sample()

  • B) sample()

  • D) rand.sample()

  • E) from random sample()

Q3. If the statement from math import sqrt were used, how would one specify use of the sqrt function from that module?

  • A) from math sqrt()

  • B) import sqrt

  • B) m.sqrt()

  • D) math.sqrt()

  • E) sqrt()