Python Handbook
Python Handbook
Functions
21. Objects
Flavio Copes 22. Loops
Blog Solopreneur Land Notion to Site Books Bootcamp
22.1. while loop
22.2. for loop
22.3. Break and continue
23. Classes
The ecosystem is huge. There seems to be a library for everything you can
imagine.
Starting with Python is very easy. All you need is to install the official
This has pros and cons. In particular we can mention that you write
package from [Link], for Windows, macOS or Linux, and you’re ready to
programs faster, but on the other hand you have less help from the tools to
go.
prevent possible bugs and you will find out about some kinds of issues only
by executing the program at runtime.
If you are new to programming, in the following posts I will guide you to go
from zero to becoming a Python programmer.
Python supports a wide variety of different programming paradigms,
including procedural programming, object oriented programming and
And even if you are currently a programmer specialized into another
functional programming. It’s flexible enough to adapt to a lot of different
language, Python is a language worth knowing because I think we’re just at
needs.
the start.
2. Installing Python
Go to [Link] choose the Downloads menu, choose your
operating system and a panel with a link to download the official package
will appear:
Notice the >>> symbol, and the cursor after that. You can type any Python
code here, and press the enter key to run it.
name = "Flavio"
print(name)
Make sure you follow the specific instructions for your operating system. On
macOS you can find a detailed guide on [Link]
installation-macos/.
3. Running Python programs Note: in the REPL, you can also just type name, press the enter key and
you’ll get the value back. But in a program, you are not going to see any
There are a few different ways to run Python programs. output if you do so - you need to use print() instead.
Let’s start with interactive prompts. You can access the same interactive prompt using the IDLE application
that’s installed by Python automatically:
If you open your terminal and type python, you will see a screen like this:
This is the Python REPL (Read-Evaluate-Print-Loop) This might be more convenient for you because with the mouse you can
move around and copy/paste more easily than with the terminal.
Those are the basics that come with Python by default. However I
recommend to install IPython, probably the best command line REPL
application you can find.
Install it with
Make sure the pip binaries are in your path, then run ipython:
Note that we save Python programs with the .py extension, that’s a
convention.
In this case the program is executed as a whole, not one line at a time. And
that’s typically how we run programs.
On Linux and macOS a Python program can also be transformed into a shell
script, by prepending all its content with a special line that indicates which
executable to use to run it.
The second way to run a Python program is to write your Python program
code into a file, for example [Link]:
and then run it with python [Link] and I can run the program with
./[Link]
This is especially useful when you write scripts that interact with the
terminal.
After installing this extension you will have Python code autocompletion and
error checking, automatic formatting and code linting with pylint, and
some special commands, including:
and you will be immediately shown an editor with a [Link] file, ready to
Another way to easily run Python code is to use [Link], a very nice website be filled with a lot of Python code:
that provides a coding environment you can create and run your apps on, in
any language, Python included:
Once you have some code, click “Run” to run it on the right side of the
window:
In this example we assign a string with the value “Roger” to the name label:
name = "Roger"
age = 8
One key topic to talk about, right from the start, is the Python 2 vs Python 3 These are invalid variable names:
discussion.
123
Python 3 was introduced in 2008, and it’s been in development as the main
test!
Python version, while Python 2 continued being maintained with bug fixes
name%
and security patches until early 2020.
On that date, Python 2 support was discontinued. Other than that, anything is valid unless it’s a Python keyword. There are
some keywords like for, if, while, import and more.
Many programs are still written using Python 2, and organizations still
actively work on those, because the migration to Python 3 is not trivial and There’s no need to memorize them, as Python will alert you if you use one of
those programs would require a lot of work to upgrade those programs. And those as a variable, and you will gradually recognize them as part of the
large and important migrations always introduce new bugs. Python programming language syntax.
But new code, unless you have to adhere to rules set by your organization 5.2. Expressions and statement
that forces Python 2, should always be written in Python 3.
We can expression any sort of code that returns a value. For example
This book focuses on Python 3.
1 + 1 6. Data Types
"Roger"
name = "Roger"
print(name) name = "Roger"
A program is formed by a series of statements. Each statement is put on its You can check which type a variable is using the type() function, passing
own line, but you can use a semicolon to have more than one statement on the variable as an argument, and then comparing the result to str:
a single line:
name = "Roger"
Or using isinstance():
5.3. Comment
In a Python program, everything after a hash mark is ignored, and name = "Roger"
#this is a commented line Notice that to see the True value in Python, outside of a REPL, you need to
wrap this code inside print(), but for clarity reasons I avoid using it
name = "Roger" # this is an inline comment
We used the str class here, but the same works for other data types.
5.4. Indentation First, we have numbers. Integer numbers are represented using the int
class. Floating point numbers (fractions) are of type float:
Indentation in Python is meaningful.
age = 1
You cannot indent randomly like this:
type(age) == int #True
name = "Flavio"
print(name) fraction = 0.1
type(fraction) == float #True
In this case, if you try to run this program you would get a name = "Flavio"
IndentationError: unexpected indent error, because indenting age = 20
has a special meaning.
age = int("20")
print(age) #20 Or to assign a variable value to another variable:
We’ll explore them all soon. Note that you don’t need a space between the operands, but it’s good for
readability.
Python operators are symbols that we use to run operations upon values
print(-4) #-4
and variables.
We can divide operators based on the kind of operation they perform: + is also used to concatenate String values:
Example:
Otherwise, pay attention to a possible source of confusion.
age = 8 or used in an expression returns the value of the first operand that is not a
age += 1
falsy value (False, 0, '', []..). Otherwise it returns the last operand.
# age is now 9
print(0 or 1) ### 1
7.0.3. Comparison operator print(False or 'hey') ### 'hey'
print('hi' or 'hey') ### 'hi'
Python defines a few comparison operators: print([] or False) ### False
print(False or []) ### []
==
!=
The Python docs describe it as if x is false, then y, else x.
>
< and only evaluates the second argument if the first one is true. So if the first
>= argument is falsy (False, 0, '', []..), it returns that argument. Otherwise it
<= evaluates the second argument:
You can use those operators to get a boolean value (True or False)
print(0 and 1) ### 0
depending on the result:
print(1 and 0) ### 0
print(False and 'hey') ### False
a = 1
print('hi' and 'hey') ### 'hey'
b = 2
print([] and False ) ### []
print(False and [] ) ### False
a == b #False
a != b #True
The Python docs describe it as if x is false, then x, else y.
a > b #False
a <= b #True
7.0.5. Bitwise operator
7.0.4. Boolean operator Some operators are used to work on bits and binary numbers:
Python gives us the following boolean operators: & performs binary AND
| performs binary OR
not ^ performs a binary XOR operation
and ~ performs a binary NOT operation
or
<< shift left operation
>> shift right operation
When working with True or False attributes, those work like logical AND,
OR and NOT, and are often used in the if conditional expression evaluation:
Bitwise operators are rarely used, only in very specific situations, but they name = "Roger"
are worth mentioning.
is is called the identity operator. It is used to compare two objects and phrase = "Roger" + " is a good dog"
returns true if both are the same object. More on objects later.
You can append to a string using +=:
in is called the membership operator. Is used to tell if a value is contained
in a list, or another sequence. More on lists and other sequences later. name = "Roger"
name += " is a good dog"
8. The Ternary Operator
print(name) #Roger is a good dog
The ternary operator in Python allows you to quickly define a conditional.
You can convert a number to a string using the str class constructor:
Let’s say you have a function that compares an age variable to the 18 value,
and return True or False depending on the result.
str(8) #"8"
Instead of writing:
This is essential to concatenate a number to a string:
def is_adult(age):
if age > 18: print("Roger is " + str(8) + " years old") #Roger is 8 years old
return True
else:
A string can be multi-line when defined with a special syntax, enclosing the
return False
string in a set of 3 quotes:
You can implement it with the ternary operator in this way: print("""Roger is
def is_adult(age): 8
return True if age > 18 else False
years old
""")
First you define the result if the condition is True, then you evaluate the
condition, then you define the result if the condition is false:
#double quotes, or single quotes
9. Strings
8
"Roger"
'Roger' A string has a set of built-in methods, like:
name = "Roger"
print([Link]()) #"roger" You can also use a range, using what we call slicing:
print(name) #"Roger"
name = "Roger"
You can use some global functions to work with strings, too. name[0:2] #"Ro"
name[:2] #"Ro"
In particular I think of len(), which gives you the length of a string: name[2:] #"ger"
name = "Roger"
print(len(name)) #5
10. Booleans
Python provides the bool type, which can have two values: True and
The in operator lets you check if a string contains a substring: False (capitalized)
Escaping is a way to add special characters into a string. Booleans are especially useful with conditional control structures like if
statements:
For example, how do you add a double quote into a string that’s wrapped
into double quotes?
done = True
name = "Roger"
if done:
# run some code here Integer numbers are represented using the int class. You can define an
else: integer using a value literal:
# run some other code
age = 8
When evaluating a value for True or False, if the value is not a bool we
have some rules depending on the type we’re checking: You can also define an integer number using the int() constructor:
The global any() function is also very useful when working with booleans, Or using the float() constructor:
as it returns True if any of the values of the iterable (list, for example)
passed as argument are True: fraction = float(0.1)
book_1_read = True
To check if a variable is of type float, you can use the type() global
book_2_read = False
function:
The global all() function is same, but returns True if all of the values
passed to it are True: 11.0.3. Complex number
Complex numbers are of type complex.
ingredients_purchased = True
meal_cooked = False
You can define them using a value literal:
You can specify a second parameter to set the decimal points precision:
Again, to check if a variable is of type complex, you can use the type()
global function: round(0.12, 1) #0.1
1 + 1 #2
We’ll explore some of those separately later on.
2 - 1 #1
2 * 2 #4
4 / 2 #2 12. Constants
4 % 3 #1
4 ** 2 #16 Python has no way to enforce a variable to be a constant.
4 // 2 #2
The nearest you can go is to use an enum:
+= WIDTH = 1024
HEIGHT = 256
-=
*=
/= And get to each value using for example [Link].
%=
..and so on No one can reassign that value.
to quickly perform operations on variables, too: Otherwise if you want to rely on naming conventions, you can adhere to this
one: declare variables that should never change uppercase:
age = 8
age += 1 WIDTH = 1024
No one will prevent to overwrite this value, and Python will not stop it.
11.0.5. Built-in Function
That’s what does most Python code you will see.
There are 2 built-in functions that help with numbers:
To use enums, import Enum from the enum standard library module:
print('Your age is ' + age)
from enum import Enum
This approach gets input at runtime, meaning the program will stop
Then you can initialize a new enum in this way:
execution and will wait until the user types something and presses the
enter key.
class State(Enum):
INACTIVE = 0
You can also do more complex input processing and accept input at
ACTIVE = 1
program invocation time, and we’ll see how to do that later on.
Once you do so, you can reference [Link] and [Link], This works for command line applications. Other kinds of applications will
and they serve as constants. need a different way of accepting input.
The same value can be reached by the number assigned in the enum: In Python we do so using the if statement:
print(State(1)) will return [Link]. Same for using the square
brackets notation State['ACTIVE']. condition = True
You can however get the value using [Link]. if condition == True:
# do something
You can list all the possible values of an enum:
When the condition test resolves to True, like in the above case, its block
list(State) # [<[Link]: 0>, <[Link]: 1>]
gets executed.
You can count them: What is a block? A block is that part that is indented one level (4 spaces
usually) on the right:
len(State) # 2
condition = True
The block can be formed by a single line, or multiple lines as well, and it
name = "Roger" ends when you move back to the previous indentation level:
print(name)
condition = True
We can also accept input from the user, using input():
if condition == True:
condition = True
if and else can also be used in an inline format, which lets us return a
if condition == True: value or another based on a condition.
print("The condition")
print("was True")
Example:
else:
print("The condition") a = 2
And you can have different linked if checks with elif, that’s executed if
the previous check was False: 16. Lists
condition = True Lists are an essential Python data structure.
name = "Roger"
The allow you to group together multiple values and reference them all with
if condition == True: a common name.
print("The condition")
print("was True") For example:
elif name == "Roger":
print("Hello Roger") dogs = ["Roger", "Syd"]
else:
print("The condition")
A list can hold values of different types:
print("was False")
In a if statement you can have just one if and else checks, but multiple
series of elif checks: print("Roger" in items) # True
[Link](["Test1", "Test2"])
As with strings, using a negative index will start searching from the end:
items[-1] # True These append the item to the end of the list.
To add an item in the middle of a list, at a specific index, use the insert()
You can also extract a part of a list, using slices:
method:
items[0:2] # ["Roger", 1]
[Link](1, "Test") # add "Test" at index 1
items[2:] # ["Syd", True]
len(items) #4
Sort a list using the sort() method:
You can add items to the list by using a list append() method:
[Link]()
[Link]("Test")
Tip: sort() will only work if the list holds values that can be compared.
Strings and integers for example can’t be compared, and you’ll get an error
or the extend() method:
like TypeError: '<' not supported between instances of
'int' and 'str' if you try.
[Link](["Test"])
Tip: with extend() or += don’t forget the square brackets. Don’t do items Sorting modifies the original list content. To avoid that, you can copy the list
+= "Test" or [Link]("Test") or Python will add 4 individual content using
characters to the list, resulting in ['Roger', 1, 'Syd', True, 'T',
'e', 's', 't'] itemscopy = items[:]
or use the sorted() global function: names[0:2] # ('Roger', 'Syd')
names[1:] # ('Syd',)
print(sorted(items, key=[Link]))
Get the number of items in a tuple using the len() global function, the
that will return a new list, sorted, instead of modifying the original list. same we used to get the length of a string:
Tuples are another fundamental Python data structure. You can create a sorted version of a tuple using the sorted() global
function:
They allow you to create immutable groups of objects. This means that
once a tuple is created, it can’t be modified. You can’t add or remove items.
sorted(names)
They are created in a way similar to lists, but using parentheses instead of
square brackets: You can create a new tuple from existing tuples using the + operator:
A tuple is ordered, like a list, so you can get its values referencing an index
value:
18. Dictionaries
Dictionaries are a very important Python data structure.
names[0] # "Roger"
names[1] # "Syd" While lists allow you to create collections of values, dictionaries allow you to
create collections of key / value pairs.
You can also use the index() method:
Here is a dictionary example with one key/value pair:
[Link]("Roger") # 0
[Link]("Syd") # 2 dog = { 'name': 'Roger' }
As with strings and lists, using a negative index will start searching from the The key can be any immutable value like a string, a number or a tuple. The
end: value can be anything you want.
dog['name'] # 'Roger'
You can check if an item is contained into a tuple with the in operator: dog['age'] # 8
And another way is using the get() method, which has an option to add a You can remove a key/value pair from a dictionary using the del statement:
default value:
del dog['favorite food']
[Link]('name') # 'Roger'
[Link]('test', 'default') # 'default'
To copy a dictionary, use the copy() method:
The pop() method retrieves the value of a key, and subsequently deletes dogCopy = [Link]()
the item from the dictionary:
You can check if a key is contained into a dictionary with the in operator:
You can create a set using this syntax:
Get a list with the keys in a dictionary using the keys() method, passing its
Sets work well when you think about them as mathematical sets.
result to the list() constructor:
print(list([Link]()))
# ['Roger', 8] You can create a union of two sets:
print(list([Link]()))
set1 = {"Roger", "Syd"}
# [('name', 'Roger'), ('age', 8)]
set2 = {"Luna"}
Get a dictionary length using the len() global function, the same we used union = set1 | set2
to get the length of a string or the items in a list: #{'Syd', 'Luna', 'Roger'}
You can add a new key/value pair to the dictionary in this way: set1 = {"Roger", "Syd"}
set2 = {"Roger"}
To run this function, we must call it. This is the syntax to call the function:
difference = set1 - set2 #{'Syd'}
hello()
You can check if a set is a superset of another (and of course if a set is a
subset of another) We can execute this function once, or multiple times.
set1 = {"Roger", "Syd"} The name of the function, hello, is very important. It should be descriptive,
set2 = {"Roger"} so anyone calling it can imagine what the function does.
isSuperset = set1 > set2 # True A function can accept one or more parameters:
You can count the items in a set with the len() global function: def hello(name):
print('Hello ' + name + '!')
You can get a list from the items in a set by passing the set to the list() hello('Roger')
constructor:
We call parameters the values accepted by the function inside the function
names = {"Roger", "Syd"} definition, and arguments the values we pass to the function when we call it.
list(names) #['Syd', 'Roger'] It’s common to get confused about this distinction.
An argument can have a default value that’s applied if the argument is not
You can check if an item is contained into a set with the in operator:
specified:
20. Functions
hello()
#Hello my friend!
A function lets us create a set of instructions that we can run when needed.
Functions are essential in Python and in many other programming Here’s how we can accept multiple parameters:
languages to create meaningful programs, because they allow us to
decompose a program into manageable parts, they promote readability and def hello(name, age):
code reuse. print('Hello ' + name + ', you are ' + str(age) + ' years old!
This is the function definition. There is a name (hello) and a body, the set Parameters are passed by reference. All types in Python are objects but
of instructions, which is the part that follows the colon and it’s indented one some of them are immutable, including integers, booleans, floats, strings,
level on the right. and tuples. This means that if you pass them as parameters and you modify
their value inside the function, the new value is not reflected outside of the return name, 'Roger', 8
function:
In this case calling hello('Syd') the return value (note: not what it’s
def change(value): printed on screen, but the return value) is a tuple containing those 3 values:
value = 2 ('Syd', 'Roger', 8):
val = 1
def hello(name):
change(val)
print('Hello ' + name + '!')
return name, 'Roger', 8
print(val) #1
If you pass an object that’s not immutable, and you change one of its print(hello('Syd')) #('Syd', 'Roger', 8)
properties, the change will be reflected outside.
A function can return a value, using the return statement. For example in 21. Objects
this case we return the name parameter name:
Everything in Python is an object.
def hello(name):
Even values of basic primitive types (integer, string, float..) are objects. Lists
print('Hello ' + name + '!')
are objects, tuples, dictionaries, everything.
return name
Objects have attributes and methods that can be accessed using the dot
When the function meets the return statement, the function ends. syntax.
We can omit the value: For example, try defining a new variable of type int:
You can return multiple values by using comma separated values: A variable holding a list value has access to a different set of methods:
age += 1
The methods depend on the type of value.
The id() global function provided by Python lets you inspect the location in and you check with id(age) you will find that age points to a different
memory for a particular object. memory location. The original value has not mutated, we switched to
another value.
id(age) # 140170065725376
22. Loops
Your memory value will change, I am only showing it as an example
Loops are one essential part of programming.
If you assign a different value to the variable, its address will change,
because the content of the variable has been replaced with another value In Python we have 2 kinds of loops: while loops and for loops.
stored in another location in memory:
22.1. while loop
age = 8
while loops are defined using the while keyword, and they repeat their
print(id(age)) # 140535918671808 block until the condition is evaluated as False:
But if you modify the object using its methods, the address stays the same: This is an infinite loop. It never ends.
items = [1, 2] Let’s halt the loop right after the first iteration:
The address only changes if you reassign a variable to another value. In this case, the first iteration is ran, as the condition test is evaluated to
True, and at the second iteration the condition test evaluates to False, so
Some objects are mutable, some are immutable. This depends on the object the control goes to the next instruction, after the loop.
itself. If the object provides methods to change its content, then it’s mutable.
Otherwise it’s immutable. Most types defined by Python are immutable. For It’s common to have a counter to stop the iteration after some number of
example an int is immutable. There are no methods to change its value. If cycles:
you increment the value using
count = 0
age = 8 while count < 10:
age = age + 1 print("The condition is True")
count = count + 1
if item == 2:
print("After the loop") continue
print(item)
items = [1, 2, 3, 4]
23. Classes
for item in items:
In addition to using the Python-provided types, we can declare our own
print(item)
classes, and from classes we can instantiate objects.
Or, you can iterate a specific amount of times using the range() function: An object is an instance of a class. A class is the type of an object.
class Dog:
Both while and for loops can be interrupted inside the block, using two print('WOF!')
items = [1, 2, 3, 4]
If you run
for item in items:
[Link]() # 'WOF!'
print(type(roger))
def bark(self):
print('WOF!') def bark():
print('WOF!')
One important features of classes is inheritance. Or, we can use the from .. import syntax and call the function directly:
We can create an Animal class with a method walk(): from dog import bark
and the Dog class can inherit from Animal: The second strategy lets us pick the things we need.
Those modules are specific to your program, and importing depends on the
class Dog(Animal):
location of the file in the filesystem.
def bark(self):
print('WOF!')
Suppose you put [Link] in a lib subfolder.
Now creating a new object of class Dog will have the walk() method as In that folder, you need to create an empty file named __init__.py. This
that’s inherited from Animal: tells Python the folder contains modules.
roger = Dog() Now you can choose, you can import dog from lib:
[Link]() # 'Walking..'
from lib import dog or
sqrt(4) # 2.0
or you can reference the dog module specific function importing from
[Link]:
We’ll soon explore the most important modules individually to understand
what we can do with them.
from [Link] import bark
Python exposes a lot of built-in functionality through its standard library. If you learn the right naming and formatting conventions right from the start,
it will be easier to read code written by other people, and people will find
The standard library is a huge collection of all sort of utilities, ranging from your code easier to read.
math utilities to debugging to creating graphical user interfaces.
Python defines its conventions in the PEP8 style guide. PEP stands for
You can find the full list of standard library modules here: Python Enhancement Proposals and it’s the place where all Python
[Link] language enhancements and discussions happen. There are a lot of PEP
proposals, all available at [Link]
Some of the important modules are:
PEP8 is one of the first ones, and one of the most important, too. It defines
math for math utilities the formatting and also some rules on how to write Python in a “pythonic”
re for regular expressions way.
json to work with JSON
datetime to work with dates You can read its full content here: [Link]
sqlite3 to use SQLite 0008/ but here’s a quick summary of the important points you can start
os for Operating System utilities with:
random for random number generation
statistics for statistics utilities Indent using spaces, not tabs
requests to perform HTTP network requests Indent using 4 spaces.
http to create HTTP servers Python files are encoded in UTF-8
urllib to manage URLs Use maximum 80 columns for your code
Write each statement on its own line
Let’s introduce how to use a module of the standard library. You already Functions, variable names and file names are lowercase, with
know how to use modules you create, importing from other files in the underscores between words (snake_case)
program folder. Class names are capitalized, separate words are written with the capital
letter too, (CamelCase)
Well that’s the same with modules provided by the standard library: Package names are lowercase and do not have underscores between
words
import math Variables that should not change (constants) are written in uppercase
Variable names should be meaningful
[Link](4) # 2.0 Add useful comments, but avoid obvious comments
Add spaces around operators
Do not use unnecessary whitespace
Add a blank line before a function If you declare it outside of any function, the variable is visible to any code
Add a blank line between methods in a class running after the declaration, including functions:
Inside functions/methods, blank lines can be used to separate related
blocks of code to help readability age = 8
You debug by adding one breakpoint into your code: If you define a variable inside a function, that variable is a local variable, and
it is only visible inside that function. Outside the function, it is not reachable:
breakpoint()
def test():
You can add more breakpoints if needed. age = 8
print(age)
When the Python interpreter hits a breakpoint in your code, it will stop, and it
will tell you what is the next instruction it will run. test() # 8
You can press n to step to the next line in the current function. If the code 29. Accept arguments from the command
calls functions, the debugger does not get into them, and consider them
“black boxes”.
line
Python offers several ways to handle arguments passed when we invoke
You can press s to step to the next line in the current function. If the next
the program from the command line.
line is a function, the debugger goes into that, and you can then run one
instruction of that function at a time.
So far you’ve run programs either from a REPL, or using
You can press c to continue the execution of the program normally, without
the need to do it step-by-step. python <filename>.py
You can press q to stop the execution of the program. You can pass additional arguments and options when you do so, like this:
A basic way to handle those arguments is to use the sys module from the
28. Variables scope standard library.
When you declare a variable, that variable is visible in parts of your program,
You can get the arguments passed in the [Link] list:
depending on where you declare it.
import sys You can set an option to have a specific set of values, using choices:
print(len([Link]))
print([Link]) parser.add_argument('-c', '--color', metavar='color', required=True
choices={'red','yellow'}, help='the color to search for')
The [Link] list contains as the first item the name of the file that was
ran, e.g. ['[Link]'].
➜ python python [Link] -c blue
This is a simple way, but you have to do a lot of work. You need to validate usage: [Link] [-h] -c color
arguments, make sure their type is correct, you need to print feedback to the [Link]: error: argument -c/--color: invalid choice: 'blue'
user if they are not using the program correctly. (choose from 'yellow', 'red')
Python provides another package in the standard library to help you: There are more options, but those are the basics.
argparse.
And there are community packages that provide this functionality, too, like
First you import argparse and you call [Link](), Click and Python Prompt Toolkit.
passing the description of your program:
Lambda functions (also called anonymous functions) are tiny functions that
parser = [Link]( have no name and only have one expression as their body.
description='This program prints the name of my dogs'
) In Python they are defined using the lambda keyword:
Then you proceed to add arguments you want to accept. For example in this lambda <arguments> : <expression>
program we accept a -c option to pass a color, like this: python
[Link] -c red
The body must be a single expression. Expression, not a statement.
lambda a, b : a * b
print([Link]) # 'red'
Lambda functions cannot be invoked directly, but you can assign them to
If the argument is not specified, the program raises an error: variables:
The common way to explain recursion is by using the factorial calculation. def talk(phrase):
def say(word):
The factorial of a number is the number n mutiplied by n-1, multiplied by n-
print(word)
2… and so on, until reaching the number 1:
words = [Link](' ')
3! = 3 * 2 * 1 = 6 for word in words:
4! = 4 * 3 * 2 * 1 = 24 say(word)
5! = 5 * 4 * 3 * 2 * 1 = 120
talk('I am going to buy the milk')
Using recursion we can write a function that calculates the factorial of any
number: If you want to access a variable defined in the outer function from the inner
function, you first need to declare it as nonlocal:
def factorial(n):
if n == 1: return 1 def count():
return n * factorial(n-1) count = 0
default will halt recursions at 1000 calls, and when this limit is reached, you
will get a RecursionError error. count()
Recursion is helpful in many places, and it helps us simplify our code when This is useful especially with closures, as we’ll see later.
there’s no other optimal way to do it, so it’s good to know this technique.
33. Closures
32. Nested Functions
If you return a nested function from a function, that nested function has
Functions in Python can be nested inside other functions. access to the variables defined in that function, even if that function is not
active any more.
A function defined inside a function is visible only inside that function.
Here is a simple counter example.
# do something after
def counter():
return val
count = 0
return wrapper
def increment():
nonlocal count
35. Docstrings
count = count + 1
return count
Documentation is hugely important, not just to communicate to other
people what is the goal of a function/class/method/module, but also to
return increment
yourself.
increment = counter()
When you’ll come back to your code 6 or 12 months from now, you might
not remember all the knowledge you are holding in your head, and reading
print(increment()) # 1
your code and understanding what it is supposed to do, will be much more
print(increment()) # 2
difficult.
print(increment()) # 3
34. Decorators
Another way is to use docstrings.
Decorators are a way to change, enhance or alter in any way how a function
works. The utility of docstrings is that they follow conventions and as such they can
be processed automatically.
Decorators are defined with the @ symbol followed by the decorator name,
just before the function definition. This is how you define a docstring for a function:
This hello function has the logtime decorator assigned. class Dog:
"""A class representing a dog"""
Whenever we call hello(), the decorator is going to be called. def __init__(self, name, age):
"""Initialize a new dog"""
A decorator is a function that takes a function as a parameter, wraps the [Link] = name
function in an inner function that performs the job it has to do, and returns [Link] = age
that inner function. In other words:
def bark(self):
def logtime(func): """Let the dog bark"""
def wrapper(): print('WOF!')
# do something before
val = func()
Document a module by placing a docstring at the top of the file, for example I like Google’s standard: [Link]
supposing this is [Link]: pages/[Link]#38-comments-and-docstrings
"""Dog module
Standard allows to have tools to extract docstrings and automatically
generate documentation for your code.
This module does ... bla bla bla and provides the following classes
36. Introspection
- Dog
... Functions, variables and objects can be analyzed using introspection.
"""
First, using the help() global function we can get the documentation if
class Dog: provided in form of docstrings.
"""A class representing a dog"""
def __init__(self, name, age): Then, you can use print() to get information about a function:
"""Initialize a new dog"""
[Link] = name def increment(n):
[Link] = age return n + 1
or an object:
Docstrings can span over multiple lines:
class Dog():
def increment(n):
def bark(self):
"""Increment
print('WOF!')
a number
"""
roger = Dog()
return n + 1
print(roger)
Python will process those and you can use the help() global function to
get the documentation for a class/method/function/module. # <__main__.Dog object at 0x7f42099d3340>
increment(n)
print(type(roger))
Increment
# <class '__main__.Dog'>
a number
print(type(1))
There are many different standards to format docstrings, and you can # <class 'int'>
choose to adhere to your favorite one.
print(type('test'))
count: int = 0
# <class 'str'>
Python will ignore those annotations. A separate tool called mypy can be run
The dir() global function lets us find out all the methods and attributes of
standalone, or integrated by IDE like VS Code or PyCharm to automatically
an object:
check for type errors statically, while you are coding, and it will help you
catch type mismatch bugs before even running the code.
print(dir(roger))
A great help especially when your software becomes large and you need to
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', refactor your code.
# '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
# '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
38. Exceptions
# '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__'
# '__repr__', '__setattr__', '__sizeof__', '__str__',
It’s important to have a way to handle errors.
# '__subclasshook__', '__weakref__', 'bark']
The id() global function shows us the location in memory of any object: If you wrap lines of code into a try: block:
print(id(roger)) # 140227518093024
try:
print(id(1)) # 140227521172384
# some lines of code
Annotations allow us to (optionally) do that. To catch all exceptions you can use except without any error type:
try: You can raise exceptions in your own code, too, using the raise statement:
# some lines of code
except <ERROR1>:
raise Exception('An error occurred!')
# handler <ERROR1>
except <ERROR2>:
# handler <ERROR2>
This raises a general exception, and you can intercept it using:
else:
# no exceptions were raised, the code ran successfully try:
finally: raise Exception('An error occurred!')
# do something in any case except Exception as error:
print(error)
The specific error that’s going to occur depends on the operation you’re
performing. You can also define your own exception class, extending from Exception:
For example if you are reading a file, you might get an EOFError. If you class DogNotFoundException(Exception):
divide a number by zero you will get a ZeroDivisionError. If you have a pass
type conversion issue you might get a TypeError.
pass here means “nothing” and we must use it when we define a class
Try this code:
without methods, or a function without code, too.
result = 2 / 0
try:
print(result)
raise DogNotFoundException()
except DogNotFoundException:
The program will terminate with an error print('Dog not found!')
and the lines of code after the error will not be executed.
For example when working with files, each time we open a file, we must
remember to close it.
Adding that operation in a try: block lets us recover gracefully and move
on with the program:
with makes this process transparent.
Instead of writing:
filename = '/Users/flavio/[Link]' python -m pip install <package>
try:
For example you can install the requests package, a popular HTTP library:
file = open(filename, 'r')
content = [Link]()
pip install requests
print(content)
finally:
[Link]() and once you do, it will be available for all your Python scripts, because
packages are installed globally.
In other words we have built-in implicit exception handling, as close() will pip install –U <package>
be called automatically for us.
Install a specific version of a package using:
with is not just helpful to work with files. The above example is just meant
to introduce its capabilities.
pip install <package>==<version>
40. Installing 3rd party packages using pip Uninstall a package using:
The Python standard library contains a huge number of utilities that simplify
our Python development needs, but nothing can satisfy everything. pip uninstall <package>
That’s why individuals and companies create packages, and make them Show an installed package details, including version, documentation
available as open source software for the entire community. website and author information using:
Those modules are all collected in a single place, the Python Package Index
pip show <package>
available at [Link] and they can be installed on your system using
pip.
41. List comprehensions
There are more than 270.000 packages freely available, at the time of
writing. List comprehensions are a way to create lists in a very concise way.
You should have pip already installed if you followed the Python installation Suppose you have a list:
instructions.
numbers = [1, 2, 3, 4, 5]
Install any package using the command pip install:
You can create a new list using a list comprehension, composed by the
pip install <package>
numbers list elements, power 2:
or, if you do have troubles, you can also run it through python -m:
numbers_power_2 = [n**2 for n in numbers] Operator overloading is an advanced technique we can use to make classes
# [1, 4, 9, 16, 25] comparable and to make them work with Python operators.
42. Polymorphism
We can use operator overloading to add a way to compare those 2 objects,
Polymorphism generalizes a functionality so it can work on different types. based on the age property:
It’s an important concept in object-oriented programming.
class Dog:
We can define the same method on different classes: # the Dog class
def __init__(self, name, age):
class Dog: [Link] = name
def eat(): [Link] = age
print('Eating dog food') def __gt__(self, other):
return True if [Link] > [Link] else False
class Cat:
def eat():
Now if you try running print(roger > syd) you will get the result True.
print('Eating cat food')
In the same way we defined __gt__() (which means greater than), we can
Then we can generate objects and we can call the eat() method define the following methods:
regardless of the class the object belongs to, and we’ll get different results:
__eq__() to check for equality
animal1 = Dog()
__lt__() to check if an object should be considered lower than
animal2 = Cat() another with the < operator
__le__() for lower or equal (<=)
[Link]() __ge__() for greater or equal (>=)
[Link]() __ne__() for not equal (!=)
Then run
source .venv/bin/activate
➜ folder
to
(.venv) ➜ folder