8 Modules and packages

Functional programming, which we explored in the previous chapter, is one of the knottiest topics you’ll encounter in the programming world. I’m happy to tell you that this chapter, about Python’s modules, will provide a stark contrast, and will be one of the easiest in this book. Modules are important, but they’re also very straightforward to create and use. So if you find yourself reading this chapter and thinking, “Hey, that’s pretty obvious,” well, that’s just fine.

What are modules in Python, and how do they help us? I’ve already mentioned the acronym DRY, short for “Don’t repeat yourself,” several times in this book. As programmers, we aim to “DRY up” our code by taking identical sections of code and using them multiple times. Doing so makes it easier to understand, manage, and maintain our code. We can also more easily test such code.

When we have repeated code in a single program, we can DRY it up by writing a function and then calling that function repeatedly. But what if we have repeated code that’s used across multiple programs? We can then create a library--or, as it’s known in the world of Python, a module.

Modules actually accomplish two things in Python. First, they make it possible for us to reuse code across programs, helping us to improve the reusability and maintainability of our code. In this way, we can define functions and classes once, stick them into a module, and reuse them any number of times. This not only reduces the amount of work we need to do when implementing a new system, but also reduces our cognitive load, since we don’t have to worry about the implementation details.

For example, let’s say that your company has come up with a special pricing formula that combines the weather with stock-market indexes. You’ll want to use that pricing formula in many parts of your code. Rather than repeating the code, you could define the function once, put it into a module, and then use that module everywhere in your program that you want to calculate and display prices.

You can define any Python object--from simple data structures to functions to classes--in a module. The main question is whether you want it to be shared across multiple programs, now or in the future.

Second, modules are Python’s way of creating namespaces. If two people are collaborating on a software project, you don’t want to have to worry about collisions between their chosen variable and function names, right? Each file--that is, module--has its own namespace, ensuring that there can’t be conflicts between them.

