# Python Concepts/Modules

This Programming Language resource is a "stub". Learn how you can help Wikiversity to develop it.

## Objective

* To become familiar with some of the more common modules.
* To understand the syntax associated with modules.
* To experiment with what you can do and what you can't do with modules.
* To appreciate the extra power and flexibility which modules provide.

## Page Index

* Lesson
* Assignments
* Further Reading or Review
* References

## Lesson

As powerful as Python is, it would be almost impossible to write meaningful code without importing certain modules.
Yes, handwritten code can sometimes replace information available in a module. For example, your code might contain the statement:
lower = 'abcdefghijklmnopqrstuvwxyz'
and your hand-written code is as good as:
lower = string.ascii_lowercase
In this situation you might decide that it's not necessary to import string.
But, what about a statement like:
error = sys.exc_info
This statement provides essential information about the most recent error which execution of your code has caused.
Only an expert could create hand-written code to replace this statement and an expert would not want to do so.
When so many powerful features are available in python's modules, it makes good sense to use them.
With appropriate modules imported, your code reflects your good knowledge of python and your willingness to
reap the benefits of the labor of others whose contribution to python makes our professional lives easier.
You're already familiar with some of python's modules: decimal, sys.
In this lesson we'll look first at module string and the basic syntax concerning the use of module
string.
Module string
Importing Module string
The simplest way to use module string is to open python and import it.
$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
To see what you have imported:
>>> globals
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__':, '__builtins__': <module 'builtins' (built-in)>, 'string': <module 'string' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py'>}
>>> string
<module 'string' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py'>
This shows that module string has been imported and it's available, but it doesn't tell us much about string.
For more information about module string:
>>> dir (string)
['Formatter', 'Template', '_ChainMap', '_TemplateMetaclass', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_re', '_string', 'ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace']
for v in dir(string) :
print ('###########################')
print ( v )
print ( eval( 'string.'+v ),'\n' )
Formatter
<class 'string.Formatter'>
Template
<class 'string.Template'>
_ChainMap
<class 'collections.ChainMap'>
_TemplateMetaclass
<class 'string._TemplateMetaclass'>
__all__
['ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace', 'Formatter', 'Template']
__builtins__
**** Lengthy list of builtins. ****
__cached__
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/__pycache__/string.cpython-36.pyc
__doc__
A collection of string constants.
Public module variables:
whitespace -- a string containing all ASCII whitespace
ascii_lowercase -- a string containing all ASCII lowercase letters
ascii_uppercase -- a string containing all ASCII uppercase letters
ascii_letters -- a string containing all ASCII letters
digits -- a string containing all ASCII decimal digits
hexdigits -- a string containing all ASCII hexadecimal digits
octdigits -- a string containing all ASCII octal digits
punctuation -- a string containing all ASCII punctuation characters
printable -- a string containing all ASCII characters considered printable
__file__
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py
__loader__
<_frozen_importlib_external.SourceFileLoader object at 0x10209ff98>
__name__
string
__package__
__spec__
ModuleSpec(name='string', loader=<_frozen_importlib_external.SourceFileLoader object at 0x10209ff98>, origin='/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py')
_re
<module 're' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/re.py'>
_string
<module '_string' (built-in)>
ascii_letters
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
ascii_lowercase
abcdefghijklmnopqrstuvwxyz
ascii_uppercase
ABCDEFGHIJKLMNOPQRSTUVWXYZ
capwords
<function capwords at 0x1020a02f0>
digits
0123456789
hexdigits
0123456789abcdefABCDEF
octdigits
01234567
printable
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'*+,-./:;<=>?@[\]^_`{|}~
^M^K^L
punctuation
!"#$%&'*+,-./:;<=>?@[\]^_`{|}~
whitespace
^M^K^L
Now that you know what's in module string, you can access the contents of string by name:
>>> string.__file__
'/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py'
>>> string.__spec__
ModuleSpec(name='string', loader=<_frozen_importlib_external.SourceFileLoader object at 0x1018accc0>, origin='/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py')
>>> string.digits
'0123456789'
Importing Contents of Module string
For more information about the contents of string, change syntax slightly and try again:
$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from string import *
>>> globals
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__':, '__builtins__': <module 'builtins' (built-in)>, 'ascii_letters': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'ascii_lowercase': 'abcdefghijklmnopqrstuvwxyz', 'ascii_uppercase': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'capwords': <function capwords at 0x100786ae8>, 'digits': '0123456789', 'hexdigits': '0123456789abcdefABCDEF', 'octdigits': '01234567', 'printable': '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c', 'punctuation': '!"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~', 'whitespace': ' \t\n\r\x0b\x0c', 'Formatter': <class 'string.Formatter'>, 'Template': <class 'string.Template'>}
With a little formatting we see:
'ascii_letters': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'ascii_lowercase': 'abcdefghijklmnopqrstuvwxyz',
'ascii_uppercase': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'capwords': <function capwords at 0x100786ae8>,
'digits': '0123456789',
'hexdigits': '0123456789abcdefABCDEF',
'octdigits': '01234567',
'printable': '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c',
'punctuation': '!"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~',
'whitespace': ' \t\n\r\x0b\x0c',
'Formatter': <class 'string.Formatter'>,
'Template': <class 'string.Template'>}
The values in the left hand column above are keys of dictionary globals and they are always strings.
In the right hand column are the values associated with the keys of the left hand.
As you can see, the values may or may not be strings.
Because globals is a dictionary, it may be accessed like a dictionary:
>>> [ v for v in globals if '__' not in v ]
['ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace', 'Formatter', 'Template']
# These values are the same as string.__all__ .
>>> globals['digits']
'0123456789'
>>> globals['ascii_uppercase']
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
The one name not seen in globals is string.
>>> string
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'string' is not defined
>>> 'string' in globals
False
The contents of string are now available:
>>> ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> punctuation
'!"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~'
>>> whitespace
' \t\n\r\x0b\x0c'
>>> whitespace == ' \t\n\r\v\f'
True
Experiment with the contents of string:
>>> capwords('the authOrizEd biogRAPHY of tHomas jeFferSON')
'The Authorized Biography Of Thomas Jefferson'
>>> printable == digits + ascii_lowercase + ascii_uppercase + punctuation + whitespace
True
>>> dir(string._re)
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_alphanum_bytes', '_alphanum_str', '_cache', '_compile', '_compile_repl', '_expand', '_locale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'template']
>>> import re
>>> dir(re)
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_alphanum_bytes', '_alphanum_str', '_cache', '_compile', '_compile_repl', '_expand', '_locale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'template']
>>> re == string._re
True
Note:
While the statement import * is convenient, Python's Documentation states:
In most cases Python programmers do not use this facility since it introduces an unknown set of names into the interpreter, possibly hiding some things you have already defined.
.... in general the practice of importing * from a module or package is frowned upon, since it often causes poorly readable code. However, it is okay to use it to save typing in interactive sessions.
Changing and restoring contents of module string
>>> whitespace = 'Hello, world!' ; whitespace
'Hello, world!'
>>> whitespace = ' \t\n\r\x0b\x0c' ; whitespace
' \t\n\r\x0b\x0c'
>>> whitespace = 'Hello, world!' ; whitespace
'Hello, world!'
>>> from string import whitespace ; whitespace
' \t\n\r\x0b\x0c'
Using module string
After you become familiar with the contents of module string, you may decide to import only the module
and use the syntax that requires the name of the module:
$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> whitespace
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'whitespace' is not defined
>>> string.whitespace
' \t\n\r\x0b\x0c'
>>> punctuation
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'punctuation' is not defined
>>> string.punctuation
'!"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~'
You can change the contents of module string, but this not recommended. In extreme cases, you may have to quit python and start again.
Creating your own module
In this case we will be working with module decimal. If this module is new to you, spend some time looking at
module decimal as if it were module string above.
In the present working directory create a Python source file, for example, myDec.py . This will become module
myDec.
# file myDec.py
import decimal
# Handy abbreviations:
D = decimal.Decimal
getC = decimal.getcontext
T = decimal.DecimalTuple
# User-written function:
def doit(v1) :
return D(v1) + D(5)
Invoke Python in interactive mode:
$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from myDec import *
>>> globals
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__':, '__builtins__': <module 'builtins' (built-in)>,
'decimal': <module 'decimal' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/decimal.py'>,
'D': <class 'decimal.Decimal'>,
'getC': Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=, traps=[InvalidOperation, DivisionByZero, Overflow]),
'T': <class 'decimal.DecimalTuple'>,
'doit': <function doit at 0x1018a1950>}
>>> decimal # Loaded from module myDec.
<module 'decimal' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/decimal.py'>
>>> dir (decimal)
['BasicContext', 'Clamped', 'Context', 'ConversionSyntax', 'Decimal', 'DecimalException', 'DecimalTuple', 'DefaultContext', 'DivisionByZero', 'DivisionImpossible', 'DivisionUndefined', 'ExtendedContext', 'FloatOperation', 'HAVE_THREADS', 'Inexact', 'InvalidContext', 'InvalidOperation', 'MAX_EMAX', 'MAX_PREC', 'MIN_EMIN', 'MIN_ETINY', 'Overflow', 'ROUND_05UP', 'ROUND_CEILING', 'ROUND_DOWN', 'ROUND_FLOOR', 'ROUND_HALF_DOWN', 'ROUND_HALF_EVEN', 'ROUND_HALF_UP', 'ROUND_UP', 'Rounded', 'Subnormal', 'Underflow', '__builtins__', '__cached__', '__doc__', '__file__', '__libmpdec_version__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'getcontext', 'localcontext', 'setcontext']
>>> The various contexts:
>>> type(decimal.BasicContext)
<class 'decimal.Context'>
>>> type(decimal.DefaultContext)
<class 'decimal.Context'>
>>> type(decimal.ExtendedContext)
<class 'decimal.Context'>
>>> type(decimal.getcontext)
<class 'builtin_function_or_method'>
>>> type(decimal.getcontext)
<class 'decimal.Context'>
>>> T
<class 'decimal.DecimalTuple'>
>>> D
<class 'decimal.Decimal'>
>>> doit
<function doit at 0x1018a1950>
>>> getC
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=, traps=[InvalidOperation, DivisionByZero, Overflow])
>>> doit(7)
Decimal('12')
>>> getC.prec=31
>>> getC
Context(prec=31, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=, traps=[InvalidOperation, DivisionByZero, Overflow]) # prec was changed to 31.
>>> getC.prec=28
>>> D(1234567890123456789012345678901234567890)+0
Decimal('1.234567890123456789012345679E+39') # Precision of 28.
>>> getC.prec=10
>>> D(1234567890123456789012345678901234567890)+0
Decimal('1.234567890E+39') # precision of 10
>>> getC
Context(prec=10, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow]) # Precision of 10.
>>> T(1,(3,4,5,6),-3)
DecimalTuple(sign=1, digits=(3, 4, 5, 6), exponent=-3)
>>> T(1,(3,4,5,6),-3).sign
1
>>> T(1,(3,4,5,6),-3).digits
(3, 4, 5, 6)
>>> T(1,(3,4,5,6),-3).exponent
-3
>>> D(T(1,(3,4,5,6),-3))
Decimal('-3.456')
Slightly more advanced
Let your file myDec.py be:
import decimal
# If module decimal was previously loaded, this statement is ignored.
# If module decimal was not previously loaded, this statement is executed.
# Same for 'import sys' below.
import sys
# Handy abbreviations:
getC = decimal.getcontext
T = decimal.DecimalTuple
# User-written function:
def D (v1) :
This function converts value v1 to decimal object.
If there is an error in conversion, this function
attempts to avoid introducing another error in the
'except' clause by ensuring that module 'sys' is
available. It was loaded above.
if isinstance (v1, decimal.Decimal) : return v1
error = output = ''
try : output = decimal.Decimal(str(v1))
except : error = sys.exc_info[:2]
if error :
print ('myDec.D: error converting', str(v1)[:80], 'to Decimal:')
print (' ', error)
return None
return output
Invoke Python in interactive mode:
$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from myDec import *
>>> dir
['D', 'T', '__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'decimal', 'getC', 'sys']
>>> sorted(dir) == sorted([ v for v in globals ])
True
>>> v1 = Decimal(6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'Decimal' is not defined
>>> decimal.Decimal(6)
Decimal('6')
>>> D(6)
Decimal('6')
>>> type(D(6))
<class 'decimal.Decimal'>
>>> D(1.23)
Decimal('1.23')
>>> decimal.Decimal(1.23)
>>> Decimal('1.229999999999999982236431605997495353221893310546875')
>>> D(4.).as_tuple
DecimalTuple(sign=0, digits=(4, 0), exponent=-1)
>>> D(4.).as_tuple.digits
(4, 0)
>>> D(49.).sqrt
Decimal('7.0')
>>> D(3+4j)
myDec.D: error converting (3+4j) to Decimal:
(<class 'decimal.InvalidOperation'>, InvalidOperation([<class 'decimal.ConversionSyntax'>],))
globals unique to each module
This example (on UNIX) shows how to access global variables across modules.
Create 2 files test1.py and test.py.
# test1.py
def test1_ReceiveGlobals(dict1) :
for v in dict1 :
globals[v] = dict1[v]
def test1_SendGlobals :
return globals
# test.py
from test1 import *
def set_globals :
t1 = (
('test1_23',67),
('test1_24',83),
('common_1',17), # This name is repeated below against "global".
('common_2',23), # This name is repeated below against "global".
dict1 = dict( t1 )
test1_ReceiveGlobals(dict1)
global test_46,test_47
global common_1,common_2 # These 2 names exist in "dict1" above.
test_46 = 79
test_47 = 41
common_1 = 'φιλοσοφοῦμεν ἄνευ μαλακίας.' # This name exists in "dict1" above.
common_2 = 'These are the times that ....' # This name exists in "dict1" above.
def print_globals :
print
print ('globals:')
for v in [v for v in globals if '__' not in v]:
print ('globals[] ='.format(v, globals[v]))
test1_globals = test1_SendGlobals
print
print ('test1_globals:')
for v in [v for v in test1_globals if '__' not in v]:
print ('test1_globals[] ='.format(v, test1_globals[v]))
print_globals
set_globals
print_globals
Invoke test.py:
$ python3.6 ./test.py >sout 2>serr ; echo $? ; wc sout serr
0
28 107 1224 sout
0 0 0 serr
28 107 1224 total
# file sout
globals:
globals[test1_ReceiveGlobals] = <function test1_ReceiveGlobals at 0x1022451e0> # Common to both.
globals[test1_SendGlobals] = <function test1_SendGlobals at 0x102245268> # Common to both.
globals[set_globals] = <function set_globals at 0x100561e18> # Unique to test.
globals[print_globals] = <function print_globals at 0x1022452f0> # Unique to test.
test1_globals:
test1_globals[test1_ReceiveGlobals] = <function test1_ReceiveGlobals at 0x1022451e0> # Common to both.
test1_globals[test1_SendGlobals] = <function test1_SendGlobals at 0x102245268> # Common to both.
globals:
globals[test1_ReceiveGlobals] = <function test1_ReceiveGlobals at 0x1022451e0> # Common to both.
globals[test1_SendGlobals] = <function test1_SendGlobals at 0x102245268> # Common to both.
globals[set_globals] = <function set_globals at 0x100561e18> # Unique to test.
globals[print_globals] = <function print_globals at 0x1022452f0> # Unique to test.
globals[test_46] = 79 # Unique to test.
globals[test_47] = 41 # Unique to test.
globals[common_1] = φιλοσοφοῦμεν ἄνευ μαλακίας. # Name exists in test1 below. Value is different.
globals[common_2] = These are the times that .... # Name exists in test1 below. Value is different.
test1_globals:
test1_globals[test1_ReceiveGlobals] = <function test1_ReceiveGlobals at 0x1022451e0> # Common to both.
test1_globals[test1_SendGlobals] = <function test1_SendGlobals at 0x102245268> # Common to both.
test1_globals[test1_23] = 67 # Unique to test1.
test1_globals[test1_24] = 83 # Unique to test1.
test1_globals[common_1] = 17 # Name exists in test above. Value is different.
test1_globals[common_2] = 23 # Name exists in test above. Value is different.
Imported module invokes function in main module
File test5.py:
def test5_doit :
main5_doit
File main5.py:
import test5
def main5_doit :
print ('in main5_doit')
test5.test5_doit
Invoke main5.py:
$ python3.6 ./main5.py
Traceback (most recent call last):
File "./main5.py", line 6, in <module>
test5.test5_doit
File "...../test5.py", line 2, in test5_doit
main5_doit
NameError: name 'main5_doit' is not defined
Add one line of code to file main5.py:
import test5
def main5_doit :
print ('in main5_doit')
test5.main5_doit = main5_doit
test5.test5_doit
Invoke main5.py:
$ python3.6 ./main5.py
in main5_doit
Function main5_doit in main module was invoked by code in imported module test5. :

## Assignments

* In the output of dir(string) are two names 'Formatter' and 'Template'. Because this page is about modules generally,
* and module string is used as an example, there has been no information presented concerning these two classes.
* For more information about these classes, see
* "Custom String Formatting" and
* "Template strings."
* Experiment with statements such as import decimal, from decimal import *, import myDec,
* from myDec import *.
* Become familiar with the syntax associated with contents of modules, such as:
* Decimal(6), decimal.Decimal(6), myDec.decimal.Decimal(6), D(6),
* myDec.D(6).
* Experiment with files main.py, test1.py, test2.py, test3.py. In main.py include statements import test1, import test2, import test3. Implement functionality so that code in test1 can invoke functions in test2 and test3, and vice-versa.

## Further Reading or Review

Completion status: this resource is a stub, which means that pretty much nothing has been done yet.
Previous Lesson: Built-in Functions
This Lesson: Modules
Next Lesson: Classes
Course Home Page :