The Python Handbook Print

  • internetivo, python, handbook, tutorial
  • 8

The Python Handbook follows the 80/20 rule: learn 80% of the topic in 20% of the time.

I find this approach gives a well-rounded overview.

This book does not try to cover everything under the sun related to Python. It focuses on the core of the language, trying to simplify the more complex topics.

I hope the contents of this book will help you achieve what you want: learn the basics of Python.

Note: You can get a PDF, ePub and Mobi version of this Python Handbook

Enjoy!

Summary

Introduction to Python

Python is literally eating the programming world. It is growing in popularity and usage in ways that are pretty much unprecedented in the history of computers.

Python excels in a wide variety of scenarios – Shell scripting, task automation, and Web development are just some basic examples.

Python is the language of choice for data analysis and machine learning, but it can also adapt to create games and work with embedded devices.

Most importantly, it's the language of choice for introductory computer science courses in universities all around the world.

Many students learn Python as their first programming language. Many are learning it right now, and many more will learn it in the future. And for many of them, Python will be the only programming language they need.

Thanks to this unique position, Python is likely going to grow even more in the future.

The language is simple, expressive, and it's quite straightforward.

The ecosystem is huge. There seems to be a library for everything you can imagine.

Python is a high-level programming language suitable for beginners thanks to its intuitive syntax, its huge community, and its vibrant ecosystem.

It is also appreciated by professionals across many different fields.

Technically speaking Python is an interpreted language that does not have an intermediate compilation phase like a compiled language, for example C or Java.

And like many interpreted languages, it is dynamically typed. This means that you do not have to indicate the types of the variables you use, and variables are not tied to a specific type.

This has pros and cons. In particular, you write programs faster, but on the other hand you have less help from the tools to prevent possible bugs. This means that you will find out about certain issues only by executing the program at runtime.

Python supports a wide variety of different programming paradigms, including procedural programming, object oriented programming, and functional programming. It's flexible enough to adapt to a lot of different needs.

Created in 1991 by Guido van Rossum, it's been rising in popularity - especially in the past 5 years, as this Google Trends infographic shows:

Screen-Shot-2020-11-09-at-19.22.38

Starting with Python is very easy. All you need is to install the official package from python.org, for Windows, macOS or Linux, and you're ready to go.

If you are new to programming, in the following posts I will guide you to go from zero to becoming a Python programmer.

And even if you are currently a programmer who specializes in another language, Python is a language worth knowing because I think it's only going to keep growing from here.

Lower level languages like C++ and Rust might be great for expert programmers, but they're daunting to begin with, and they take a long time to master.

Python, on the other hand, is a programming language for everyone – students, people doing their day jobs with Excel, scientists, and more.

It's the language everyone interested in coding should learn first.

How to Install Python

Go to https://www.python.org, choose the Downloads menu, choose your operating system, and a panel with a link to download the official package will appear:

Screen-Shot-2020-11-09-at-13.57.36-1

Make sure you follow the specific instructions for your operating system. On macOS you can find a detailed guide on https://flaviocopes.com/python-installation-macos/.

How to Run Python Programs

There are a few different ways to run Python programs.

In particular, there's a distinction between using interactive prompts, where you type Python code and it's immediately executed, and saving a Python program into a file and executing that.

Let's start with interactive prompts.

If you open your terminal and type python, you will see a screen like this:

Screen-Shot-2020-11-10-at-13.44.07

This is the Python REPL (Read-Evaluate-Print-Loop).

Notice the >>> symbol, and the cursor after that. You can type any Python code here, and press the enter key to run it.

For example try defining a new variable using

name = "Flavio"

and then print its value, using print():

print(name)

Screen-Shot-2020-11-10-at-14.11.57

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 output if you do so - you need to use print() instead.

Any line of Python you write here is going to be executed immediately.

Type quit() to exit this Python REPL.

You can access the same interactive prompt using the IDLE application that's installed by Python automatically:

Screen-Shot-2020-11-10-at-14.13.25

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 that you install IPython, probably the best command line REPL application you can find.

Install it with

pip install ipython

Make sure the pip binaries are in your path, then run ipython:

Screen-Shot-2020-11-11-at-09.36.29

ipython is another interface that lets you work with a Python REPL, and provides some nice features like syntax highlighting, code completion, and much more.