Python comes with a large number of modules, and even the smallest nontrivial Python program will use import (http://mng.bz/xWme), to use one or more of them. In addition to the standard library, as it’s known, Python programmers can take advantage of a large number of modules available on the Python Package Index (https://pypi.org). In this chapter, we’ll explore the use and creation of modules, including packages.

Hint If you visit PyPI at https://pypi.org, you’ll discover that the number of community-contributed, third-party packages is astonishingly large. Just as of this writing, there are more than 200,000 packages on PyPI, many of which are buggy or unmaintained. How can you know which of these packages is worthwhile and which isn’t? The site “Awesome Python,” at http://mng.bz/ AA0K, is an attempt to remedy this situation, with edited lists of known stable, maintained packages on a variety of topics. This is a good first place to check for packages before going to PyPI. Although it doesn’t guarantee that the package you use will be excellent, it certainly improves the chances of this being the case.

Table 8.1 What you need to know

Concept

What is it?

Example

To learn more

import

Statement for importing modules

import os

http://mng.bz/xWme

from X import Y

Imports module X, but only defines Y as a global variable

from os import sep

http://mng.bz/xWme

importlib.reload

Re-imports an already loaded module, typically to update definitions during development

importlib.reload(mymod)

http://mng.bz/Z2PO

pip

Command-line program for installing packages from PyPI

pip install packagename

https://pypi.org/

Decimal

Class that accurately handles floating-point numbers

from decimal import Decimal

http://mng.bz/RAX0

Importing modules

One of the catchphrases in the Python world is “batteries included.” This refers to the many TV commercials I saw as a child that would spend their first 29.5 seconds enticing us to buy their exciting, fun-looking, beautiful toys ... only to spend the final half second saying, “batteries not included”--meaning that it wasn’t enough to buy the product to enjoy it, we had to buy batteries as well.

“Batteries included” refers to the fact that when you download and install Python, you have everything you’re going to need to get your work done. This isn’t quite as true as used to be the case, and PyPI (the Python Package Index, described separately in this chapter) provides us with a huge collection of third-party Python modules that we can use to improve our products. But the fact remains that the standard library, meaning the stuff that comes with Python when we install it, includes a huge number of modules that we can use in our programs.

The most commonly used things in the standard library, such as lists and dicts, are built into the language, thanks to a namespace known as builtins. You don’t need to worry about importing things in the builtins module, thanks to the LEGB rule that I discussed back in chapter 6. But anything else in the standard library must be loaded into memory before it can be used.

We load such a module using the import statement. The simplest version of import looks like

import MODULENAME

For example, if I want to use the os module, then I’ll write

import os

Notice a couple of things about this statement:

First, it’s not a function; you don’t say import(os), but rather import os.

Second, we don’t import a filename. Rather, we indicate the variable that we want to define, rather than the file that should be loaded from the disk. So don’t try to import "os" or even import "os.py". Just as def defines a new variable that references a function, so too import defines a new variable that references a module.

When you import os, Python tries to find a file that matches the variable name you’re defining. It’ll typically look for os.py and os.pyc, where the former is the original source code and the latter is the byte-compiled version. (Python uses the filesystem’s timestamp to figure out which one is newer and creates a new byte-compiled version as necessary. So don’t worry about compiling!)

Python looks for matching files in a number of directories, visible to you in sys.path. This is a list of strings representing directories; Python will iterate over each directory name until it finds a matching module name. If more than one directory contains a module with the same name, then the first one Python encounters is loaded, and any subsequent modules will be completely ignored. This can often lead to confusion and conflicts, in my experience, so try to choose unusual and distinct names for your modules.

Now, import has a number of variations that are useful to know, and that you’ll probably see in existing code--as well as use in your own code. That said, the ultimate goal is the same: load a module, and define one or more module-related names in your namespace.

If you’re happy loading a module and using its name as a variable, then import MODULENAME is a great way to go. But sometimes, that name is too long. For that reason, you’ll want to give the module name an alias. You can do that with

import mymod as mm

When you use as, the name mymod will not be defined. However, the name mm will be defined. This is silly and unnecessary if your module name is going to be short. But if the name is long, or you’re going to be referring to it a lot, then you might well want to give it a shorter alias. A classic example is NumPy (https://numpy.org/), which sits at the core of all of Python’s scientific and numeric computing systems, including data science and machine learning. That module is typically imported with an alias of np:

import numpy as np

Once you’ve imported a module, all of the names that were defined in the file’s global scope are available as attributes, via the module object. For example, the os module defines sep, which indicates what string separates elements of a directory path. You can access that value as os.sep. But if you’re going to use it a lot, then it’s a bit of a pain to constantly say os.sep. Wouldn’t it be nice to just call it sep? You can’t do that, of course, because the name sep would be a variable, whereas os.sep is an attribute.

However, you can bridge the gap and get the attribute loaded by using the following syntax:

from os import sep

Note that this won’t define the os variable, but it will define the sep variable. You can use from .. import on more than one variable too:

from os import sep, path

Now, both sep and path will be defined as variables in your global scope.

Worried about one of these imported attributes clashing with an existing variable, method, or module name? Then you can use from .. import .. as:

from os import sep as s

There’s a final version that I often see, and that I generally advise people not to use. It looks like this:

from os import *

This will load the os module into memory, but (more importantly) will take all of the attributes from os and define them as global variables in the current namespace. Given that we generally want to avoid global variables unless necessary, I see it as a problem when we allow the module to decide what variables should be defined.

Note Not all names from a module will be imported with import *. Names starting with _ (underscore) will be ignored. Moreover, if the module defines a list of strings named __all__, only names specified in the module will be loaded with import *. However, from X import Y will always work, regardless of whether __all__ is defined.

At the end of the day, import makes functions, classes, and data available to you in your current namespace. Given the huge number of modules available, both in Python’s standard library and on PyPI, that puts a lot of potential power at your fingertips--and explains why so many Python programs start with several lines of import statements.

Exercise 36 Sales tax

Modules allow us to concentrate on higher-level thinking and avoid digging into the implementation details of complex functionality. We can thus implement a function once, stick it into a module, and use it many times to implement algorithms that we don’t want to think about on a day-to-day basis. If you had to actually understand and wade through the calculations involved in internet security, for example, just to create a web application, you would never finish.

In this exercise, you’ll implement a somewhat complex (and whimsical) function, in a module, to implement tax policy in the Republic of Freedonia. The idea is that the tax system is so complex that the government will supply businesses with a Python module implementing the calculations for them.

Sales tax on purchases in Freedonia depends on where the purchase was made, as well as the time of the purchase. Freedonia has four provinces, each of which charges its own percentage of tax:

  • Chico: 50%

  • Groucho: 70%

  • Harpo: 50%

  • Zeppo: 40%

Yes, the taxes are quite high in Freedonia (so high, in fact, that they’re said to have a Marxist government). However, these taxes rarely apply in full. That’s because the amount of tax applied depends on the hour at which the purchase takes place. The tax percentage is always multiplied by the hour at which the purchase was made. At midnight (i.e., when the 24-hour clock is 0), there’s no sales tax. From 12 noon until 1 p.m., only 50% (12/24) of the tax applies. And from 11 p.m. until midnight, 95.8% (i.e., 23/24) of the tax applies.

Your job is to implement that Python module, freedonia.py. It should provide a function, calculate_tax, that takes three arguments: the amount of the purchase, the province in which the purchase took place, and the hour (an integer, from 0-24) at which it happened. The calculate_tax function should return the final price, as a float.

Thus, if I were to invoke

calculate_tax(500, 'Harpo', 12)

a $500 purchase in Harpo province (with 50%) tax would normally be $750. However, because the purchase was done at 12 noon, the tax is only half of its maximum, or $125, for a total of $625. If the purchase were made at 9 p.m. (i.e, 21:00 on a 24-hour clock), then the tax would be 87.5% of its full rate, or 43.75%, for a total price of $718.75.

Moreover, I want you to write this solution using two separate files. The calculate _tax function, as well as any supporting data and functions, should reside in the file freedonia.py, a Python module. The program that calls calculate_tax should be in a file called use_freedonia.py, which then uses import to load the function.

Working it out

The freedonia module does precisely what a Python module should do. Namely, it defines data structures and functions that provide functionality to one or more other programs. By providing this layer of abstraction, it allows a programmer to focus on what’s important to them, such as the implementation of an online store, without having to worry about the nitty-gritty of particular details.

While some countries have extremely simple systems for calculating sales tax, others--such as the United States--have many overlapping jurisdictions, each of which applies its own sales tax, often at different rates and on different types of goods. Thus, while the Freedonia example is somewhat contrived, it’s not unusual to purchase or use libraries to calculate taxes.

Our module defines a dict (RATES), in which the keys are the provinces of Freedonia, and the values are the taxation rates that should be applied there. Thus, we can find out the rate of taxation in Groucho province with RATES['Groucho']. Or we can ask the user to enter a province name in the province variable, and then get RATES[province]. Either way, that will give us a floating-point number that we can use to calculate the tax.

A wrinkle in the calculation of Freedonian taxation is the fact that taxes get progressively higher as the day goes on. To make this calculation easier, I wrote a time_percentage function, which simply takes the hour and returns it as a percentage of 24 hours.

Note In Python 2, integer division always returns an integer, even when that means throwing away the remainder. If you’re using Python 2, be sure to divide the current hour not by 24 (an int) but by 24.0 (a float).

Finally, the calculate_tax function takes three parameters--the amount of the sale, the name of the province in which the sale took place, and the hour at which the sale happened--and returns a floating-point number indicating the actual, current tax rate.

The Decimal version

If you’re actually doing calculations involving serious money, you should almost certainly not be using floats. Rather, you should use integers or the Decimal class, both of which are more accurate. (See chapter 1 for some more information on the inaccuracy of floats.) I wanted this exercise to concentrate on the creation of a module, and not the use of the Decimal class, so I didn’t require it.

Here’s how my solution would look using Decimal:

from decimal import Decimal
 
rates = {
    'Chico': Decimal('0.5'),
    'Groucho': Decimal('0.7'),
    'Harpo': Decimal('0.5'),
    'Zeppo': Decimal('0.4')
}
 
def time_percentage(hour):
    return hour / Decimal('24.0')
 
def calculate_tax(amount, state, hour):
    return float(amount + (amount * rates[state] * time_percentage(hour)))

Notice that this code uses Decimal on strings, rather than floats, to ensure maximum accuracy. We then return a floating-point number at the last possible moment. Also note that any Decimal value multiplied or divided by a number remains a Decimal, so we only need to make a conversion at the end.

Here’s a program that uses our freedonia module:

from freedonia import calculate_tax
 
tax_at_12noon = calculate_tax(100, 'Harpo', 12)
tax_at_9pm = calculate_tax(100, 'Harpo', 21)
 
print(f'You owe a total of: {tax_at_12noon}')
print(f'You owe a total of: {tax_at_9pm}')

Error checking the Pythonic way

Since a module will be used by many other programs, it’s important for it to not only be accurate, but also have decent error checking. In our particular case, for example, we would want to check that the hour is between 0 and 24.

Right now, someone who passes an invalid hour to our function will still get an answer, albeit a nonsensical one. A better solution would be to have the function raise an exception if the input is invalid. And while we could raise a built-in Python exception (e.g., ValueError), it’s generally a better idea to create your own exception class and raise it; for example

class HourTooLowError(Exception): pass
class HourTooHighError(Exception): pass
 
def calculate_tax(amount, state, hour):
    if hour < 0:
        raise HourTooLowError(f'Hour of {hour} is < 0')
 
    if hour >= 24:
        raise HourTooHighError(f'Hour of {hour} is >= 24')
 
    return amount + (amount * rates[state] * time_percentage(hour))

Adding such exceptions to your code is considered very Pythonic and helps to ensure that anyone using your module will not accidentally get a bad result.

Solution

RATES = {
    'Chico': 0.5,
    'Groucho': 0.7,
    'Harpo': 0.5,
    'Zeppo': 0.4
}
 
def time_percentage(hour):
    return hour / 24           
 
def calculate_tax(amount, state, hour):
    return amount + (amount * RATES[state] * time_percentage(hour))
 
 
print(calculate_tax(500, 'Harpo', 12))

This means we’ll get 0% at midnight and just under 100% at 23:59.

You can work through a version of this code in the Python Tutor at http://mng.bz/ oP1j.

Note that the Python Tutor site doesn’t support modules, so this solution was placed in a single file, without the use of import.

Screencast solution

Watch this short video walkthrough of the solution: https://livebook.manning.com/ video/python-workout.

Beyond the exercise

Now that you’ve written a simple function that masks more complex functionality, here are some other functions you can write as modules:

  • Income tax in many countries is not a flat percentage, but rather the combination of different “brackets.” So a country might not tax you on your first $1,000 of income, and then 10% on the next $10,000, and then 20% on the next $10,000, and then 50% on anything above that. Write a function that takes someone’s income and returns the amount of tax they will have to pay, totaling the percentages from various brackets.

  • Write a module providing a function that, given a string, returns a dict indicating how many characters provide a True result to each of the following functions: str.isdigit, str.isalpha, and str.isspace. The keys should be isdigit, isalpha, and isspace.

  • The dict.fromkeys method (http://mng.bz/1zrV) makes it easy to create a new dict. For example, dict.fromkeys('abc') will create the dict {'a':None, 'b':None, 'c':None}. You can also pass a value that will be assigned to each key, as in dict.fromkeys('abc', 5), resulting in the dict {'a':5, 'b':5, 'c':5}. Implement a function that does the same thing as dict.keys but whose second argument is a function. The value associated with the key will be the result of invoking f(key).

Loading and reloading modules

When you use import to load a module, what happens? For example, if you say

import mymod

then Python looks for mymod.py in a number of directories, defined in a list of strings called sys.path. If Python encounters a file in one of those directories, it loads the file and stops searching in any other directories.

Note There are a number of ways to modify sys.path, including by setting the environment variable PYTHONPATH and creating files with a .pth suffix in your Python installation’s site-packages directory. For more information on setting sys.path, see the Python documentation, or read this helpful article: http://mng.bz/PAP9.

This means import normally does two distinct things: it loads the module and defines a new variable. But what happens if your program loads two modules, each of which in turn loads modules? For example, let’s say that your program imports both pandas and scipy, both of which load the numpy module. In such a case, Python will load the module the first time, but only define the variable the second time. import only loads a module once, but it will always define the variable that you’ve asked it to create.

This is done via a dict defined in sys called sys.modules. Its keys are the names of modules that have been loaded, and its values are the actual module objects. Thus, when we say import mymod, Python first checks to see if mymod is in sys.modules. If so, then it doesn’t search for or load the module. Rather, it just defines the name.

This is normally a great thing, in that there’s no reason to reload a module once the program has started running. But when you’re debugging a module within an interactive Python session, you want to be able to reload it repeatedly, preferably without exiting from the current Python session.

In such cases, you can use the reload function defined in the importlib module. It takes a module object as an argument, so the module must already have been defined and imported. And it’s the sort of thing that you’ll likely use all the time in development, and almost never in actual production.

Note In previous versions of Python, reload was a built-in function. As of Python 3, it’s in the importlib module, which you must import to use it.

Exercise 37 Menu

If you find yourself writing the same function multiple times across different programs or projects, you almost certainly want to turn that function into a module. In this exercise, you’re going to write a function that’s generic enough to be used in a wide variety of programs.

Specifically, write a new module called “menu” (in the file menu.py). The module should define a function, also called menu. The function takes any number of key-value pairs as arguments. Each value should be a callable, a fancy name for a function or class in Python.

When the function is invoked, the user is asked to enter some input. If the user enters a string that matches one of the keyword arguments, the function associated with that keyword will be invoked, and its return value will be returned to menu’s caller. If the user enters a string that’s not one of the keyword arguments, they’ll be given an error message and asked to try again.

The idea is that you’ll be able to define several functions, and then indicate what user input will trigger each function:

from menu import menu
 
def func_a():
    return "A"
 
def func_b():
    return "B"
 
return_value = menu(a=func_a, b=func_b)
print(f'Result is {return_value}')

In this example, return_value will contain A if the user chooses a, or B if the user chooses b. If the user enters any other string, they’re told to try again. And then we’ll print the user’s choice, just to confirm things.

Working it out

The solution presented here is another example of a dispatch table, which we saw earlier in the book, in the “prefix calculator” exercise. This time, we’re using the **kwargs parameter to create that dispatch table dynamically, rather than with a hard-coded dict.

In this case, whoever invokes the menu function will provide the keywords--which function as menu options--and the functions that will be invoked. Note that these functions all take zero arguments, although you can imagine a scenario in which the user could provide more inputs.

We use ** here, which we previously saw in the XML-creation exercise. We could have instead received a dict as a single argument, but this seems like an easier way for us to create the dict, using Python’s built-in API for turning **kwargs into a dict.

While I didn’t ask you to do so, my solution presents the user with a list of the valid menu items. I do this by invoking str.join on the dict, which has the effect of creating a string from the keys, with / characters between them. I also decided to use sorted to present them in alphabetical order.

With this in place, we can now ask the user for input from any zero-argument function.

Why do we check __name__?

One of the most famous lines in all of Python reads as follows:

if __name__ == '__main__':

What does this line do? How does it help? This line is the result of a couple different things happening when we load a module:

  • First, when a module is loaded, its code is executed from the start of the file until the end. You’re not just defining things; any code in the file is actually executed. That means you can (in theory) invoke print or have for loops. In this case, we’re using if to make some code execute conditionally when it’s loaded.

  • Second, the __name__ variable is either defined to be __main__, meaning that things are currently running in the initial, default, and top-level namespace provided by Python, or it’s defined to be the name of the current module. The if statement here is thus checking to see if the module was run directly, or if it was imported by another piece of Python code.

In other words, the line of code says, “Only execute the below code (i.e., inside of the if statement) if this is the top-level program being executed. Ignore the stuff in the if when we import this module.”

You can use this code in a few different ways:

  • Many modules run their own tests when invoked directly, rather than imported.

  • Some modules can be run interactively, providing user-facing functionality and an interface. This code allows that to happen, without interfering with any function definitions.

  • In some odd cases, such as the multiprocessing module in Windows, the code allows you to differentiate between versions of the program that are being loaded and executed in separate processes.

While you can theoretically have as many if __name__ == '__main__' lines in your code as you want, it’s typical for this line to appear only once, at the end of your module file.

You’ll undoubtedly encounter this code, and might even have written it yourself in the past. And now you know how it works!

Solution

def menu(**options):                                 
    while True:                                      
        option_string = '/'.join(sorted(options))    
        choice = input(
            f'Enter an option ({option_string}): ')  
        if choice in options:                        
            return options[choice]()                 
 
        print('Not a valid option')                  
 
def func_a():
    return "A"
 
def func_b():
    return "B"
return_value = menu(a=func_a, b=func_b)
print(f'Result is {return_value}')

“options” is a dict populated by the keyword arguments.

An infinite loop, which we’ll break out of when the user gives valid input

Creates a string of sorted options, separated by “/”

Asks the user to enter an option

Has the user entered a key from “**options”?

If so, then return the result of executing the function.

Otherwise, scold the user and have them try again.

You can work through a version of this code in the Python Tutor at http://mng.bz/ nPW8.

Note that the Python Tutor site doesn’t support modules, so this solution was placed in a single file, without the use of import.

Screencast solution

Watch this short video walkthrough of the solution: https://livebook.manning.com/ video/python-workout.

Beyond the exercise

Now that you’ve written and used two different Python modules, let’s go beyond that and experiment with some more advanced techniques and problems:

  • Write a version of menu.py that can be imported (as in the exercise), but that when you invoke the file as a stand-alone program from the command line, tests the function. If you aren’t familiar with testing software such as pytest, you can just run the program and check the output.

  • Turn menu.py into a Python package and upload it to PyPI. (I suggest using your name or initials, followed by “menu,” to avoid name collisions.) See the sidebar on the difference between modules and packages, and how you can participate in the PyPI ecosystem with your own open-source projects.

  • Define a module stuff with three variables--a, b, and c--and two functions--foo and bar. Define __all__ such that from stuff import * will cause a, c, and bar to be imported, but not b and foo.

Modules vs. packages

This chapter is all about modules--how to create, import, and use them. But you might have noticed that we often use another term, package, to discuss Python code. What’s the difference between a module and a package?

A module is a single file, with a “.py” suffix. We can load the module using import, as we’ve seen. But what if your project is large enough that it would make more sense to have several separate files? How can you distribute those files together?

The answer is a package, which basically means a directory containing one or more Python modules. For example, assume you have the modules first.py, second.py, and third.py, and want to keep them together. You can put them all into a directory, mypackage. Assuming that directory is in sys.path, you can then say

from mypackage import first

Python will go into the mypackage directory, look for first.py, and import it. You can then access all of its attributes via first.x, first.y, and so forth.

Alternatively, you could say

import mypackage.first

In this case, Python will still load the module first, but it’ll be available in your program via the long name, mypackage.first. You can then use mypackage.first.x and mypackage.first.y.

Alternatively, you could say

import mypackage

But this will only be useful if, in the mypackage directory, you have a file named __init__.py. In such a case, importing mypackage effectively means that __init__.py is loaded, and thus executed. You can, inside of that file, import one or more of the modules within the package.

What about if you want to distribute your package to others? Then you’ll have to create a package. If this sounds strange, that you need a package to distribute your package, that’s because the same term, package, is used for two different concepts. A PyPI package, or distribution package, is a wrapper around a Python package containing information about the author, compatible versions, and licensing, as well as automated tests, dependencies, and installation instructions.

Even more confusing than the use of “package” to describe two different things is the fact that both the distribution package and the Python package are directories, and that they should have the same name. If your distribution package is called mypackage, you’ll have a directory called mypackage. Inside that directory, among other things, will be a subdirectory called mypackage, which is where the Python package goes.

Creating a distribution package means creating a file called setup.py (documented here: http://mng.bz/wB9q), and I must admit that for many years, I found this to be a real chore. It turns out that I wasn’t alone, and a number of Python developers have come up with ways to create distribution packages with relative ease. One that I’ve been using for a while is called “Poetry” (http://mng.bz/2Xzd), and makes the entire process easy and straightforward.

If you want to distribute packages via PyPI, you’ll need to register for a username and password at https://pypi.org/. Once you have that, here are the minimal steps you’ll need to take an existing package and upload it to PyPI with Poetry, using Unix shell commands:

$ poetry new mypackage                  
$ cd mypackage                          
$ cp -R ~/mypackage-code/* mypackage    
$ poetry build                          
$ poetry publish                        

Creates a new package skeleton called mypackage

Moves into the top-level directory

Copies the contents of the Python package into its subdirectory

Creates the wheelfile and tar.gz versions of your package in the dist directory

Publishes the package to PyPI; to confirm, you enter your username and password when prompted

Note that you can’t upload the specific name mypackage to PyPI. I suggest prefacing your package name with your username or initials, unless you intend to publish it for public consumption.

You could add plenty of other steps to the ones I’ve listed--for example, you can (and should) edit the pyproject.toml configuration file, in which you describe your package’s version, license, and dependencies. But creating a distribution package is no longer difficult. Rather, the hard part will be deciding what code you want to share with the community.

Summary

Modules and packages are easy to write and use, and help us to DRY up our code--making it shorter and more easily maintainable. This benefit is even greater when you take advantage of the many modules and packages in the Python standard library, and on PyPI. It’s thus no wonder that so many Python programs begin with several lines of import statements. As you become more fluent in Python, your familiarity with third-party modules will grow, allowing you to take even greater advantage of them in your code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset