My Python Notes
My Python Notes
Beginners
By John Reed
CODING ACADEMIA
© Copyright 2020 - All rights reserved.
The content contained within this book may not be reproduced, duplicated
or transmitted without direct written permission from the author or the
publisher.
Under no circumstances will any blame or legal responsibility be held
against the publisher, or author, for any damages, reparation, or monetary
loss due to the information contained within this book. Either directly or
indirectly.
Legal Notice:
This book is copyright protected. This book is only for personal use. You
cannot amend, distribute, sell, use, quote or paraphrase any part, or the
content within this book, without the consent of the author or publisher.
Disclaimer Notice:
Please note the information contained within this document is for
educational and entertainment purposes only. All effort has been executed
to present accurate, up to date, and reliable, complete information. No
warranties of any kind are declared or implied. Readers acknowledge that
the author is not engaging in the rendering of legal, financial, medical or
professional advice. The content within this book has been derived from
various sources. Please consult a licensed professional before attempting
any techniques outlined in this book.
By reading this document, the reader agrees that under no circumstances is
the author responsible for any losses, direct or indirect, which are incurred
as a result of the use of the information contained within this document,
including, but not limited to, errors, omissions, or inaccuracies.
Table of Contents
Introduction
CHAPTER 1. Setting Up your Environment
Installing Python on Windows
Exceptions
Capturing Import Errors
Unbinded Variables
Instructions
Expressions
Order of Operations
Module operator
Working with strings
Ask the user for an input value
Comments
Choose mnemonic variable names
Debug
Conditional execution
Boolean expressions
Logical operators
Conditional execution
Alternative execution
Chained Conditions
CHAPTER 4. Functions
Values returned by functions in Python
Passing parameters
Optional parameters
CHAPTER 5. Loops
For Cycle
Range
While Loop
Break and Continue
List
Automatic generation of lists of integers
Indexing of the elements of a list
Tuples
Indexing of the elements of a tuple
Classes
Methods
Self
Initialize Instances
Attributes
Modules
Creating a form
Importing a form
Manage calls to instructions
Standard modules in Python
Conclusion
Introduction
There are many reasons why I think everyone should be able to learn to
program:
It can simplify your daily life, a common cycle for example can
be much more powerful than you imagine.
It can become a job, even if it is well paid.
It helps you to reason logically, do not underestimate this aspect,
we are always surrounded by small problems, and learning to
rationalize is a skill you can always rely on.
A computer is a very powerful and at the same time very stupid tool: a
practically infinite amount of memory when compared with our brain, a
high calculation speed and moreover is not always bored doing the same
thing (for a human being it would be instead impossible). What you have to
do to use his potential is to learn to "communicate with him", and this can
be achieved through the knowledge of programming languages.
To really learn something, you must like it. Learning to programming must
become a hobby for you, such as going for a walk or playing the guitar.
Initially you will write programs for yourself, to simplify what your current
needs are; when you get good enough you can start writing code for
someone else, and start working by programming in Python.
In the rest of this book I will teach you all the tools to become a
professional programmer. Of course it cannot be an exhaustive book, any
book is exaustive and this is even more true in programming. What I can
teach you is all the knowledge to be able to walk alone, deepen and become
an ever better programmer, and perhaps ... the best, day after day.
Reading this book, studying it, writing codes with him is only a matter of
time before "the light will turn on". This is undoubtedly the best time, you
will begin to understand the wonderful world behind programming and you
will write codes all day because you want to learn the next step as fast as
you can, in short, the computer not obtained for you more secrets, you will
be able literally to do anything with it.
CHAPTER 1. Setting Up your
Environment
The first thing you need to do with Python is to install it.
If you are using an account on a remote server, your ISP may have already
installed Python 3. If you are using Linux at home, you may already have
Python 3 in this case too. Most popular GNU / Linux distributions include
Python 2 in the own default installation; the number of distributions that
also include Python 3 is limited, but steadily increasing. Mac OS X includes
a command line version of Python 2, but at the time of writing it does not
include Python 3. Microsoft Windows does not include any version of
Python. But don't despair! You can pave the way towards installing Python
with a mouse click, regardless of which operating system you use.
The easiest way to check if you have Python 3 on your Linux or Mac OS X
system is to use the command line. On Linux, look for a program called
Terminal in your Applications menu. (It could be in a submenu like
Accessories or System Tools.) On Mac OS X, there is an application called
Terminal.app in your / Applications / Utilities / folder.
Once you are at the command line prompt, simply type python3 (all in
lowercase, no spaces) and see what happens. On my home Linux system
Python 3 is already installed, so this command brings me into the
interactive Python shell.
mark@atlantis:~$ python3
Python 3.0.1+ (r301:69556, Apr 15 2009, 17:25:52)
[GCC 4.3.3] on linux2
Digit "help", "copyright", "credits" o "license" for further informations.
>>>
So going back to the question this section started with, "Which Python do
you need?" Whatever is already installed on the computer you have.
Installing Python on Windows
Today Windows is distributed for two architectures: 32 bit and 64 bit. Of
course, there are many different versions of Windows - XP, Vista, Windows
7 - but Python works on all of them. The most important distinction is
between 32 bit and 64 bit. If you have no idea which architecture you are
using, it is probably 32-bit.
I prefer not to provide you with direct links to download installers, because
minor Python updates are released at all times and I don't want to be
responsible for making you miss any important updates. You should always
install the latest version of Python 3.x unless you have some dark reason for
not doing so.
Double-click
the .msi file when the download is complete. Windows will present you
with a security warning while you are about to start an executable file. The
official Python installer is digitally signed by the Python Software
Foundation, the nonprofit company that oversees the development of
Python. Beware of imitations!
First, the installer will ask you if you want to install Python 3 for all users
or just you. The default choice is "install for all users" (which is "install for
all users"), which is best unless you have a good reason to choose
otherwise. (One of the possible reasons why you might prefer "install just
for me" is that you are installing Python on your company's computer and
you do not have administrative rights on your Windows account. But then
why are you installing Python without the administrator's permission
Windows of your company? Don't let me have this problem!)
• Tcl / Tk is the graphics library used by Shell Python that you will use
throughout this book. I highly recommend keeping this option
checked.
• Documentation installs a help file that contains much of the
information found on docs.python.org. Recommended if you have a
dial-up connection or limited Internet access.
• Utility Scripts includes the 2to3.py script which you will learn about
later in this book. This script is necessary if you want to learn how to
convert existing Python 2 code to Python 3.
If you don't have existing Python 2 code, you can leave this option out.
Suite Test Suite (test series) is a collection of scripts used to test the Python
interpreter. We will not use it in this book, nor have I personally used it in
Python programming activities. Completely optional.
If you are not sure how much free space you have on disk, click on the Disk
Usage button. The installer will list your disks and calculate both how much
space is available on each and how much space would remain after
installation. Click the OK button to return to the "Customizing Python"
screen (ie "Customize Python").
If you
decide to exclude an option, click on the button to the left of the option and
select "Entire feature will be unavailable" (ie "The entire function will not
be available") from the drop-down list that will appear. For example,
excluding tests will save the incredible 7908 KB disk space. Click on the
Next button to confirm your choice of options.
The installer will copy all the necessary files to the destination directory
you have chosen. Click on the Finish button to exit the installer. There
should be a new element in your Start menu called Python 3.1.
Inside, there is a program called IDLE. Select this item to launch the
interactive Python Shell.
Your browser should automatically mount the disk image and open a Finder
window to show you its contents. (If this does not happen, you will have to
find the disk image in the folder where you downloaded it and double click
on it to mount it. Its name should be something like python-3.1.dmg.) The
image disk contains a number of text files (Build.txt, License.txt,
ReadMe.txt) and the actual installation package, called Python.mpkg.
Like all the best installers, the Python installer shows you the software
license agreement. Python is open source and its license is approved by the
Open Source Initiative. Python has had a number of owners and sponsors
throughout its history, each of which has left its mark on the software
license. But the end result is this: Python is open source and you can use it
on any platform, for any purpose, without paying anything and without
having any reciprocity obligation.
Since Python is open source, you are actually "accepting" that the license
grants you additional rights rather than depriving you of them.
From this screen you can also customize the installation to exclude some
features. If you want to do this, click on the Customize button, otherwise
click on the Install button.
If you choose a customized installation, the installation program will show
you the following list of features:
• Python Framework (Python framework). This is the heart of Python
and is both selected and disabled because it must necessarily be
installed. GUI Applications includes IDLE, the graphical Shell Python
that you will use throughout this book. I highly recommend keeping
this option checked.
• UNIX command-line tools (UNIX command line tools) includes the
python3 command line application. I highly recommend keeping this
option as well.
• Python Documentation contains much of the information found on
docs.python.org. Recommended if you have a dial-up connection or
limited Internet access. Shell profile updater checks whether to update
your shell profile (used in Terminal.app) to make sure that this version
of Python is the one contained in your shell's search path. You
probably don't need to change this setting.
• Fix system Python (correction for the system Python interpreter)
should not be changed. (Tells your Mac to use Python 3 as the default
Python interpreter for all scripts, including Apple's installed system
scripts. This would be a real disaster, as many of those scripts were
written for Python 2 and would not run correctly. from Python 3.)
Assuming everything went well, the installer will show you a large green
tick to let you know that the installation was successfully completed. Click
on the Close button to exit the installation program. Assuming that you
have not changed the installation path, you can find the newly installed files
in the Python 3.1 folder inside your / Applications folder.
The most important element is IDLE, the graphical Shell Python. Double
click on IDLE to launch the Python Shell.
Using Shell Python
Shell Python is the place where you can explore Python syntax, get
interactive help on commands and debug small programs. The Graphical
Shell Python (called IDLE) also contains a decent text editor that supports
coloring of Python syntax and integrates with the Python Shell. If you don't
have your favorite editor yet, you should try using IDLE.
Let's start from the beginning. Shell Python itself is a wonderful interactive
playing field. In this book, you will see examples like this:
>>> 1 + 1
2
The three angle brackets, >>>, denote the Shell Python prompt. That part
only serves to let you know that this example is meant to be followed in the
Shell Python, so it should not be typed.
1 + 1 is the part you need to type. You can type any valid Python expression
or any command in the Python Shell. Don't be shy, it won't bite you! The
worst that could happen to you is getting an error message. The commands
are executed immediately (as soon as you press ENTER); expressions are
evaluated immediately and Shell Python prints the result.
2 is the result of the evaluation of this expression. It turns out that 1 + 1 is a
valid Python expression. The result, of course, is 2.
Let's try another one.
Pretty simple, isn't it? But you can do much more in Shell Python. If you
ever get stuck - can't remember a command, or can't remember the
appropriate arguments to pass to a certain function - you can get interactive
help in Shell Python. Just type in help and press ENTER.
>>> help
Type help () for interactive help, or help (object) for help on object. There
are two ways to help. You can get help on a single object by simply printing
the documentation and returning immediately to the Shell Python prompt.
You can also enter the help mode, where instead of evaluating Python
expressions, type keywords and command names and get all the known
information about those commands printed. To enter interactive help mode,
type help () and press ENTER.
>>> help()
Welcome to Python 3.0! This is the online help mode. If this is your first
time using Python, you should definitely give it take a look at the tutorial at
http://docs.python.org/tutorial/ .
Type the name of any module, keyword, or topic for get help on writing
Python programs and using Python modules. To exit this help mode and
return to the interpreter, vi just type "quit". To get a list of available
modules, keywords, or topics, type "modules", "keywords", or "topics".
Each module is equipped with a brief summary of its functions; to list the
modules whose summaries contain a certain word like "spam", type
"modules spam".
help>
Notice how the prompt changes from >>> to help>. This reminds you that
you are in interactive help mode. Now you can enter any keyword,
command, module name, function name - just about anything Python can
understand - and read the related documentation.
help> PapayaWhip
help> quit
You are exiting help mode and returning to the Python interpreter.
If you want to ask for help directly on a particular object from within the
interpreter, you can type
has the same effect as typing a particular string at the help mode prompt.
4. The prompt will return to >>> to let you know that you have
exited interactive help mode and returned to Shell Python. IDLE,
the Graphical Python Shell, also includes a text editor for Python.
CHAPTER 2. Let’s start
programming
As with most programming books, the convention would require you to
start with a series of boring chapters on fundamentals and then gradually
build something useful. We will spare ourselves this wait. Below you will
immediately find a complete and functional Python program. It probably
doesn't make any sense to you now, but don't worry because you're going to
analyze it line by line. However, try to read it, first of all, to see if you can
get anything out of it.
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
'' 'Convert the size of a file into a readable form.
Look at the bottom of the program and you will see two calls to print
(approximate_size (arguments)). These are function invocations - they first
call the approximate_size () function by passing it a number of arguments,
then take the return value and pass it directly to the print () function. The
print () function is predefined, so you will never see its explicit declaration.
You can simply use it anytime, anywhere. (There are many predefined
functions and many other functions that are divided into modules. Be
patient, grasshopper.)
So why does running the script from the command line return you the same
results every time? We will get there. First of all, let's take a look at the
approximate_size () function.
Declare Functions
Python allows you to write functions like most other languages, but it
doesn't use separate header files like C ++ or interface / implementation
sections like Pascal. When you need a function, simply declare it like this:
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
The def keyword begins the function declaration, followed by the function
name, followed by the function arguments enclosed in parentheses. Topics
are separated by commas. Note also that the function does not define a
return data type.
Python functions do not specify the data type of their return value, nor do
they specify whether or not they return a value. (In fact, each Python
function returns a value: if the function executes a return statement, it will
return that value, otherwise it will return None, the null value of Python.) In
some languages, functions (which return a value) begin with function and
procedures (which do not return a value) begin with sub. There are no
procedures in Python.
There are only functions, all functions return a value (even if it is None) and
all functions begin with def. The approximate_size () function takes two
arguments - size and a_kilobyte_is_1024_bytes - but no argument declares
its type. In Python, variables are never explicitly typed. The Python
interpreter understands for itself what the type of a variable is and tracks it
internally. In Java and other statically typed languages, you must declare the
type of the return value and each argument of the function. In Python, types
are never declared. Based on the value that is assigned, Python keeps track
of the data type internally.
5. This invocation also fails, for the same reason as the previous
one. Are you surprised? After all, you passed 4000 as the value
for the argument called size, then "obviously" you meant to pass
that False value to the argument a_kilobyte_is_1024_bytes. But
Python doesn't work this way. As soon as you use a named
argument, all the arguments to the right of that argument must
also be named arguments.
Documentation Strings
You can document a Python function by adding a documentation string
(called docstring for brevity). In our program, the approximate_size ()
function has been equipped with a docstring:
Triple quotes are also an easy way to define a string that contains both
quotes and quotes, such as qq /.../ in Perl 5.
Before continuing, I want to briefly mention the search path for the
libraries. Python looks in several places when you try to import a module.
Specifically, look in all directories defined in sys.path. This attribute is
simply a list and you can easily view or edit it with the standard list
methods. (You will learn more about lists in the chapter on native data
types.)
1. Importing the sys module makes all its functions and attributes
available.
4. You can add a new directory to the Python search path at runtime
by adding the directory name to sys.path; subsequently, Python
will also look in that directory every time you try to import a
module. The effect lasts as long as the Python interpreter is
running.
Everything is an Object
In case you missed it, I just said that Python functions have attributes and
that these attributes are available at runtime. A function, like everything
else in Python, is an object.
Launch the interactive Python shell and follow me through this series of
instructions:
Returns: string
What is an Object?
You may have heard the term "first class object" in other programming
contexts. In Python, functions are first class objects. You can pass a
function as an argument to another function. Modules are first class objects.
You can pass an entire module as an argument to a function. Classes are
first-class objects, and individual instances of a class are also first-class
objects.
This concept is important, so I'll repeat it in case you missed it the first few
times: everything in Python is an object. Streaks are objects. Lists are
objects. Functions are objects. Classes are objects. Instances of a class are
objects. Even modules are objects.
Exceptions
What is an exception? It is usually a mistake, an indication that something
has gone wrong. (Not all exceptions are errors, but don't worry about this
for now.) Some programming languages encourage the use of return error
codes, which are checked. Python encourages the use of exceptions, which
are handled.
When an error occurs in the Shell Python, some details are printed on the
exception and how it occurred, and that's all. This is called an unhandled
exception. When the exception was raised, there was no instruction to
explicitly notice and address it, so it bubbled up to the level of Shell
Python, which spits out some debug information and considers its job
finished. In the shell this is not a big problem, but if it happened while your
Python program is running, the whole program would crash if the exception
is not handled. Maybe this is the behavior you want, maybe it isn't.
Unlike Java, Python functions do not declare which exceptions they might
raise. It's up to you to determine what possible exceptions you need to
catch. An exception does not necessarily have to result in a complete block
of the program, however. Exceptions can be handled. Sometimes an
exception appears because your code actually has a bug (like trying to
access a variable that doesn't exist), but other times an exception is
something you can anticipate.
If you are opening a file, that file may not exist. If you are importing a
module, that module may not be installed. If you are opening a connection
to a database, that database may not be available, or you may not have the
correct security credentials to log in. If you know that a line of code could
raise an exception, you should handle the exception using a try ... except
block. Python uses try ... except blocks to handle exceptions and the raise
statement to throw them. Java and C ++ use try ... catch blocks to handle
exceptions and the throw statement to throw them.
The syntax for raising an exception is quite simple. Use the raise statement,
followed by the name of the exception and a string containing a message for
debugging purposes. The syntax recalls that of the invocation of a function.
(In fact, exceptions are implemented as classes and this raise statement
actually creates an instance of the ValueError class by passing the string 'the
number must not be negative' to its initialization method. But we are putting
the cart ahead of the oxen!)
You don't need to manage an exception in the function that raises it. If a
function does not handle an exception, the exception is passed to the calling
function, then to the function that called that function, and so on "to the top
of the execution stack". If the exception is never handled, your program will
crash, Python will print a "stack trace" on the error channel and things will
end there. Again, perhaps this is the behavior you desire; it depends on what
your program does.
Later, you can check for the presence of the chardet module with a simple if
statement:
if chardet:
# do something
else:
# continue anyway
At the end of this try..except block you have imported some module and
called it etree. Since both modules implement a common API, the rest of
your program doesn't have to check every time which module was
imported. And since the module that was imported is always called etree,
there is no need to spread if statements anywhere in the rest of your
program to call modules with different names.
Unbinded Variables
Never declare the multiple variable, but simply assign it a value. This is
fine, because Python allows you to do it. What Python doesn't allow you is
to refer to a variable that has never been assigned a value. The attempt to do
this will raise a NameError exception.
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x = 1
>>> x
1
And so on.
But you can also run the module directly as a separate program, in which
case __name__ will be the special default value __main__. In our example,
Python will evaluate the if statement, find a true expression and execute the
corresponding block of code. In this case, to print two values.
1.0 TB
931.3 GiB
If you are not sure which type a specific value belongs to, you can consult
the interpreter.
It is not surprising that the strings belong to the str type and the integers
belong to the int type. It is less obvious that numbers with a decimal point
belong to the type called float. This is due to the fact that these numbers are
represented in a format called floating point.
>>> type(3.2)
<class 'float'>
And what about values like "17" and "3.2"? While looking like numbers are
enclosed in quotation marks like strings.
>>> type('17')
<class 'str'>
>>> type('3.2')
<class 'str'>
In reality they are real strings. When entering a large integer, such as
"1,000,000", you may be tempted to use commas in groups of three digits.
This is not an integer allowed in Python, although it appears to be spelled
correctly:
>>> print(1,000,000)
100
Variables
One of the most powerful features of a programming language is the ability
to manipulate variables. A variable is a name assigned to a value. Through
an assignment instruction you have the ability to create new variables and
assign them a value:
>>> message = 'And now for something completely different'
>>> n = 17
>>> pi = 3.1415926535897931
In this example, three assignments are made: the first assigns a string to a
new variable called message, the second assigns the integer 17 to the
variable n, the third assigns the (approximate) value of π to pi. You can use
the print statement to view the value of a variable:
>>> print(n)
17
>>> print(pi)
3.141592653589793
The name 76trombones is not valid because it starts with a number, more
@, instead, because it contains the illegal character '@'. But what's wrong
with class? It turns out that class is one of Python's reserved words. The
interpreter uses these words to recognize the structure of the program,
therefore they cannot be assigned to variables. Python reserves 33
keywords:
and del from None True as elif global nonlocal try assert else if not while
break except import or with class False in pass yield continue finally is
raise def for lambda return
It is better to keep this list handy: if the interpreter complains about the
name of one of your variables and you do not understand why, check if it is
present in the list.
Instructions
The instruction is a minimum unit of code that can be executed by the
Python interpreter. We have seen two types of instructions: Print used both
as an expression instruction and as an assignment. When you type an
instruction in interactive mode, the interpreter executes it and, if it exists,
displays the result. Generally a script contains a sequence of instructions. If
there is more than one instruction, the results are displayed one at a time as
the instructions are executed. Eg:
print(1)
x=2
print(x)
produce the output
1
2
In the transition between Python 2.x and Python 3.x the division operator
has been changed: now the result is represented in floating point:
>>> minute = 59
>>> minute/60
0.9833333333333333
In Python 2.x the operator would have divided the two integers and
truncated the result by returning an integer value:
>>> minute = 59
>>> minute/60
0
To achieve the same result in Python 3.x, the integer division (// integer)
must be used.
>>> minute = 59
>>> minute//60
0
In Python 3.x the integer division works much more similarly to what you
would expect if you entered the expression on a calculator.
Expressions
The expression is a combination of values, variables and operators. Both a
single value or a variable are considered an expression. Therefore the
following are all correct expressions (provided that a value has been
assigned to the variable x)
17
X
x + 17
Order of Operations
Module operator
The module operator is applied to whole numbers and results in the
remainder of when the first operand is divided by the second. In Python, the
modulo operator is the percentage character (%). The syntax is the same as
for the other operators:
>>> quotient = 7 // 3
>>> print(quotient)
2
>>> remainder = 7 % 3
>>> print(remainder)
1
>>> first = 10
>>> second = 15
>>> print(first+second)
25
>>> first = '100'
>>> second = '150'
>>> print(first + second)
100150
The output of this script is 100150. The * operator also works with strings
by multiplying the contents of a string by an integer. For example:
>>> first = 'Test '
>>> second = 3
>>> print(first * second)
Test Test Test
Before receiving input from the user, it is usually a good idea to display a
prompt that informs the user what to enter. It is possible to indicate a string
to the input function a ché until it is displayed before the input waiting
pause:
>>> name = input('What is your name?\n')
What is your name?
Chuck
>>> print(name)
Chuck
The sequence \ n at the end of the prompt indicates a carriage return and is a
special character that causes the line to be interrupted. That's why user input
appears below the prompt. If you expect the user to type an integer, you can
try converting the return value to int using the int () function.
>>> prompt = 'What...is the airspeed velocity of an unladen swallow?\n'
>>> speed = input(prompt)
What...is the airspeed velocity of an unladen swallow?
17
>>> int(speed)
17
>>> int(speed) + 5
22
But if the user enters something other than a string consisting of digits, an
error message is displayed:
>>> speed = input(prompt)
What...is the airspeed velocity of an unladen swallow?
What do you mean, an African or a European swallow?
>>> int(speed)
ValueError: invalid literal for int() with base 10:
Comments
As programs get bigger and more complex, they become more difficult to
read. Formal languages are condensed and it is often difficult to examine a
piece of code and understand what or why it does something. For this
reason, it is a good idea to add some notes to your programs to explain in
natural language what the program is doing. These notes, which in Python
begin with the # symbol, are called comments:
# compute the percentage of the hour that has elapsed
percentage = (minute * 100) / 60
In this case, the comment appears alone on one line. You can also insert
comments at the end of a line:
percentage = (minute * 100) / 60 # percentage of an hour
Anything between "#" and the end of the line is ignored and has no e etto
ect on the program. Comments are even more useful when documenting not
so obvious code features. While it is reasonable to assume that code readers
can understand what this does, it is far more useful to explain why. This
code comment is superfluous and unnecessary:
v = 5 # assign 5 to v
v = 5 # velocity in meters/second.
Assigning suitable names to variables can reduce the need for comments,
but long names can make complex expressions difficult to read, so there is a
tradeoff.
Python interprets all three in exactly the same way as we humans read and
understand these programs quite differently. The purpose of the second
example is quickly understood since the developer has chosen the name of
the variables thinking about what data will be stored in each of them. We
call these wisely chosen variable names "mnemonic variable names".
This is because novice developers have not yet memorized the reserved
words (there are only 33) and sometimes variables with too descriptive
names begin to seem part of the language and not just well-chosen variable
names. Take a quick look at the following Python sample code which runs
repeatedly (looped) on some data. We'll get back to the loops soon, but for
now, try to understand what it means:
What is happening? Which words (for, word, in, etc.) are reserved words
and which are only variables? Can Python understand the notion of words
fundamentally? Beginner programmers have a hard time distinguishing
which parts of the code should remain unchanged, like this example, and
which parts of the code are simply choices made by the developer. The
following code is equivalent to the previous one:
for slice in pizza: print(slice)
It is easier for the novice programmer to read this script to know which
parts are reserved words of Python and which parts are simply variable. It is
quite clear that Python does not know the notion of pizza and slice (slice)
and that a pizza is made up of a set of one or more slices. But if our
program is really about reading data and searching for words in the data,
pizza and slices are by no means mnemonic variable names. Choosing them
as variable names distracts us from the purpose of the program.
After a short period of time, you will know the most common reserved
words and they will begin to catch your eye: The parts of the code de fi ned
by Python (for, in, print, and :) are bold, contrary to the variables chosen by
the developer (word and words). Many text editors recognize Python syntax
and color reserved words differently by highlighting them with respect to
variables. After a little practice in reading Python you will be able to
quickly understand which is a variable and which is a reserved word.
Debug
At this point, the most likely syntax error you can make is choosing an
illegal variable name, such as class and yield, which are keywords, or odd ~
job eUS $, which contain illegal characters. If you enter a space in the
variable name, Python will assume that they are two operands without an
operator:
>>> bad name = 5
SyntaxError: invalid syntax
>>> month = 09
File "<stdin>", line 1
month = 09 ^
SyntaxError: invalid token
As for the syntax errors, it must be said that the error messages are not of
great help. The most common messages, SyntaxError: invalid syntax and
SyntaxError: invalid token, are both not very explanatory. The most
common runtime error is "use before def;": that is, the use of a variable
before assigning it a value. This can happen if a variable is written
incorrectly:
>>> principal = 327.68
>>> interest = principle * rate
NameError: name 'principle' is not defined
Variable names are case-sensitive: LaTeX is not the same as latex. At this
point, the most likely cause of a semantic error is the order of operations.
For example, to calculate 1 / 2π, you may be tempted to write:
>>> 1.0 / 2.0 * pi
Since the division is done first, you will get π / 2 which is not the same
thing! Since Python has no way of knowing what I really wanted to write,
you will not receive an error message but only an incorrect result.
Conditional execution
Boolean expressions
True and False are not considered strings but are special values belonging to
the bool type:
>>> type(True)
<class 'bool'>
>>> type(False)
<class 'bool'>
x != y # x is not equal to y
x > y # x is greater than y
x < y # x is less than y
x >= y # x is greater than or equal to y
x <= y # x is less than or equal to y
x is y # x is the same as y
x is not y # x is not the same as y
Although these operations are likely to be familiar to you, the symbols used
by Python are different from the mathematical ones. A common mistake is
to use a single equal sign (=) instead of a double equal sign (==):
Remember that = assigns a value while == compares two values. There is
currently no operator similar to = <or =>.
Logical operators
There are three logical operators: and, or and not. The semantics (meaning)
of these operators is similar to their meaning in the English language. For
example: x> 0 and x <10 is TRUE only if x is greater than 0 and less than
10. n% 2 == 0 or n% 3 == 0 is TRUE if one of the conditions occurs: that
is, if the number it is divisible by 2 or 3. Finally, the not operator negates a
Boolean expression, so not (x> y) is true if x> y is false; that is, if x is less
than or equal to y. In practice, the operands of the logical operators should
be Boolean expressions, even Python is not very rigorous in this regard.
Any non-zero number is interpreted as "true":
While this flexibility may come in handy, there are a few details that could
be confusing. Unless you know what you are doing, you should avoid such
an event.
Conditional execution
To write useful programs, we almost always need to check the conditions
and change the behavior of the program accordingly. Conditional
statements give us this ability. The simplest form is the if statement:
if x > 0 :
print('x is positive')
If you enter an if statement in the Python interpreter, the prompt will change
from three chevron to three points to signal that you are in the middle of a
block of instructions, as shown below:
>>> x = 3
>>> if x < 10:
... print('Small')
... Small
>>>
Alternative execution
A second form of the if statement is the alternative execution in which two
possibilities have been foreseen and the condition determines which should
be performed. The syntax looks like this:
if x%2 == 0 :
print('x is even')
else :
print('x is odd')
Chained Conditions
if x < y:
print('x is less than y')
elif x > y:
print('x is greater than y')
else:
print('x and y are equal')
elif is an abbreviation for "else if". Again, only one branch will run. There
is no limit to the number of elif instructions. Various else conditions can be
used, as long as they are inserted at the end.
if choice == 'a':
print('Bad guess')
elif choice == 'b':
print('Good guess')
elif choice == 'c':
print('Close, but not correct')
When the Python interpreter executes these instructions, a new prompt will
appear, as if Python had thought "oops" and had moved on to the next
instruction. However, if you insert this code into a Python script and this
error occurs, the script immediately stops displaying a traceback, refusing
to execute the next statement. This is an example script to convert a
temperature from Fahrenheit to Celsius:
If we run this code and supply it with invalid values, it will simply fail by
showing an unfriendly error message:
python fahren.py
Enter Fahrenheit Temperature:72
22.22222222222222
python fahren.py
Enter Fahrenheit Temperature:fred
Traceback (most recent call last):
File "fahren.py", line 2, in <module>
fahr = float(inp)
ValueError: could not convert string to float: 'fred'
python fahren2.py
Enter Fahrenheit Temperature:fred
Please enter a number
Handling an exception with a try statement is called "catching an
exception". In this example, the condition except shows an error message.
In general, catching an exception gives you the opportunity to solve the
problem or try again, or at least end the program elegantly.
CHAPTER 4. Functions
Functions are a very useful tool in Python (and in general in any
programming language). Splitting a program into functions may seem
unnecessary effort, but instead it is very beneficial. Focus on the following
points, which expose the ventures in dividing a program into functions:
As you can see the par function accepts a single parameter, named n.
Let's try to write a function that returns the factorial number of any number
passed as a parameter.
Let's try to type now in IDLE fact followed by the round parenthesis as in
the figure:
We can see the help window (the so-called "helper") which is automatically
shown to us and which includes the list of parameters necessary for the
function.
def f1 ():
pass
def f2 ():
return
def f3 ():
return None
We can verify it in IDLE:
We probably have often had to make the function return more than one
value.
In these cases, with languages other than Python, various escamotages had
to be used: such as passing parameters by reference, returning values to an
array and so on.
With Python we just need to return and contextually assign two or more
values.
Let's clarify with an example:
But there are other features and modes for passing parameters that allow us
to define functions in Python in an extremely versatile and powerful way.
Optional parameters
For each parameter we can define an optional default value: in the absence
of the respective parameter, the function will use the default value. Let's try
to type the sequence "int (" in IDLE and wait, as you can see in the
following figure, for the helper to appear:
We see that the int function accepts one or two parameters: x and base.
Given the second suggestion, we can guess that the base parameter is an
optional parameter.
>>> f = stamp
>>> f(“hello”)
Hello
>>>
For Cycle
The for loop allows us to iterate over all the elements of an iterable and
execute a certain block of code. An iterable is any object capable of
returning all the elements one after the other, such as lists, tuples, sets,
dictionaries (return the keys), etc.
• after the colon there is a block of indented code (which can also be
made up of several lines);
• the loop iterates over all the elements of the sequence, assigns them to
the variable n, and executes the block of code;
• in this example the variable n will assume the values of 1, 2, 3, 4, and
5 and for each value it will print the square;
• once the code block has been executed for all values, the for loop
ends.
• the for loop is introduced by the keyword for, followed by a variable,
the keyword in, an iterable, and finally the colon (:);
Again the code block is executed 5 times, one for each value of the
sequence.
Those familiar with other languages will have noticed that in Python the
for loop does not use indexes that are manually incremented (as in C, for
example), but is rather more similar to constructs such as foreach.
Range
Since it often happens to want to work on sequences of numbers, Python
provides a built-in function called range that allows you to specify an initial
or start value (included), a final or stop value (excluded), and a step, and
which returns a sequence of integers:
>>> range (5) # returns a range object with start equal to 0 and stop equal to 5
range (0, 5)
>>> list (range (5)) # converting it to a list we can see the values
[0, 1, 2, 3, 4]
>>> list (range (5, 10)) # with 2 arguments you can specify the start and stop
[5, 6, 7, 8, 9]
>>> list (range (0, 10, 2)) # with 3 arguments you can also specify the step
[0, 2, 4, 6, 8]
This function is particularly useful when combined with the for loop:
range can also be used in combination with the for loop if we want to repeat
a block of code a fixed number of times:
>>> # print 'Python' 3 times
>>> for x in range (3):
... print ('Python')
... Python Python Python
In this case, a behavior more similar to the "traditional" for (like that of C)
is obtained and the variable x is not used.
While Loop
>>> # remove and print numbers from seq until only 3 remain
>>> seq = [10, 20, 30, 40, 50, 60]
>>> while len (seq)> 3:
... print (seq.pop ())
...
60
50
40
>>> seq
[10, 20, 30]
In Python this construct does not exist, but obtaining an equivalent result is
very simple:
>>> # ask the user to enter numbers as long as you guess
>>> n = 8
>>> while True:
... guess = int (input ('Enter a number from 1 to 10:'))
... if guess == n:
... print ('You guessed it!')
... break # guessed number, break the cycle
... else:
... print ('Retry you will be luckier')
... Please enter a number from 1 to 10: 3
Try again you will be luckier
Please enter a number from 1 to 10: 5
Try again you will be luckier
Please enter a number from 1 to 10: 8
You guessed!
In this example, the while loop is used to ask for numbers until the user
guesses the correct number (8). The condition used is simply True, and
since it can never become false, an infinite loop is created. The cycle is
actually interrupted when the user guesses the number, using an if and the
keyword break.
Break and Continue
Python has 2 constructs that can be used in the for and while loops:
• break: interrupts the cycle;
• continue: interrupts the current iteration and proceeds to the next.
For example, we can use a for loop to search for an element in a list and
stop the search as soon as the element is found:
>>> seq = ['alpha', 'beta', 'gamma', 'delta']
>>> for elem in seq:
... print ('I'm checking', elem)
... if elem == 'range':
... print ('Item found!')
... break # element found, break the cycle
... I am checking alpha
I am checking beta
I am checking gamma
Item found!
In this example, however, we use continuous to "jump" the words that have
5 letters. From the output you can see that the if condition is true for
"alpha", "gamma", and "delta", and in these cases the iteration proceeds
immediately with the next element without printing. Only in the case of
'beta' (which has 4 letters), the continue is not performed and the element is
printed.
for-else and while-else
A peculiarity of Python is the ability to add an else to the for and while. The
block of code in the axis is performed if the cycle ends all the iterations. If,
on the other hand, the cycle is interrupted by a break, the else is not
performed. The syntax is similar to the one we have already seen with the
if: the else must be indented at the same level as the for / while, it must be
followed by a colon (:) and an indented block. Let's see an example where
we give the user 3 attempts to guess a number:
>>> n = 8
>>> for x in range (3):
... guess = int (input ('Enter a number from 1 to 10:'))
... if guess == n:
... print ('You guessed it!')
... break # guessed number, break the cycle
... else:
... print ('Attempts finished. You didn't guess')
...
Note that even if the axis follows the if, the indentation corresponds to that
of the for: it is therefore a for-else, not an if-else. If the user is able to guess
the number, the if condition is fulfilled and the break is performed. In this
case the for else is not executed because the for loop has been interrupted:
If, on the other hand, the user is unable to guess the number in 3 attempts,
the for loop ends all the iterations and the for else is performed.
The syntax for the creation of the dictionaries is simple, in fact one can be
defined by delimiting with the square brackets of the pairs formed each by a
key associated with the respective value through the ":" operator and
separated by a comma. The values of the pairs of a dictionary can be
associated with any type of data and be present more than once, the keys
instead must be unique and their type immutable.
# Dictionaries definition
nome_dict = {1: 'homer', 2: 'bart'}
>>> nome_dict
{1: 'homer', 2: 'bart'}
The main difference between the first methodology and the one based on
get () lies in the fact that the method does not return anything if a
nonexistent key is passed to it as an argument, with "dict_name
['nonexistent_key_name']" an error would instead be generated .
Change the elements of a dictionary
To modify an element of a dictionary it is sufficient to associate a new value
to the key of a pair:
# Modify an element of a dictionary
>>> name_nict = {1: 'euro', 2: 'dollar', 3: 'pound'}
>>> dict_name
{1: 'euro', 2: 'dollar', 3: 'pound'}
>>>ict_name [2] = 'US dollar'
>>> dict_name
{1: 'euro', 2: 'US dollar', 3: 'pound'}
The popitem () method works similarly to pop () but with the difference that
it does not accept any parameter, in practice, by calling this method the
Python interpreter arbitrarily chooses the key / value pair to be eliminated:
Finally, the () function works like the pop () method when the key of a pair
is passed as an argument, but it can also be used to permanently delete a
dictionary:
List
In Python it is possible to define a list, to which a name can be attributed,
inserting elements in square brackets ("[..]"). Those who already work with
other languages for programming or development will certainly know
arrays, or "vectors", which are variables intended to contain further
variables; syntactically and conceptually the lists can remember arrays, but
their functioning has some peculiarities that make them different.
Basically a list can exist but be empty, that is, not present any element
inside it:
Just as you can create lists that present elements of different nature:
Finally, the creation of nested lists is also allowed, i.e. lists that have other
lists among their elements.
[1, 2, 3, 4, 5, 6, 7]
These elements will be the result of the call to the range () function which
will evaluate the two arguments of the range by returning a list containing
all the integer values starting from the first, included in the list, up to the
second, excluded from the list instead.
When, on the other hand, we pass the function an integer as in the example
below:
The elements present will therefore be 8, placing the "0" as an element and
(not) initial value.
In this case, the element called will be "d", ie the fourth inserted in the list,
this is because "a" is associated with the index "0", "b" to "1", "c" to "2"
and di consequence "d" has as index "3".
Access to the elements in the list could also take place through negative
indexing, where the last element will have the index "-1", the penultimate
"-2" and so on. A call like the following will therefore have the result of
allowing access to the "a" element.
# Access to an element of a list
# through the negative index
# definition of the elements in the list
>>> list_name = ['a', 'b', 'c', 'd', 'e']
# access to element with index "-5"
>>> list_name [-5]
will allow access to the elements "a", "b", ie those whose index goes from
"0" to "2" (excluded). The colon symbol (":"), previously used for the
definition of the interval, is called slicing operator. It can also be used for
other purposes, such as defining the index from which to start for data
access:
# Access to multiple elements of a list
# starting from a specific index
# definition of the elements in the list
>>> list_name = ['a', 'b', 'c', 'd', 'e']
# access to the first element in the list ('a') via negative index
# the last 4 elements will be excluded
>>> list_name [: - 4]
# access from the third element to the last
# 'c', 'd' and 'e'
>>> list_name [2:]
# access to all items in the list
>>> list_name [:]
As described in the next chapter, Python has constructs that allow you to
perform more advanced operations than simply accessing values, such as
those dedicated to manipulating lists.
Tuples
As anticipated, tuples are constructs which, as with lists, can contain a
collection of elements; the substantial difference between the lists and the
tuples, however, lies in the fact that while in the former the elements that
the components must be replaced, in the tuples they become immutable.
The syntax for defining tuples requires that the elements to be inserted into
them are delimited by round brackets and associated with a name by
assignment (operator "=").
Basically, as already seen for the list, tuples can exist, and therefore have
been defined, but at the same time be empty and therefore do not have any
element inside:
# Example of empty tuple
tuple_name = ()
Always pay attention to the rule that to assign a single element to a tuple
requires that it be followed by a comma:
# Definition of a tuple with a single element
>>> tuple_name = ('Homer')
>>> type (double_name)
<class 'str'> # without the comma is not identified as a tuple
>>> tuple_name = ('Homer',)
>>> type (double_name)
<class 'tuple'>
In the event that a tuple is not empty, you will be asked to separate the
elements that make it up with a comma, you can therefore create tuples
intended to contain elements associated with a single type of data:
In the same way, tuples can be defined that present elements associated with
different types of data.
Finally, nested tuples can be generated, that is, tuples that have other tuples
among their elements.
The syntax of tuples also supports their creation without the use of round
brackets and, in this case, we are talking about an operation called tuple
packing:
# Tuple packing
triple_name = 5, 8.7, 'Bart'
As already observed for lists, tuples also require that their elements be
indexed numerically; indexing will therefore start from "0", which is why a
tuple consisting of only three elements will have "0", "1" and "2" as indices.
A certain element of a tuple can then be recalled through the reference
index:
In this case the element called will be "x", ie the third inserted in the tuple,
in fact "z" is associated with the index "0", "y" to "1" and consequently "x"
will have "2" as index. Note how the index was specified in square and non-
round brackets, taking up the same syntax as the lists.
An alternative procedure for accessing the elements of the tuple involves
exploiting negative indexing, in this case the last element will have the
index "-1", the penultimate "-2" and so on, exactly as for the lists. The
following call will, for example, allow access to the "y" element.
You can also access the elements of a list by defining a range of values; the
two components of the range will correspond to the index numbers, so an
expression like the one proposed below:
# Access to multiple elements of a tuple
# through an interval
# definition of the elements of the tuple
>>> tuple_name = ('z', 'y', 'x', 'w', 'v')
# access to elements with range "0: 3"
>>> list_name [0: 3]
will allow access to the elements "z", "y" and "x", that is to say those whose
index goes from "0" to "3" excluding the latter. The colon symbol (":") also
used in the lists for the definition of the interval, that is the already known
slicing operator, can also be adopted for different purposes, for example
with the aim of defining the index from which to start. to access the
elements of the tuple:
If you want to access an element of a tuple nested within another tuple, the
reference indices must also be nested:
The result of the call will be equal to "31", ie the second element (with
index "1") of the tuple which in turn represents the fourth element, with
index "3", of the tuple in which it is nested.
Classes
In this lesson we will see in more detail how to define classes, methods and
attributes, and how to use them. We will also see how to create instances
and subclasses Define classes The simplest class we can define in Python
is:
As we can see from the example, to define a class just use the class
keyword, followed by the name we want to give to the class (in this case
Test), followed by a colon (:), followed finally by a block of indented code (
in this case there is only the pass).
This syntax is similar to the one used to define functions, with the
difference that the keyword class is used instead of def and that the list of
arguments after the name is not present.
>>> Test
# Test refers to the class <class '__main __. Test'>
>>> Test ()
# Test () returns a new instance <__ main __. Test object at 0x7f87ed6a26d8>
>>> Test ()
# Test () returns a new instance <__ main __. Test object at 0x7f87ed6a26a0>
Copy Each call returns a new and separate instance, as can be seen from the
different ID of the two instances created in the example (0x7f87ed6a26d8
and 0x7f87ed6a26a0). Note that in Python 2 it is important to define classes
using the syntax class Test (object): ... to make them inherit from object. In
Python 3 all classes automatically inherit from object.
Methods
In the previous lesson we also saw that the methods are similar to functions
defined within the class:
• the definitions of the methods are found indented within the class;
• the syntax used to define the methods is the same as that used to
define the functions;
• the methods must define an additional parameter which is
conventionally called self;
• to call a method just use the instance.method () syntax.
Self
As noted in the previous example, the most important difference between
the definition of methods and functions is the presence of self. self is an
argument that refers to the instance, and even if the methods must explicitly
declare it, it is not necessary to pass it explicitly. Let's look at another
example to better understand how self works:
The reason why it is not necessary to explicitly pass self is that the
expression inst.method () is simply syntactic sugar for Test.method (inst):
Both ways produce the same result, but normally the second way
(inst.method ()) is used: when we call inst.method (), Python actually
automatically goes back to the inst class and executes Test.method (inst).
For this, each method defined in the class must accept self as the first
argument. Also note that self has nothing special or different from other
arguments (unlike other languages such as Java which uses the keyword
this to refer to the instance).
Since self refers to the instance, we can use it to access other attributes and
methods defined within the class simply by making self.attribute or
self.method ().
Initialize Instances
The classes also support several "special" methods which are identified by
the presence of two underscores before and after the name. These methods
are not called directly by making inst .__ method__, but are typically called
automatically in special situations One of these special methods is __init__,
automatically called each time an instance is created:
>>> Test ()
# when we instantiate, __init__ is called New instance created!
<__ main __. Test object at 0x7fef3ff76390>
Copy __init__ also has another peculiarity: the arguments passed during the
creation of the instance are received by __init__. This allows us to
automatically create different instances based on past topics:
>>>
# let's define a Dog class
>>> class Dog:
...
# let's define an __init__ that accepts a name
...
def __init __ (self, name):
...
# let's create an instance attribute for the name
...
self.name = name
...
>>>
# let's create two instances of Dog
>>> rex = Dog ('Rex')
>>> fido = Dog ('Fido')
>>> rex.name
# we check that the name of the first one is Rex 'Rex'
>>> fido.name
# and that the name of the second is Fido
'Fido'
Attributes
In these last two lessons we have seen that attributes are values associated
with the instance (or class) and we have also seen some examples of
declaration and use of attributes.
As you can guess from the names, the instance attributes are tied to a
specific instance, while the class attributes are tied to the class. Instance
attributes are generally more common and are declared by instance.attribute
= value.
When an instance attribute is declared within a method (for example the __
init__), self.attributo = value is used, since self refers to the instance:
>>>
# let's create an instance of Dog
>>> rex = Dog ('Rex')
>>>
# let's check the attributes and methods of the instance
>>>
# using dir () (special methods have been omitted)
>>> dir (rex) [..., 'name', 'print_name']
>>>
# let's add a new attribute to the instance
>>> rex.job = 'police officer'
>>>
# check that the attribute has been added
>>> dir (rex) [..., 'job', 'name', 'print_name']
>>>
# we access the new attribute
>>> rex.job 'police officer'
>>>
# we remove the attribute using "del"
>>> of rex.job
>>>
# check that the attribute has been removed
>>> dir (rex) [..., 'name', 'print_name']
Class attributes are class-related values, which are common and accessible
by all instances. To declare class attributes, there are two ways: using
class.attribute = value or using attribute = value in the body of a class
declaration:
>>>
# let's define a Dog class
>>> class Dog:
...
# let's define a class attribute
...
scientific_name = 'Canis lupus familiaris'
...
# let's define an __init__ that accepts a name
...
def __init __ (self, name):
...
# let's create an instance attribute for the name
...
self.name = name
...
>>>
# we create two instances of Dog
>>> rex = Dog ('Rex')
>>> fido = Dog ('Fido')
>>>
# we check that each instance has a different name
>>> rex.name 'Rex'
>>> fido.name 'Fido'
>>>
# we access the class attribute from Dog
>>> Dog.scientific_name 'Canis lupus familiaris'
>>>
# we access the class attribute from the instances
>>> rex.scientific_name 'Canis lupus familiaris'
>>> fido.scientific_name 'Canis lupus familiaris'
>>>
# let's change the value of the class attribute
>>> Dog.scientific_name = 'Canis lupus lupus'
>>>
# check the change from the instance
>>> rex.scientific_name 'Canis lupus lupus'
In this example we see that the scientific name ('Canis lupus familiaris'),
common to all instances of Dog, is declared during the definition of the
class, and is accessible both from the instances and from the class itself.
Each instance then has a unique name (e.g. 'Rex' and 'Fido'), which is
defined in the __ init__ and which is accessible only from the instances.
Modules
In Python a module is essentially a file that contains code written in this
language. The modules are characterized by the extension ".py", therefore
the file "instruction.py" will correspond to the module name "instruction".
Creating a form
product = x * y
return product
Once the code is saved in a file, which we will call for example "app.py",
we will have a module that can be imported into any program.
Importing a form
To import a module you must use the keyword import followed by the name
of the module and not that of the file that represents it, therefore omitting
the extension ".py"; once this is done, the instructions contained therein will
become available for the application in which it was imported. So, in the
case of the previously created module, we will have to use a syntax like the
following:
# Importing a form
>>> import app
After the import, to use the instructions contained in the module we will
have to perform an operation which technically consists in introducing the
names of the functions defined in "app" in the current symbol table. It is a
matter of making the functions of the module usable, which is possible by
concatenating the name of the module to the desired function by means of
the already known operator ".".
In our case the "app" module presents only the "mul ()" function which we
will call in this way:
Be careful, however, because once a module is renamed the new name must
also be used in the function call, otherwise Python will produce an error no
longer recognizing the initial name of the module:
Note how in this case it is possible to use the function without the need to
concatenate its name to that of the module. In case you want to import
multiple instructions of a module excluding others, just use the construct
seen above, where the names of the chosen instructions will be separated
with a comma:
# Multiple importation of instructions from a form
>>> from app import mul, second_instruction, third_instruction
These modules can be imported using the same syntax that can be used for
user-defined modules.
If you want to change the default setting, you can use another method,
setfirstweekday (), which accepts the day of the week index with which you
want to start the week as a parameter. In the event that the choice should
fall on Sunday, following a usual convention in countries like the United
States, we should proceed as follows:
At the beginning of this book, we saw four basic programming models used
to write programs:
• Sequential code
• Conditional code (if instructions)
• Repetitive code (cycles)
• Stores and reuses (functions).
There are many ways to write programs and, at this point, you have
probably written some "not particularly elegant" and other "more elegant"
scripts. Even if your scripts are quite small in size, you are starting to
understand how there is a bit of "art" and "aesthetics" in developing code.
As programs reach millions of lines, it becomes increasingly important to
write code that is easy to interpret. If you are working on a million-line
program, you will never be able to keep the entire program in mind at the
same time.
We need to find ways to break the program into multiple pieces so that
solving problems, fixing a bug or adding a new feature is as simple as
possible. In a sense, object-oriented programming is a way of organizing
the code so that we can focus our attention on 500 lines of code while
momentarily ignoring the other 999,500.
consider this chapter as a way to study some basic terms and concepts
illustrated through some simple examples with the aim of laying the
foundations for future learning. Although in the rest of the book we will
new ones. What we want to achieve with this chapter is a basic knowledge
of how objects are made, how they work and, above all, how to exploit the
Use objects
You will realize that we actually used the objects throughout the course:
Python provides us with many objects already integrated into it. Here is a
simple script whose first few lines should seem very simple and familiar to
you.
stuff = list ()
stuff.append ( 'python')
stuff.append ( 'Chuck')
stuff.sort ()
print (stuff [0])
print (stuff .__ getitem __ (0))
print (list .__ getitem __ (stuff, 0))
Rather than focusing on what you could achieve through these few lines of
code, let's see what is really going on from an object-oriented perspective.
Don't worry if the first time you read the next few paragraphs it seems that
we don't make much sense since I haven't explained the meaning of many
of the terms yet. The first line is building a list object, the second and third
lines call the append () method, the fourth line calls the sort () method and
the fifth line is getting the element in position 0. The sixth line calls the
__getitem __ () method in the stuff list with parameter zero.
print (stuff .__ getitem __ (0))
The seventh row is an even more detailed way of recovering the element
that occupies the zero position in the list.
print (list .__ getitem __ (stuff, 0))
In this script, we call the __getitem__ method of the list class, we pass it in
the list (stuff) with the element we want to retrieve from the list as the
second parameter. The last three lines of the program are completely
equivalent, but it is easier to use the syntax with square brackets to search
for an element in a specific position of a list. We can take a look at the
potential of an object by studying the output of the dir () function:
More precisely dir () lists the methods and attributes of an object. The rest
of this chapter will provide you with a more precise de fi nition of all the
terms already reported, therefore, after completing this chapter, re-read the
previous paragraphs to verify what you have really learned.
If we focus a little more on this program: we can see that the "external
world" and the internal world of the program coexist. The input and output
operations represented the way in which the program interacts with the
outside world. Within the program we have the code and data necessary to
perform the task for which it was designed.
Some well-defined interactions with the "outside" world take place within
the program, which are generally not something we focus on. When we
write about the code, we only care about the details "within the program".
One way to think about object-oriented programming is to want to try to
separate our program into multiple "zones".
Each "zone" is composed of code and data (as if it were a program in its
own right) and has well-defined interactions with the outside world and
with the other zones within the program. If we take into consideration the
link extraction script in which we used the BeautifulSoup library we can see
a program consisting of multiple objects that interact with each other to
perform a task:
The URL is requested as a string, then passed in urllib for the recovery of
data from the web. The urllib library makes the network connection by
leaning on the socket library. The string downloaded from urllib is
delivered to BeautifulSoup for analysis.
At this moment, the most important thing is not to fully understand the
functioning of this program, but rather to see how this set of objects has
been structured and how the exchange of information is orchestrated. It is
also important to note that when you studied the functioning of a script
present in the first chapters of this book, you were able to fully understand
what was happening without even realizing that the program was
"managing the movement of data between the objects present". Back then,
for you it was just lines of code that did the job.
This ability to focus on the part of a program that interests us ignoring the
rest of the program is also useful for the developers of the objects
themselves: the programmers who take care of the BeautifulSoup
development do not need to know or worry about how you recovered the
HTML page from analyze, which parts you want to read or what you intend
to do with the data you extracted.
There is another word that is commonly used to convey the idea that we are
ignoring the internal functioning of the objects we use: "encapsulation". In
other words, it means that we can know how to use an object without really
knowing what really happens inside it.
class PartyAnimal:
x=0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
an.party()
an.party()
an.party()
PartyAnimal.party(an)
Each method that looks like a function starts with the def keyword and
consists of a block of indented code. The previous example has an attribute
(x) and a method (party). The methods have a special first parameter called
by self convention. Just as the def keyword does not cause the function
code to execute, the class keyword does not create an object. Rather, the
class keyword defines a model that indicates which data and code will be
contained in each PartyAnimal type object.
You might think that the classroom is a cookie cutter and that the objects
created using the classroom are cookies2. When preparing the biscuits, you
know that the icing should not be put on the mold but rather on the biscuits
and you always have the possibility to put a different icing on each biscuit.
But now let's continue to analyze the sample code. Look at the first line of
executable code:
an = PartyAnimal()
This is the point where we tell Python where to build (eg create) an object
or "the instance of the class called PartyAnimal". It looks like a function
call to the class itself and Python builds the object with the correct data and
methods and returns the object which is then assigned to the variable an. In
a sense, all of this is quite similar to the line we have used since the
beginning:
counts = dict()
Here we are telling Python to create an object using the template dict
(already present in the language), return the dictionary instance and assign
it to the counts variable.
When we want to use the PartyAnimal class to build an object, the variable
an allows us to point to that object, access the code and data that that
particular instance of a PartyAnimal object contains. Each Partyanimal
object / instance contains an x variable and a party method / function which
is called in this line:
an.party()
When the party method is called, the first parameter (called by self
convention) points to the particular instance of the PartyAnimal object
which is called within the party. Within the party method, we can see the
line:
self.x = self.x + 1
This syntax using the 'dot' operator indicates 'the x inside self'. So each time
party () is called the internal value x is increased by 1 and then displayed.
To help you understand the di enza erence between a global function and a
method within a class / object, in the following line you can see another
way to call the party method within the object an:
PartyAnimal.party(an)
In this variant we are accessing the code from the class and explicitly
passing the pointer of the object an as the first parameter (for example self
within the method). You can think of an.party () as an abbreviation of the
previous line. When the program is executed, the following output will be
generated: So far 1 So far 2 So far 3 So far 4 The object was created and the
party method is called four times, increasing and displaying the value of x
inside the object an.
Classes as types
As we have seen, in Python all variables have a type that we can examine
via the integrated dir function. these features are extended to the classes we
create.
class PartyAnimal:
x=0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
print ("Type", type(an))
print ("Dir ", dir(an))
print ("Type", type(an.x))
print ("Type", type(an.party))
You can notice that we created a new type using the class keyword and in
the output of dir that both the integer attribute x and the party method are
available in the object.
Life cycle of the object
class PartyAnimal:
x=0
def __init__(self):
print('I am constructed')
def party(self) :
self.x = self.x + 1
print('So far',self.x)
def __del__(self):
print('I am destructed', self.x)
an = PartyAnimal()
an.party()
an.party()
an = 42 print('an contains',an)
I am contructed
So far 1
So far 2
I am destructed 2
an contains 42
As soon as Python starts building our object, call our __init__ method to
give us the opportunity to set some initial or default values to pass to the
object. When Python encounters the line:
an = 42
In fact, "trash our object" so that we can reuse the variable an to store the
value 42. The destructor code (__del__) is called just when our object an is
"destroyed". We cannot prevent our variable from being destroyed but we
can do any necessary cleaning before our object no longer exists. During
object development it is quite common to add a constructor to an object to
set its initial values and it is relatively equally rare that you need to set a
destructor.
Inheritance
Another powerful feature of object-oriented programming is the ability to
create a new class by extending an existing one. When we extend a class,
we call the original class 'parent class' and the new 'child class'. In this
example we will move our PartyAnimal class to its file:
class PartyAnimal:
x=0
name = ''
def __init__(self, nam):
self.name = nam
print(self.name,'constructed')
def party(self) :
self.x = self.x + 1
print(self.name,'party count',self.x)
So we have the possibility to 'import' the PartyAnimal class into a new file
and extend it as follows:
from party import PartyAnimal
class CricketFan(PartyAnimal):
points = 0
def six(self):
self.points = self.points + 6
self.party()
print(self.name,"points",self.points)
s = PartyAnimal("Sally")
s.party()
j = CricketFan("Jim")
j.party()
j.six()
print(dir(j))
In defining the CricketFan object, we indicated that we are extending the
PartyAnimal class: all variables (x) and methods (party) of the PartyAnimal
class are inherited from the CricketFan class. You can see that within the six
method in the CricketFan class we can call the party method from the
PartyAnimal class. The variables and methods of the parent class are united
in the child class. During the execution of the program we can see that s and
j are independent instances of PartyAnimal and CricketFan. Object j has
additional capabilities with respect to object s.
Sally constructed
Sally party count 1
Jim constructed
Jim party count 1
Jim party count 2
Jim points 6
['__class__', '__delattr__', ... '__weakref__', 'name', 'party', 'points', 'six', 'x']
In the dir output for object j (instance of the CricketFan class) you can see
that both have both the attributes and methods of the parent class and the
attributes and methods that were added when the class was extended to
create the CricketFan class.
CHAPTER 8. Error Handling
A Python program terminates as soon as it encounters an error. In Python,
an error can be a syntax error or an exception. In this chapter, you will see
what an exception is and how it differs from a syntax error. After that, you
will learn about raising exceptions and making assertions. Then, you’ll
finish with a demonstration of the try and except block.
Exceptions versus Syntax Errors
Syntax errors occur when the parser detects an incorrect statement. Observe
the following example:
>>> print( 0 / 0 ))
File "<stdin>" , line 1
print ( 0 / 0 ))
^
SyntaxError : invalid syntax
The arrow indicates where the parser ran into the syntax error. In this
example, there was one bracket too many. Remove it and run your code
again:
>>> print( 0 / 0)
Traceback (most recent call last):
File "<stdin>" , line 1 , in <module>
ZeroDivisionError : integer division or modulo by zero
This time, you ran into an exception error. This type of error occurs
whenever syntactically correct Python code results in an error. The last line
of the message indicated what type of exception error you ran into.
Instead of showing the message exception erro r , Python details what
type of exception error was encountered. In this case, it was a
ZeroDivisionErro r . Python comes with various built-in exceptions as well
as the possibility to create self-defined exceptions.
Raising an Exception
We can use raise to throw an exception if a condition occurs. The statement
can be complemented with a custom exception.
If you want to throw an error when a certain condition occurs using raise,
you could go about it like this:
x = 10
if x > 5 :
raise Exception ( 'x should not exceed 5. The value of x was: {} ' . format(x))
When you run this code, the output will be the following:
The program comes to a halt and displays our exception to screen, offering
clues about what went wrong.
The AssertionError Exception
Instead of waiting for a program to crash midway, you can also start by
making an assertion in Python. We asser t that a certain condition is met.
If this condition turns out to be Tru e , then that is excellent! The program
can continue. If the condition turns out to be Fals e , you can have the
program throw an AssertionErro r exception.
Have a look at the following example, where it is asserted that the code will
be executed on a Linux system:
import sys
assert ( 'linux' in sys . platform), "This code runs on Linux only."
If you run this code on a Linux machine, the assertion passes. If you were to
run this code on a Windows machine, the outcome of the assertion would
be False and the result would be the following:
The following function can help you understand the tr y and excep t block:
def linux_interaction():
assert ( 'linux' in sys . platform), "Function can only run on Linux systems."
print ( 'Doing something.' )
The way you handled the error here is by handing out a pass. If you were to
run this code on a Windows machine, you would get the following output:
You got nothing. The good thing here is that the program did not crash. But
it would be nice to see if some type of exception occurred whenever you
ran your code. To this end, you can change the pass into something that
would generate an informative message, like so:
try :
linux_interaction()
except :
print ( 'Linux function was not executed' )
What you did not get to see was the type of error that was thrown as a result
of the function call. In order to see exactly what went wrong, you would
need to catch the error that the function threw.
The first message is the AssertionErro r , informing you that the function
can only be executed on a Linux machine. The second message tells you
which function was not executed.
In the previous example, you called a function that you wrote yourself.
When you executed the function, you caught the AssertionErro r
exception and printed it to screen.
Here’s another example where you open a file and use a built-in exception:
try :
with open ('file.log' ) as file:
read_data = file. read()
except :
print ('Could not open file.log' )
If file.log does not exist, this block of code will output the following:
Could not open file.log
This is an informative message, and our program will still continue to run.
In the Python docs, you can see that there are a lot of built-in exceptions
that you can use here. One exception described on that page is the
following:
Exception FileNotFoundError
Raised when a file or directory is requested but doesn’t exist. Corresponds to errno ENOENT.
To catch this type of exception and print it to screen, you could use the
following code:
try :
with open ( 'file.log' ) as file:
read_data = file . read()
except FileNotFoundError as fnf_error:
print (fnf_error)
In this case, if file.log does not exist, the output will be the following:
[Errno 2] No such file or directory: 'file.log'
You can have more than one function call in your tr y clause and
anticipate catching various exceptions. A thing to note here is that the code
in the tr y clause will stop as soon as an exception is encountered.
Look at the following code. Here, you first call the linux_interaction( )
function and then try to open a file:
try :
linux_interaction()
with open ( 'file.log' ) as file:
read_data = file . read()
except FileNotFoundError as fnf_error:
print (fnf_error)
except AssertionError as error:
print (error)
print ( 'Linux linux_interaction() function was not executed' )
If the file does not exist, running this code on a Windows machine will
output the following:
Function can only run on Linux systems.
Linux linux_interaction() function was not executed
Inside the tr y clause, you ran into an exception immediately and did not
get to the part where you attempt to open file.log. Now look at what
happens when you run the code on a Linux machine:
[Errno 2] No such file or directory: 'file.log'
If you were to run this code on a Linux system, the output would be the
following:
Doing something.
Executing the else clause.
Because the program did not run into any exceptions, the els e clause was
executed.
You can also tr y to run code inside the els e clause and catch possible
exceptions there as well:
try :
linux_interaction()
except AssertionError as error:
print (error)
else :
try :
with open ( 'file.log' ) as file:
read_data = file . read()
except FileNotFoundError as fnf_error:
print (fnf_error)
If you were to execute this code on a Linux machine, you would get the
following result:
Doing something.
[Errno 2] No such file or directory: 'file.log'
From the output, you can see that the linux_interaction () function ran.
Because no exceptions were encountered, an attempt to open file.log was
made. That file did not exist, and instead of opening the file, you caught
the FileNotFoundErro r exception.
Imagine that you always had to implement some sort of action to clean up
after executing your code. Python enables you to do so using the finall y
clause.
Have a look at the following example:
try :
linux_interaction()
except AssertionError as error:
print (error)
else :
try :
with open ( 'file.log' ) as file:
read_data = file . read()
except FileNotFoundError as fnf_error:
print (fnf_error)
finally :
print ( 'Cleaning up, irrespective of any exceptions.' )
Summing Up
After seeing the difference between syntax errors and exceptions, you
learned about various ways to raise, catch, and handle exceptions in Python.
In this article, you saw the following options:
• rais e allows you to throw an exception at any time.
• asser t enables you to verify if a certain condition is met and throw
an exception if it isn’t.
• In the tr y clause, all statements are executed until an exception is
encountered.
• excep t is used to catch and handle the exception(s) that are
encountered in the try clause.
• els e lets you code sections that should run only when no exceptions
are encountered in the try clause.
• finall y enables you to execute sections of code that should always
run, with or without any previously encountered exceptions.
Conclusion
The basics of Python programming have been explained in this book. First
of all I tried to explain why programming is useful and why (in my opinion)
we should all be able to do it. After introducing this concept, in my
fundamental opinion, I explained how to install Python on your computer
and I introduced you to the basic concepts.
The notions that you have learned in this book are notions extendable to any
programming language, cycles, if, objects, error handling are present in
many other languages: C ++, Java, SQL, JavaScript, all use these
foundations.
Naturally it will change the syntax and the potential of the language, but
with a basic knowledge, like the one I have provided you with in this book,
you will be able to learn much faster.
I would like to conclude this book by inviting you not to stop at this level of
knowledge, but to learn with curiosity as much as possible about the world
of programming, because they are useful skills, which you can use both in
the professional world and in the personal sphere. Scheduling, automating
processes helps us in daily life, allowing us to do many things in a short
time.
Happy Coding!