The second way to run a Python program is to write your Python program code into a file, for example program.py:

Screen-Shot-2020-11-10-at-14.01.24

and then run it with python program.py:

Screen-Shot-2020-11-10-at-14.01.32

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.

We use the REPL for quick prototyping and for learning.

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.

On my system the Python executable is located in /usr/bin/python3, so I type #!/usr/bin/python3 in the first line:

Screen-Shot-2020-11-10-at-14.17.26

Then I can set execution permission on the file:

chmod u+x program.py

and I can run the program with

./program.py

Screen-Shot-2020-11-10-at-14.18.42

This is especially useful when you write scripts that interact with the terminal.

We have many other ways to run Python programs.

One of them is using VS Code, and in particular the official Python extension from Microsoft:

Screen-Shot-2020-11-10-at-14.23.32

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:

Python: Start REPL to run the REPL in the integrated terminal:

Screen-Shot-2020-11-10-at-14.31.36

Python: Run Python File in Terminal to run the current file in the terminal:

Screen-Shot-2020-11-10-at-14.31.06

Python: Run Current File in Python Interactive Window:

Screen-Shot-2020-11-10-at-14.30.02-1

and many more. Just open the command palette (View -> Command Palette, or Cmd-Shift-P) and type python to see all the Python-related commands:

Screen-Shot-2020-11-10-at-14.30.02

Another way to easily run Python code is to use repl.it, a very nice website that provides a coding environment you can create and run your apps on, in any language, Python included:

Screen-Shot-2020-11-10-at-14.33.58

Signup (it's free), then under "create a repl" click Python:

Screen-Shot-2020-11-10-at-14.46.34

and you will be immediately shown an editor with a main.py file, ready to be filled with a lot of Python code:

Screen-Shot-2020-11-10-at-14.47.15

Once you have some code, click "Run" to run it on the right side of the window:

Screen-Shot-2020-11-10-at-14.48.09

I think repl.it is handy because:

  • you can easily share code just by sharing the link
  • multiple people can work on the same code
  • it can host long-running programs
  • you can install packages
  • it provides you a key-value database for more complex applications

Python 2 vs Python 3

One key topic we should address, right from the start, is the Python 2 vs Python 3 discussion.

Python 3 was introduced in 2008, and it's been in development as the main Python version, while Python 2 continued being maintained with bug fixes and security patches until early 2020.

On that date, Python 2 support was discontinued.

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 it would require a lot of work to upgrade those programs. And large and important migrations always introduce new bugs.

But new code, unless you have to adhere to rules set by your organization that forces Python 2, should always be written in Python 3.

This book focuses on Python 3.

Python Basics

Variables in Python

We can create a new Python variable by assigning a value to a label, using the = assignment operator.

In this example we assign a string with the value "Roger" to the name label:

name = "Roger"

Here's an example with a number:

age = 8

A variable name can be composed of characters, numbers, and the _ underscore character. It can't start with a number. These are all valid variable names:

name1
AGE
aGE
a11111
my_name
_name

These are invalid variable names:

123
test!
name%

Other than that, anything is valid unless it's a Python keyword. There are some keywords like for, if, while, import and more.

There's no need to memorize them, as Python will alert you if you use one of those as a variable, and you will gradually recognize them as part of the Python programming language syntax.

Expressions and statements in Python

We can expression any sort of code that returns a value. For example

1 + 1
"Roger"

A statement, on the other hand, is an operation on a value. For example these are 2 statements:

name = "Roger"
print(name)

A program is formed by a series of statements. Each statement is put on its own line, but you can use a semicolon to have more than one statement on a single line:

name = "Roger"; print(name)

Comments

In a Python program, everything after a hash mark is ignored, and considered a comment:

#this is a commented line

name = "Roger" # this is an inline comment

Indentation in Python

Indentation in Python is meaningful.

You cannot indent randomly like this:

name = "Flavio"
    print(name)

Some other languages do not have meaningful whitespace, but in Python, indentation matters.

In this case, if you try to run this program you would get a IndentationError: unexpected indent error, because indenting has a special meaning.

Everything indented belongs to a block, like a control statement or conditional block, or a function or class body. We'll see more about those later on.

Data Types in Python

Python has several built-in types.

If you create the name variable assigning it the value "Roger", automatically this variable now represents a String data type.

name = "Roger"

You can check the type of a variable by using the type() function, passing the variable as an argument, and then comparing the result to str:

name = "Roger"
type(name) == str #True

Or using isinstance():

name = "Roger"
isinstance(name, str) #True

Notice that to see the True value in Python, outside of a REPL, you need to wrap this code inside print(), but for clarity I avoid using it.

We used the str class here, but the same works for other data types.

First, we have numbers. Integer numbers are represented using the int class. Floating point numbers (fractions) are of type float:

age = 1
type(age) == int #True
fraction = 0.1
type(fraction) == float #True

You saw how to create a type from a value literal, like this:

name = "Flavio"
age = 20

Python automatically detects the type from the value type.

You can also create a variable of a specific type by using the class constructor, passing a value literal or a variable name:

name = str("Flavio")
anotherName = str(name)

You can also convert from one type to another by using the class constructor. Python will try to determine the correct value, for example extracting a number from a string:

age = int("20")
print(age) #20

fraction = 0.1
intFraction = int(fraction)
print(intFraction) #0

This is called casting. Of course this conversion might not always work depending on the value passed. If you write test instead of 20 in the above string, you'll get a ValueError: invalid literal for int() with base 10: 'test' error.

Those are just the basics of types. We have a lot more types in Python:

  • complex for complex numbers
  • bool for booleans
  • list for lists
  • tuple for tuples
  • range for ranges
  • dict for dictionaries
  • set for sets

and more!

We'll explore them all soon.

Operators in Python

Python operators are symbols that we use to run operations upon values and variables.

We can divide operators based on the kind of operation they perform:

  • assignment operator
  • arithmetic operators
  • comparison operators
  • logical operators
  • bitwise operators

plus some interesting ones like is and in.

Assignment operator in Python

The assignment operator is used to assign a value to a variable:

age = 8

Or to assign a variable value to another variable:

age = 8
anotherVariable = age

Since Python 3.8, the := walrus operator is used to assign a value to a variable as part of another operation. For example inside an if or in the conditional part of a loop. More on that later.

Arithmetic operators in Python

Python has a number of arithmetic operators: +, -, *, / (division), % (remainder), ** (exponentiation) and // (floor division):

1 + 1 #2
2 - 1 #1
2 * 2 #4
4 / 2 #2
4 % 3 #1
4 ** 2 #16
4 // 2 #2

Note that you don't need a space between the operands, but it's good for readability.

- also works as a unary minus operator:

print(-4) #-4

+ is also used to concatenate String values:

"Roger" + " is a good dog"
#Roger is a good dog

We can combine the assignment operator with arithmetic operators:

  • +=
  • -=
  • *=
  • /=
  • %=
  • ..and so on

Example:

age = 8
age += 1
# age is now 9

Comparison operators in Python

Python defines a few comparison operators:

  • ==
  • !=
  • >
  • <
  • >=
  • <=

You can use those operators to get a boolean value (True or False) depending on the result:

a = 1
b = 2

a == b #False
a != b #True
a > b #False
a <= b #True

Boolean operators in Python

Python gives us the following boolean operators:

  • not
  • and
  • or

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:

condition1 = True
condition2 = False

not condition1 #False
condition1 and condition2 #False
condition1 or condition2 #True

Otherwise, pay attention to a possible source of confusion:

or used in an expression returns the value of the first operand that is not a falsy value (False, 0, '', []..). Otherwise it returns the last operand.

print(0 or 1) ## 1
print(False or 'hey') ## 'hey'
print('hi' or 'hey') ## 'hi'
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:

print(0 and 1) ## 0
print(1 and 0) ## 0
print(False and 'hey') ## False
print('hi' and 'hey') ## 'hey'
print([] and False ) ## []
print(False and [] ) ## False

The Python docs describe it as if x is false, then x, else y.

Bitwise operators in Python

Some operators are used to work on bits and binary numbers:

  • & performs binary AND
  • | performs binary OR
  • ^ performs a binary XOR operation
  • ~ performs a binary NOT operation
  • << shift left operation
  • >> shift right operation

Bitwise operators are rarely used, only in very specific situations, but they are worth mentioning.

is and in in Python

is is called the identity operator. It is used to compare two objects and returns true if both are the same object. More on objects later.

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.

The Ternary Operator in Python

The ternary operator in Python allows you to quickly define a conditional.

Let's say you have a function that compares an age variable to the 18 value, and returns True or False depending on the result.

Instead of writing:

def is_adult(age):
    if age > 18:
        return True
    else:
        return False

You can implement it with the ternary operator in this way:

def is_adult(age):
    return True if age > 18 else False

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:

<result_if_true> if <condition> else <result_if_false>

Strings in Python

A string in Python is a series of characters enclosed in quotes or double quotes:

"Roger"
'Roger'

You can assign a string value to a variable:

name = "Roger"

You can concatenate two strings using the + operator:

phrase = "Roger" + " is a good dog"

You can append to a string using +=:

name = "Roger"
name += " is a good dog"

print(name) #Roger is a good dog

You can convert a number to a string using the str class constructor:

str(8) #"8"

This is essential to concatenate a number to a string:

print("Roger is " + str(8) + " years old") #Roger is 8 years old

A string can be multi-line when defined with a special syntax, enclosing the string in a set of 3 quotes:

print("""Roger is

    8

years old
""")

#double quotes, or single quotes

print('''
Roger is

    8

years old
''')

A string has a set of built-in methods, like:

  • isalpha() to check if a string contains only characters and is not empty
  • isalnum() to check if a string contains characters or digits and is not empty
  • isdecimal() to check if a string contains digits and is not empty
  • lower() to get a lowercase version of a string
  • islower() to check if a string is lowercase
  • upper() to get an uppercase version of a string
  • isupper() to check if a string is uppercase
  • title() to get a capitalized version of a string
  • startsswith() to check if the string starts with a specific substring
  • endswith() to check if the string ends with a specific substring
  • replace() to replace a part of a string
  • split() to split a string on a specific character separator
  • strip() to trim the whitespace from a string
  • join() to append new letters to a string
  • find() to find the position of a substring

and many more.

None of those methods alter the original string. They return a new, modified string instead. For example:

name = "Roger"
print(name.lower()) #"roger"
print(name) #"Roger"

You can use some global functions to work with strings, too.

In particular I think of len(), which gives you the length of a string:

name = "Roger"
print(len(name)) #5

The in operator lets you check if a string contains a substring:

name = "Roger"
print("ger" in name) #True

Escaping is a way to add special characters into a string.

For example, how do you add a double quote into a string that's wrapped into double quotes?

name = "Roger"

"Ro"Ger" will not work, as Python will think the string ends at "Ro".

The way to go is to escape the double quote inside the string, with the \ backslash character:

name = "Ro\"ger"

This applies to single quotes too \', and for special formatting characters like \t for tab, \n for new line and \\ for the backslash.

Given a string, you can get its characters using square brackets to get a specific item, given its index, starting from 0:

name = "Roger"
name[0] #'R'
name[1] #'o'
name[2] #'g'

Using a negative number will start counting from the end:

name = "Roger"
name[-1] #"r"

You can also use a range, using what we call slicing:

name = "Roger"
name[0:2] #"Ro"
name[:2] #"Ro"
name[2:] #"ger"

Booleans in Python

Python provides the bool type, which can have two values: True and False (capitalized).

done = False
done = True

Booleans are especially useful with conditional control structures like if statements:

done = True

if done:
    # run some code here
else:
    # run some other code

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:

  • numbers are always True except for the number 0
  • strings are False only when empty
  • lists, tuples, sets, and dictionaries are False only when empty

You can check if a value is a boolean in this way:

done = True
type(done) == bool #True

Or using isinstance(), passing 2 arguments: the variable, and the bool class:

done = True
isinstance(done, bool) #True

The global any() function is also very useful when working with booleans, as it returns True if any of the values of the iterable (list, for example) passed as argument are True:

book_1_read = True
book_2_read = False

read_any_book = any([book_1_read, book_2_read])

The global all() function is same, but returns True if all of the values passed to it are True:

ingredients_purchased = True
meal_cooked = False

ready_to_serve = all([ingredients_purchased, meal_cooked])

Numbers in Python

Numbers in Python can be of 3 types: int, float and complex.

Integer numbers in Python

Integer numbers are represented using the int class. You can define an integer using a value literal:

age = 8

You can also define an integer number using the int() constructor:

age = int(8)

To check if a variable is of type int, you can use the type() global function:

type(age) == int #True

Floating point numbers in Python

Floating point numbers (fractions) are of type float. You can define an integer using a value literal:

fraction = 0.1

Or using the float() constructor:

fraction = float(0.1)

To check if a variable is of type float, you can use the type() global function:

type(fraction) == float #True

Complex numbers in Python

Complex numbers are of type complex.

You can define them using a value literal:

complexNumber = 2+3j

or using the complex() constructor:

complexNumber = complex(2, 3)

Once you have a complex number, you can get its real and imaginary part:

complexNumber.real #2.0
complexNumber.imag #3.0

Again, to check if a variable is of type complex, you can use the type() global function:

type(complexNumber) == complex #True

Arithmetic operations on numbers in Python

You can perform arithmetic operations on numbers, using the arithmetic operators: +, -, *, / (division), % (remainder), ** (exponentiation) and // (floor division):

1 + 1 #2
2 - 1 #1
2 * 2 #4
4 / 2 #2
4 % 3 #1
4 ** 2 #16
4 // 2 #2

and you can use the compound assignment operators

  • +=
  • -=
  • *=
  • /=
  • %=
  • ..and so on

to quickly perform operations on variables, too:

age = 8
age += 1

Built-in Functions in Python

There are 2 built-in functions that help with numbers:

abs() returns the absolute value of a number.

round() given a number, returns its value rounded to the nearest integer:

round(0.12) #0

You can specify a second parameter to set the decimal point's precision:

round(0.12, 1) #0.1

Several other math utility functions and constants are provided by the Python standard library:

  • the math package provides general math functions and constants
  • the cmath package provides utilities to work with complex numbers.
  • the decimal package provides utilities to work with decimals and floating point numbers.
  • the fractions package provides utilities to work with rational numbers.

We'll explore some of those separately later on.

Constants in Python

Python has no way to enforce that a variable should be a constant.

The nearest you can get is to use an enum:

class Constants(Enum):
    WIDTH = 1024
    HEIGHT = 256

And get to each value using, for example, Constants.WIDTH.value.

No one can reassign that value.

Otherwise if you want to rely on naming conventions, you can adhere to this one: declare variables that should never change uppercase:

WIDTH = 1024

No one will prevent you from overwriting this value, and Python will not stop it.

That's what most Python code does that you will see.

Enums in Python

Enums are readable names that are bound to a constant value.

To use enums, import Enum from the enum standard library module:

from enum import Enum

Then you can initialize a new enum in this way:

class State(Enum):
    INACTIVE = 0
    ACTIVE = 1

Once you do so, you can reference State.INACTIVE and State.ACTIVE, and they serve as constants.

Now if you try to print State.ACTIVE for example:

print(State.ACTIVE)

it will not return 1, but State.ACTIVE.

The same value can be reached by the number assigned in the enum: print(State(1)) will return State.ACTIVE. Same for using the square brackets notation State['ACTIVE'].

You can, however, get the value using State.ACTIVE.value.

You can list all the possible values of an enum:

list(State) # [<State.INACTIVE: 0>, <State.ACTIVE: 1>]

You can count them:

len(State) # 2

User Input in Python

In a Python command line application you can display information to the user using the print() function:

name = "Roger"
print(name)

We can also accept input from the user, using input():

print('What is your age?')
age = input()
print('Your age is ' + age)

This approach gets input at runtime, meaning the program will stop execution and will wait until the user types something and presses the enter key.

You can also do more complex input processing and accept input at program invocation time, and we'll see how to do that later on.

This works for command line applications. Other kinds of applications will need a different way of accepting input.

Control Statements in Python

When you're dealing with booleans, and expressions that return a boolean in particular, we can make decisions and take different roads depending on their True or False values.

In Python we do so using the if statement:

condition = True

if condition == True:
    # do something

When the condition test resolves to True, like in the above case, its block gets executed.

What is a block? A block is that part that is indented one level (4 spaces usually) on the right:

condition = True

if condition == True:
    print("The condition")
    print("was true")

The block can be formed by a single line, or multiple lines as well, and it ends when you move back to the previous indentation level:

condition = True

if condition == True:
    print("The condition")
    print("was true")

print("Outside of the if")

In combination with if you can have an else block that's executed if the condition test of if results to False:

condition = True

if condition == True:
    print("The condition")
    print("was True")
else:
    print("The condition")
    print("was False")

And you can have different linked if checks with elif that's executed if the previous check was False:

condition = True
name = "Roger"

if condition == True:
    print("The condition")
    print("was True")
elif name == "Roger":
    print("Hello Roger")
else:
    print("The condition")
    print("was False")

The second block in this case is executed if condition is False, and the name variable value is "Roger".

In a if statement you can have just one if and else check, but multiple series of elif checks:

condition = True
name = "Roger"

if condition == True:
    print("The condition")
    print("was True")
elif name == "Roger":
    print("Hello Roger")
elif name == "Syd":
    print("Hello Syd")
elif name == "Flavio":
    print("Hello Flavio")
else:
    print("The condition")
    print("was False")

if and else can also be used in an inline format, which lets us return one value or another based on a condition.

Example:

a = 2
result = 2 if a == 0 else 3
print(result) # 3

Lists in Python

Lists are an essential Python data structure.

The allow you to group together multiple values and reference them all with a common name.

For example:

dogs = ["Roger", "Syd"]

A list can hold values of different types:

items = ["Roger", 1, "Syd", True]

You can check if an item is contained in a list with the in operator:

print("Roger" in items) # True

A list can also be defined as empty:

items = []

You can reference the items in a list by their index, starting from zero:

items[0] # "Roger"
items[1] # 1
items[3] # True

Using the same notation you can change the value stored at a specific index:

items[0] = "Roger"

You can also use the index() method:

items.index(0) # "Roger"
items.index(1) # 1

As with strings, using a negative index will start searching from the end:

items[-1] # True

You can also extract a part of a list, using slices:

items[0:2] # ["Roger", 1]
items[2:] # ["Syd", True]

Get the number of items contained in a list using the len() global function, the same we used to get the length of a string:

len(items) #4

You can add items to the list by using a list append() method:

items.append("Test")

or the extend() method:

items.extend(["Test"])

You can also use the += operator:

items += ["Test"]

# items is ['Roger', 1, 'Syd', True, 'Test']

Tip: with extend() or += don't forget the square brackets. Don't do items += "Test" or items.extend("Test") or Python will add 4 individual characters to the list, resulting in ['Roger', 1, 'Syd', True, 'T', 'e', 's', 't']

Remove an item using the remove() method:

items.remove("Test")

You can add multiple elements using

items += ["Test1", "Test2"]

#or

items.extend(["Test1", "Test2"])

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() method:

items.insert("Test", 1) # add "Test" at index 1

To add multiple items at a specific index, you need to use slices:

items[1:1] = ["Test1", "Test2"]

Sort a list using the sort() method:

items.sort()

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 like TypeError: '<' not supported between instances of 'int' and 'str' if you try.

The sort() methods orders uppercase letters first, then lowercase letters. To fix this, use:

items.sort(key=str.lower)

instead.

Sorting modifies the original list content. To avoid that, you can copy the list content using

itemscopy = items[:]

or use the sorted() global function:

print(sorted(items, key=str.lower))

that will return a new list, sorted, instead of modifying the original list.

Tuples in Python

Tuples are another fundamental Python data structure.

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.

They are created in a way similar to lists, but using parentheses instead of square brackets:

names = ("Roger", "Syd")

A tuple is ordered, like a list, so you can get its values by referencing an index value:

names[0] # "Roger"
names[1] # "Syd"

You can also use the index() method:

names.index('Roger') # 0
names.index('Syd')   # 1

As with strings and lists, using a negative index will start searching from the end:

names[-1] # True

You can count the items in a tuple with the len() function:

len(names) # 2

You can check if an item is contained in a tuple with the in operator:

print("Roger" in names) # True

You can also extract a part of a tuple, using slices:

names[0:2] # ('Roger', 'Syd')
names[1:] # ('Syd',)

Get the number of items in a tuple using the len() global function, the same we used to get the length of a string:

len(names) #2

You can create a sorted version of a tuple using the sorted() global function:

sorted(names)

You can create a new tuple from existing tuples using the + operator:

newTuple = names + ("Vanille", "Tina")

Dictionaries in Python

Dictionaries are a very important Python data structure.

While lists allow you to create collections of values, dictionaries allow you to create collections of key / value pairs.

Here is a dictionary example with one key/value pair:

dog = { 'name': 'Roger' }

The key can be any immutable value like a string, a number or a tuple. The value can be anything you want.

A dictionary can contain multiple key/value pairs:

dog = { 'name': 'Roger', 'age': 8 }

You can access individual key values using this notation:

dog['name'] # 'Roger'
dog['age']  # 8

Using the same notation you can change the value stored at a specific index:

dog['name'] = 'Syd'

And another way is using the get() method, which has an option to add a default value:

dog.get('name') # 'Roger'
dog.get('test', 'default') # 'default'

The pop() method retrieves the value of a key, and subsequently deletes the item from the dictionary:

dog.pop('name') # 'Roger'

The popitem() method retrieves and removes the last key/value pair inserted into the dictionary:

dog.popitem()

You can check if a key is contained into a dictionary with the in operator:

'name' in dog # True

Get a list with the keys in a dictionary using the keys() method, passing its result to the list() constructor:

list(dog.keys()) # ['name', 'age']

Get the values using the values() method, and the key/value pairs tuples using the items() method:

print(list(dog.values()))
# ['Roger', 8]

print(list(dog.items()))
# [('name', 'Roger'), ('age', 8)]

Get a dictionary length using the len() global function, the same we used to get the length of a string or the items in a list:

len(dog) #2

You can add a new key/value pair to the dictionary in this way:

dog['favorite food'] = 'Meat'

You can remove a key/value pair from a dictionary using the del statement:

del dog['favorite food']

To copy a dictionary, use the copy() method:

dogCopy = dog.copy()

Sets in Python

Sets are another important Python data structure.

We can say they work like tuples, but they are not ordered, and they are mutable.

Or we can say they work like dictionaries, but they don't have keys.

They also have an immutable version, called frozenset.

You can create a set using this syntax:

names = {"Roger", "Syd"}

Sets work well when you think about them as mathematical sets.

You can intersect two sets:

set1 = {"Roger", "Syd"}
set2 = {"Roger"}

intersect = set1 & set2 #{'Roger'}

You can create a union of two sets:

set1 = {"Roger", "Syd"}
set2 = {"Luna"}

union = set1 | set2
#{'Syd', 'Luna', 'Roger'}

You can get the difference between two sets:

set1 = {"Roger", "Syd"}
set2 = {"Roger"}

difference = set1 - set2 #{'Syd'}

You can check if a set is a superset of another (and of course if a set is a subset of another):

set1 = {"Roger", "Syd"}
set2 = {"Roger"}

isSuperset = set1 > set2 # True

You can count the items in a set with the len() global function:

names = {"Roger", "Syd"}
len(names) # 2

You can get a list from the items in a set by passing the set to the list() constructor:

names = {"Roger", "Syd"}
list(names) #['Syd', 'Roger']

You can check if an item is contained in a set with the in operator:

print("Roger" in names) # True

Functions in Python

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 languages. They help us create meaningful programs because they allow us to decompose a program into manageable parts, and they promote readability and code reuse.

Here is an example function called hello that prints "Hello!":

def hello():
    print('Hello!')

This is the function definition. There is a name (hello) and a body, the set of instructions, which is the part that follows the colon. It's indented one level on the right.

To run this function, we must call it. This is the syntax to call the function:

hello()

We can execute this function once, or multiple times.

The name of the function, hello, is very important. It should be descriptive, so anyone calling it can imagine what the function does.

A function can accept one or more parameters:

def hello(name):
    print('Hello ' + name + '!')

In this case we call the function by passing the argument

hello('Roger')

We call parameters the values accepted by the function inside the function definition, and arguments the values we pass to the function when we call it. It's common to get confused about this distinction.

An argument can have a default value that's applied if the argument is not specified:

def hello(name='my friend'):
    print('Hello ' + name + '!')

hello()
#Hello my friend!

Here's how we can accept multiple parameters:

def hello(name, age):
    print('Hello ' + name + ', you are ' + str(age) + ' years old!')

In this case we call the function passing a set of arguments:

hello('Roger', 8)

Parameters are passed by reference. All types in Python are objects, but some of them are immutable, including integers, booleans, floats, strings, 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 function:

def change(value):
    value = 2

val = 1
change(val)

print(val) #1

If you pass an object that's not immutable, and you change one of its properties, the change will be reflected outside.

A function can return a value, using the return statement. For example in this case we return the name parameter name:

def hello(name):
    print('Hello ' + name + '!')
    return name

When the function meets the return statement, the function ends.

We can omit the value:

def hello(name):
    print('Hello ' + name + '!')
    return

We can have the return statement inside a conditional, which is a common way to end a function if a starting condition is not met:

def hello(name):
    if not name:
        return
    print('Hello ' + name + '!')

If we call the function passing a value that evaluates to False, like an empty string, the function is terminated before reaching the print() statement.

You can return multiple values by using comma separated values:

def hello(name):
    print('Hello ' + name + '!')
    return name, 'Roger', 8

In this case calling hello('Syd') the return value is a tuple containing those 3 values: ('Syd', 'Roger', 8).

Objects in Python

Everything in Python is an object.

Even values of basic primitive types (integer, string, float..) are objects. Lists are objects, as are tuples, dictionaries, everything.

Objects have attributes and methods that can be accessed using the dot syntax.

For example, try defining a new variable of type int:

age = 8

age now has access to the properties and methods defined for all int objects.

This includes, for example, access to the real and imaginary part of that number:

print(age.real) # 8
print(age.imag) # 0

print(age.bit_length()) #4

# the bit_length() method returns the number of bits necessary to represent this number in binary notation

A variable holding a list value has access to a different set of methods:

items = [1, 2]
items.append(3)
items.pop()

The methods depend on the type of value.

The id() global function provided by Python lets you inspect the location in memory for a particular object.

id(age) # 140170065725376

Your memory value will change - I am only showing it as an example.

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 stored in another location in memory:

age = 8

print(id(age)) # 140535918671808

age = 9

print(id(age)) # 140535918671840

But if you modify the object using its methods, the address stays the same:

items = [1, 2]

print(id(items)) # 140093713593920

items.append(3)

print(items) # [1, 2, 3]
print(id(items)) # 140093713593920

The address only changes if you reassign a variable to another value.

Some objects are mutable, while others are immutable. This depends on the object 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 example an int is immutable. There are no methods to change its value. If you increment the value using

age = 8
age = age + 1

#or

age += 1

and you check with id(age), you will find that age points to a different memory location. The original value has not mutated, we just switched to another value.

Loops in Python

Loops are one essential part of programming.

In Python we have 2 kinds of loops: while loops and for loops.

while loops in Python

while loops are defined using the while keyword, and they repeat their block until the condition is evaluated as False:

condition = True
while condition == True:
    print("The condition is True")

This is an infinite loop. It never ends.

Let's halt the loop right after the first iteration:

condition = True
while condition == True:
    print("The condition is True")
    condition = False

print("After the loop")

In this case, the first iteration is run, as the condition test is evaluated to True. At the second iteration, the condition test evaluates to False, so the control goes to the next instruction after the loop.

It's common to have a counter to stop the iteration after some number of cycles:

count = 0
while count < 10:
    print("The condition is True")
    count = count + 1

print("After the loop")

for loops in Python

Using for loops we can tell Python to execute a block for a pre-determined amount of times, up front, and without the need of a separate variable and conditional to check its value.

For example we can iterate the items in a list:

items = [1, 2, 3, 4]
for item in items:
    print(item)

Or, you can iterate a specific amount of times using the range() function:

for item in range(04):
    print(item)

range(4) creates a sequence that starts from 0 and contains 4 items: [0, 1, 2, 3].

To get the index, you should wrap the sequence into the enumerate() function:

items = [1, 2, 3, 4]
for index, item in enumerate(items):
    print(index, item)

Break and continue in Python

Both while and for loops can be interrupted inside the block, using two special keywords: break and continue.

continue stops the current iteration and tells Python to execute the next one.

break stops the loop altogether, and goes on with the next instruction after the loop ends.

The first example here prints 1, 3, 4. The second example prints 1:

items = [1, 2, 3, 4]
for item in items:
    if item == 2:
        continue
    print(item)
items = [1, 2, 3, 4]
for item in items:
    if item == 2:
        break
    print(item)

 


Was this answer helpful?
Back