Skip to main content

Certified Entry-Level Python Programmer Certification

Course

Intro Video

Photo of Keith Thompson

Keith Thompson

DevOps Training Architect II in Content

Length

10:07:49

Difficulty

Beginner

Videos

58

Hands-on Labs

9

Quizzes/Exams

1

Course Details

The Certified Entry-Level Python Programmer Certification (PCEP) is a great place to start when getting Python certified. The Python Institute provides multiple certification exams for Python ranging from entry-level to professional level. This course is designed to teach you the fundamentals of Python required to take and pass the Certified Entry-Level Python Programmer Certification exam before moving onto the more advanced certifications.

Throughout this course we'll cover:

Python data types Control flow structures - conditionals and loops Data collections Functions & Generators

By the time you've completed this course you should feel more than comfortable taking and passing the Certified Entry-Level Python Programmer Certification exam, but more importantly you'll have a good understanding of the fundamentals of Python programming.

Syllabus

Course Introduction

Getting Started

Course Introduction

00:01:19

Lesson Description:

Python is one of the most versatile and widely used programming languages in the world. This makes learning Python a great career move. The Python Institute has created some of the few certifications that exist for programming languages, with the first one for Python being the Certified Entry-Level Python Programmer Certification. This course is designed to teach the fundamentals of Python programming and provide the necessary skills for the Certified Entry-Level Python Programmer Certification Exam.

About the Training Architect

00:00:51

Lesson Description:

This video provides a little about me, Keith Thompson.

Environment Setup

Installing Python 3.7 on a Cloud Playground

00:05:56

Lesson Description:

Learn how to install Python 3 from source on a CentOS 7 and Debian based machines. Note: This course uses Python 3.7 and you will definitely run into issues if you are using Python < 3.7. Download and Install Python 3 from Source on CentOS 7 Here are the commands that we'll run to build and install Python 3.7 on CentOS 7:

$ sudo -i
$ yum groupinstall -y "Development Tools"
$ yum install -y zlib-devel openssl-devel
$ cd /usr/src
$ wget https://python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
$ tar xf Python-3.7.3.tar.xz
$ cd Python-3.7.3
$ ./configure --enable-optimizations --with-ensurepip=install
$ make altinstall
$ exit
Important: make altinstall causes it to not replace the built-in python executable. Download and Install Python 3 from Source on Debian Here are the commands that we'll run to build and install Python 3.7 on a Debian based machine:
$ sudo -i
$ apt update -y
$ apt install -y 
  wget 
  build-essential 
  libffi-dev 
  libgdbm-dev 
  libc6-dev 
  libssl-dev 
  zlib1g-dev 
  libbz2-dev 
  libreadline-dev 
  libsqlite3-dev 
  libncurses5-dev 
  libncursesw5-dev 
  xz-utils 
  tk-dev
$ cd /usr/src
$ wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz
$ tar xf Python-3.7.3.tar.xz
$ cd Python-3.7.3
$ ./configure --enable-optimizations --with-ensurepip=install
$ make altinstall
$ exit
Note: make altinstall causes it to not replace the built-in python executable. Ensure Python 3 Works with Sudo Make sure that secure_path in /etc/sudoers file includes /usr/local/bin. The line should look something like this:
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
Upgrade Pip (might not be necesary) The version of pip that we have might be up-to-date, but it's a good practice to try to update it after the installation. We need to use the pip3.7 executable because we're working with Python 3, and we use sudo so that we can write files under the /usr/local directory.
$ sudo pip3.7 install --upgrade pip

Picking a Text Editor or IDE

00:06:17

Lesson Description:

Before writing code, we should think about the tools we're using to do the development. Much like a carpenter, having sharp tools leads to a more productive creative experience. Having a well-configured text editor can make the programming experience much more enjoyable. Documentation For This Video VimEmacsNanoAtomVS CodeSublimeTextNotepad++PyCharm Terminal-Based Editors There are a few different terminal editors we can work with. The main reason to use a terminal-based editor is that we can run them on servers we're connected to. That way we can stay in a terminal to carry out any programming task, whether that be developing the code, debugging, or deploying. There are two terminal-based editors considered to be extremely popular: Vim - Modal editor, extremely customizable.Emacs - Unbelievably customizable, not modal (at least not by default). Both of these tools are either pre-installed or readily available on all major Linux distributions. The third option is Nano/Pico and we'd suggest using this tool only if nothing else is available. GUI-Based Editors GUI-based editors can be extremely powerful and more aesthetically pleasing than terminal-based editors. This list comprises classic "text editors", but most of them can be enhanced using plugins that add additional functionality. We're going to divide them into two camps: native applications and Electron applications (built using JavaScript). This seems like a weird distinction, but plenty of people don't like the resource overhead required for running Electron applications. Native: SublimeText - Multi-platform. Very performant and extended using Python 3.Notepad++ - Windows only. Not as powerful as the others, but a good starting text editor that won't get in our way. Electron-Based: Atom - The original Electron-based editor. Aesthetically pleasing and very extendable through plugins.VS Code - The most popular GUI-based editor. A vast ecosystem of plugins and a built-in debugger. This is what we'll be using for this course. IDEs The primary IDE used by people in the Python community would be PyCharm. There is a free community edition and also a paid edition. To connect to a remote server to do editing, the paid version is required.

Setting up VS Code for Remote Python Development

00:14:09

Lesson Description:

In this lesson, we're going to set up VS Code to allow us to do remote development. By the time we're finished, we should have VS Code configured to allow us to utilize Cloud Playgrounds as our development environment, while still being able to use nice development tools on our workstations. Documentation For This Video VS CodeVS Code - Python ExtensionVS Code - Remote Development ExtensionVS Code - Pyright Extension Installing VS Code VS Code is probably the most popular text editor used by programmers today, and thankfully it's installable on all major operating systems. To follow along with this lesson, we need to have VS Code installed on our workstation. Installing Helpful Python Extensions One of the best features of VS Code is the vast number of high-quality extensions we can install and customize to make our development environment our own. For the purposes of working with Python, we're going to install a few different Python specific extensions. Python - This is the official extension maintained by Microsoft that adds a lot of Python functionality. With this extension, we can have automated linting, run our tests, debug Python code, run Python files, or even run a line of Python directly in a REPL. All this can be done from within the editor.Pyright - This extension adds support to VS Code to handle the type hints we can add to our Python code (using Python >= 3.5) and tell us if we're using functions or classes with improper types. There are other extensions we could add for working with other Python-related projects like Django, but for now, this is enough to have a very powerful Python IDE. Setting Up Remote Development If we're going to be working on Python projects on a development server, then the Remote Development Extension is fantastic. We've set up our Python development Cloud Server, and we can configure a host for the server to make it easy to connect to from within VS Code. A few things that are necessary in order to follow along: Connect to a remote host using SSH.Generate SSH Keys (ssh-keygen).Copy SSH Keys (e.g. ssh-copy-id). Let's start by creating an SSH key that we'll use for connecting to our remote SSH servers. This way, we don't use keys that have access to other servers. All of these commands need to be run from our workstation.

$ ssh-keygen -t rsa -b 4096 -C "me@example.com" -f /home/cloud_user/.ssh/id_rsa-remote-ssh
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/cloud_user/.ssh/id_rsa-remote-ssh.
Your public key has been saved in /home/cloud_user/.ssh/id_rsa-remote-ssh.pub.
The key fingerprint is:
SHA256:ISPyzUc8F+A5CbMgSpBcHlYTi5ML9KtAiU5v/7TI87s me@example.com
The key's randomart image is:
+---[RSA 4096]----+
|++o+o++ ...      |
|=o=.+.o* o .     |
|o=.*..+ X .      |
|+ oo++ + =       |
|.. =. o S        |
|. o .  .         |
| .   . .         |
|    ..+ .        |
|     ooEo        |
+----[SHA256]-----+
Next, we'll use ssh-copy-id to copy the SSH public key to our Cloud Playground.
$ ssh-copy-id -i ~/.ssh/id_rsa-remote-ssh.pub cloud_user@SERVER_ID.mylabserver.com
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/cloud_user/.ssh/id_rsa-remote-ssh.pub"
The authenticity of host 'SERVER_ID.mylabserver.com (18.191.205.57)' can't be established.
ECDSA key fingerprint is SHA256:ltRgmgobKpTm0KaXg1RN23JDEkItBtLv+wE3wuwy+o0.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
cloud_user@SERVER_ID.mylabserver.com's password:

Number of key(s) added:        1
Now try logging into the machine, with ssh 'cloud_user@SERVER_ID.mylabserver.com' and check to make sure that only the key(s) we wanted were added. Finally, let's add the host entry ~/.ssh/config to our SSH client config.
Host python-server
    User cloud_user
    HostName SERVER_ID.mylabserver.com
    IdentityFile ~/.ssh/id_rsa-remote-ssh
Now from within VS Code, we should be able to remotely connect to this server using the Remote Development extension. This will take a little longer to get started the first time as it sets up the VS Code server on the Cloud Playground. But we'll be in a new window that is connected to the remote host. This will be indicated in the bottom-left corner. If we select the Extensions item in the sidebar (the odd square) we'll notice that we now see the extensions we have locally installed and also the extensions installed on the server. There aren't any remote extensions yet, so we'll want to make sure to install the Python-related ones to the server. We can find them in the list of locally installed extensions, and then hit the Install on SSH: python-server button. This button doesn't exist for extensions that run purely in the client because they work without being on the server.

Basic Concepts

Fundamental Concepts

Compilers and Interpreters

00:03:56

Lesson Description:

Not all programming languages operate in the same way, and understanding the difference between programming language models can help gain mastery over one. In this lesson, we'll take a look at the differences between compiled and interpreted programming languages by learning how compilers and interpreters work. Downloads For This Video Download the Presentation

Lexing, Syntax, and Semantics

00:04:18

Lesson Description:

In this lesson, we'll cover some of the steps involved in the compilation and interpreting process: Lexical AnalysisSyntactic AnalysisSemantic Analysis Downloads For This Video Download the Presentation

Python Specifics: Keywords and Instructions

00:03:56

Lesson Description:

In this lesson, we'll cover some more foundational concepts of programming languages: KeywordsBytecode Instructions Downloads For This Video Download the Presentation

Using the REPL

00:02:29

Lesson Description:

Python is an interpreted language, and code is evaluated in a line-by-line fashion. Since each line can be evaluated by itself, the time between evaluating each line doesn't matter, and this allows us to have a REPL. Documentation Python Interpreter What is a REPL? REPL stands for: Read, Evaluate, Print, Loop Each line is read and evaluated, the return value is printed to the screen, and then the process repeats. Python ships with a REPL and you can access it by running python3.7 from your terminal.

$ python3.7
Python 3.7.2 (default, Jan 15 2019, 19:31:18)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
The >>> indicates that you can type on that line. Later on, you'll also see a ... which means that you are currently in a scoped area and will need to enter a blank line (no spaces) before it will evaluate the entire code block. The simplest use of this would be to do some math:
>>> 1 + 1
2
>>>
2 is the return value of the expression and it is then printed to the screen. If something doesn't have a return value, then nothing will be printed to the screen and you'll see the next prompt immediately. We'll cover this later, but an example would be None:
>>> None
>>>
To exit the REPL, you can either type exit() (the parentheses are important) or you can hit Ctrl+d on your keyboard.

Creating a Python File

00:03:36

Lesson Description:

Since this is a course about Python scripting, we will be writing the majority of our code in scripts instead of using the REPL. To create a Python script we can create a file ending with the file extension of .py. Creating Our First Python Script Let's create our first script to write our obligatory "Hello, World!" program, calling it hello.py.

$ touch hello.py
From inside this file, we can enter the lines of Python that we need. For the "Hello, World!" example we only need ~/code/hello.py
print("Hello, World!")
There are a few different pays that we can run this file. The first is by passing it to the python3.7 CLI.
$ python3.7 hello.py
Hello, World!
Setting a Shebang We'll most likely want our scripts to be: Executable from anywhere (in our $PATH)Executable without explicitly using the python3.7 CLI Thankfully, we can set the process to interpret our scripts by setting a shebang at the top of the file: hello.py:
#!/usr/bin/env python3.7
print("Hello, World")
We're not quite done. Now we need to make the file executable using chmod:
$ chmod u+x hello.py
Run the script now by using ./hello.py and we'll see the same result. If we'd rather not have a file extension on our script, we can remove it since we've put a shebang in the file. Running mv hello.py hello then performing ./hello will still result in the same thing.

Literals, Variables, and Comments

Comments

00:03:02

Lesson Description:

When writing scripts, we often want to leave ourselves notes or explanations. Python (along with most scripting languages) uses the # character to signify that the line should be ignored and not executed. Single Line Comment We can comment out a whole line:

# This is a full line comment
or we can comment at the end of a line:
2 + 2 # This will add the numbers
What About Block Comments? Python does not have the concept of block commenting that you may have encountered in other languages. Many people mistake a triple quoted string as being a comment, but it is not. It's a multi-line string. That being said, multi-line strings can functionally work like comments, but they will still be allocated into memory.
"""
This is not a block comment,
but it will still work when you need
for some lines of code to not execute.
"""

Variables and the Assignment Operator

00:06:00

Lesson Description:

Almost any script that we write will need to provide a way for us to hold onto information for use later on. That's where variables come into play. Working with Variables We can assign a value to a variable by using a single = and we don't need to (nor can we) specify the type of the variable.

>>> my_str = "This is a simple string"
Now we can print the value of that string by using my_var later on:
>>> print(my_str)
This is a simple string
We can also change the value that is assigned to a variable later on, either by using the standard assignment operator = or by using some of the short-hand operators that we'll learn about as we continue.
>>> my_str += " testing"
>>> my_str
'This is a simple string testing'
An important thing to realize is that the contents of a variable can be changed and we don't need to maintain the same type:
>>> my_str = 1
>>> print(my_str)
1
Ideally, we wouldn't change the contents of a variable called my_str to be an interger, but it is something that Python will allow us do. One last thing to remember is that, if we assign a variable with another variable, it will be assigned to the initial result of the variable and not whatever that variable points to later.
>>> my_str = 1
>>> my_int = my_str
>>> my_str = "testing"
>>> print(my_int)
1
>>> print(my_str)
testing
Short-Hand Assignment Operators There are numerous shorthand assignment operators we can use that allow us to perform operations and also assign back to variables in the way that we did with the += operator. The form for these shorthand assignment operations always follows the same pattern. We'll take the operator that we want to use, say +, and create a new operator by adding = to the right-hand side of it. So, for the subtraction operation, we could subtract from the current value and assign the new value to a variable using the -= operator. As we learn about more and more operators we'll be able to follow this pattern if we want to reassess our current variable based on an operation.

Strings and String Operators

00:11:51

Lesson Description:

Let's learn about one of the core data types in Python: the str type. Python Documentation For This Video strings (the str type) Strings Open a REPL to start exploring Python strings:

$ python3.7
We've already worked with a string when we created our "Hello, World!" program. We create strings using either single quotes ('), double quotes ("), or triple-single (''')or double quotes for a multi-line string.
>>> 'single quoted string'
'single quoted string'
>>> "double quoted string"
'double quoted string'
>>> '''
... this is a triple
... quoted string
... '''
'nthis is a triplenquoted stringn'
Strings also work with some arithmetic operators. We can combine strings using the + operator and multiply a string by a number using the * operator:
>>> "pass" + "word"
'password'
>>> "Ha" * 4
'HaHaHaHa'
A string is a sequence of grouped characters. We do need to cover the concept of an "Object" in object-oriented programming before moving on. An "object" encapsulates two things: state and behavior. For the built-in types, the state makes sense because it's the entire contents of the object. The behavior aspect means that there are functions that we can call on the instances of the objects that we have. A function bound to an object is called a method. Here are some example methods that we can call on strings: find locates the first instance of a character (or string) in a string. This function returns the index of the character or string.
>>> "double".find('s')
-1
>>> "double".find('u')
2
>>> "double".find('bl')
4
lower converts all of the characters in a string to their lowercase versions (if they have one). This function returns a new string without changing the original, and this becomes important later.
>>> "TeStInG".lower() # "testing"
'testing'
>>> "another".lower()
'another'
>>> "PassWord123".lower()
'password123'
Lastly, if we need to use quotes or special characters in a string, we can do that using the backslash character :
>>> print("TabtDelimited")
Tab     Delimited
>>> print("NewnLine")
New
Line
>>> print("Slash\Character")
SlashCharacter
>>> print("'Single' in Double")
'Single' in Double
>>> print('"Double" in Single')
"Double" in Single
>>> print(""Double" in Double")
"Double" in Double

Booleans

00:01:14

Lesson Description:

Learn about how Python represents truthiness and nothingness. Python Documentation For This Video Truth Value TestingBoolean Values Booleans Booleans represent "truthiness" and Python has two boolean constants: True and False. Notice that these both start with capital letters. Later we will learn about comparisons operations, and those will often return either True or False. Everything has a Boolean Value We can check the Boolean value for any object in Python by using the bool function. For instance, the empty string "" has the boolean value of False where any other string as a boolean value of True.

Numbers: Integers, Floats, and Scientific Notation

00:02:38

Lesson Description:

Let's learn about some of the core data types in Python: the number types int and float. Documentation For This Video numeric types (the int and float types) Numbers There are two main types of numbers that we'll use in Python, int and float. The big difference between an int and a float being that the float class handles decimal point information. If either of the numbers in a mathematical operation in Python is a float, then the other will be converted before carrying out the operation and the result will always be a float. Scientific notation If we happen to be working with really large numbers, and it's easier to use scientific notation, then Python can help us. For the equivalent of a float times 10 to a specified power we're able to use e or E when specifying the number:

>>> 4.5e9
4500000000.0
>>> 4.5e9 == 4.5 * (10 ** 9) == 4.5E9 == 4.5E+9
True

Number Systems and Numeric Operators

Numeric Operators

00:03:52

Lesson Description:

We've seen numbers in Python, but how do we go about using them? In this lesson, we'll learn about the various numeric operators that we'll use in our Python programs. Documentation For This Video Python Operators The Numeric Operators When we think about what we can do with numbers in math, there are quite a few things that come to mind such as addition, subtraction, multiplication, and division. All of those actions are carried out in our programs by using "operators", special characters we put between the two numbers that carry out a specific calculation. In Python, and in most programming languages, there are more operators than we would typically use when doing arithmetic. Here are the most common operators used in the REPL:

>>> 2 + 2 # Addition
4
>>> 10 - 4 # Subtraction
6
>>> 3 * 9 # Multiplication
27
>>> 5 / 3 # Division, converts the result to a float even when evenly divided.
1.66666666666667
>>> 5 // 3 # Floor division, always returns a number without a remainder as an int
1
>>> 8 % 3 # Modulo division, returns the remainder as an int
2
>>> 2 ** 3 # Exponent
8
There are even more operators than this, but they don't all apply to numbers. We'll learn about some of the other operators in different lessons.

Number Systems

00:06:29

Lesson Description:

In our day to day work, we almost always work with decimal numbers. These are not necessarily numbers with decimal points, but numbers derived from a base 10 number system. In this lesson, we'll take a look at how we could use other number systems in Python. Documentation For This Video Numeral SystemsBit NumberingDownload the Presentation What are Number Systems? We normally count using the decimal number system, which means that for each digit in a number we will cycle between the numbers 0-9 before adding another digit. These same numbers can be represented using other numbering systems though, such as binary which only uses the number 0-1. The decimal number of 15 is equivalent to 1111 in binary notation. To convert from decimal to binary we divide the decimal number (15) by the base of the other numbering system, in binary's case that's 2 and then we take the remainder as a digit in the binary number. We then take the part that divided cleanly and divide it by the base again. Here's the process for converting 15 to binary:

15 / 2 => 7 w/ remainder of 1
7 / 2 => 3 w/ remainder of 1
3 / 2 => 1 w/ remainder of 1
1 / 2 => 0 w/ remainder of 1
If we do this with the number 12 we'll get something different:
12 / 2 => 6 w/ remainder of 0
6 / 2 => 3 w/ remainder of 0
3 / 2 = 1 w/ remainder of 1
1 / 2 = 0 w/ remainder of 1
The bits go from least significant to most, so the remainders at the end of our division will be the most significant digits. 12 as binary is 1100. Converting back to decimal requires us to multiply each bit from least to greatest by the base (2 in binary) to the power of it's position (starting with the 0 power) and then add those numbers together. Converting 1100 back to decimal looks like this:
(1 * 2 ^ 3) + (1 * 2 ^ 2) + (0 * 2 ^ 1) + (0 * 2 ^ 0)
(1 * 8) + (1 * 4) + (0 * 2) + (0 * 1)
8 + 4 + 0 + 0
12
Common Numeral Systems The most common numbering systems are decimal (10), binary (2), octal (8), and hexadecimal (16). You might be asking yourself, "How do I represent a digit with 16 different numbers?". That's a reasonable question. The answer is to start using letters in addition to numbers. Hexadecimal digits go from 0-9, then from A-F. The binary number 12 is C in Hexadecimal. Representing Binary, Octal, and Hexadecimal Numbers in Python Now that we know how various and common number systems work let's go about actually using them in Python. To represent a number in a different number system in Python, we do this by prefixing the number with a 0 and the number system identifier: Binary uses bOctal uses oHexadecimal uses x Here are examples in the REPL:
>>> 0b1001
9
>>> 0o7424
3860
>>> 0xFF012
1044498
The result printed out will be the decimal value. If we want to work in decimal values and represent them in a different numbering system we can use the bin, oct, and hex functions like so:
>>> bin(10)
'0b1010'
>>> oct(59)
'073'
>>> hex(1024)
'0x400'
The value returned from these functions will always be a string.

Floating-Point Accuracy

00:02:20

Lesson Description:

To complete our conversation about numbers in Python we do need to discuss how accurate floats are. Documentation For This Video Floating Point Arithmetic: Issues and LimitationsDownload the Presentation Float Limitations Not all decimal numbers that we write out can be represented by a computer as a float. The reason for this is that floats are stored on computer hardware as binary fractions, and not all decimal (base 10 numbers) can be represented as binary fractions. This leads to the floating-point numbers that we work with actually being approximations of the binary fraction representation. An example of this is the decimal number 0.1 which has no binary fraction equivalent. Depending on the machine, the exact approximation used behind the scenes may be different. But since Python 3.1, the representation that is returned to the user is the clean number even though the number used behind the scenes is something like 0.1000000000000000055511151231257827021181583404541015625. All of this is to say that sometimes floating-point math doesn't work the way that we expect it to.

Data Types, Evaluations, and Basic I/O Operations

Operators and Bindings

Unary and Bitwise Operators

00:13:10

Lesson Description:

Before we start using the types that we've learned to write larger scripts with, we're going to want to know about the operators that we have access to. In this lesson, we'll be defining unary and bitwise operators. Documentation For This Video Python Bitwise Operator Documentation[Python Operators][2] What is a Unary Operator? A unary operator is an operator that only has one operand. Where the + operation is a binary operator, because we need to provide an operand to the right and left of the operator, a unary operator only takes a right-side operand. What are Bitwise Operators? Bitwise operators are operators that work off of the bit information (binary notation) for numbers. These aren't used that often, but it's good to have an understanding of what they do. Positions in binary numbers are known as "bits" and they can either be 0 or 1. Bitwise operations do various things based on the values of these bits. A Brief Aside About Truth Tables One tool from logic (from philosophy) that is used at every level of computer science is the idea of truth tables. Truth tables describe how various operations in boolean algebra work, and can show us all of the available options. Bitwise operators are boolean algebra operations because they deal with 0 and 1, which will equate to false and true. We won't go too deep into truth tables, but if you'd like to have a better understanding of boolean logic then I would encourage you to research them. Operators: Bitwise Complement The first bitwise operator that we're going to talk about is probably the most confusing one: the bitwise complement operator ~. This is the only unary operator that we're going to talk about in this lesson. It takes a number that we're going to call x, and returns the result of -x - 1. To show what this looks like in binary we'll also use the bin function to show our integers as binary numbers:

>>> a = 0b010
2
>>> bin(a)
'0b10'
>>> ~a
-3
>>> bin(~a)
'-0b11'
Bitwise OR The remainder of the bitwise operators make a lot more sense and require two numbers as the operands. The bitwise OR operation will take two numbers, and if one of them has a 1 in a bit position then it will return a 1 at that position in the final result. To use the bitwise OR we'll use a single pipe characters |:
>>> a = 0b1001
>>> b = 0b1100
>>> bin(a | b)
'0b1101'
Bitwise AND Where bitwise OR will return a 1 for a bit position if that position is a 1 in either number, bitwise AND requires that both have a 1 at that position, otherwise it will have a 0 at that position in the final result. The bitwise AND operator is a single ampersand &:
>>> a = 0b1001
>>> b = 0b1100
>>> bin(a & b)
'0b1000'
Bitwise XOR Bitwise XOR (exclusive or) is an interesting operator where the position in the final result will have a 1 if exactly one of the operands has a 1 in that position. The bitwise XOR operator is a carrot ^:
>>> a = 0b1001
>>> b = 0b1100
>>> bin(a ^ b)
'0b101'
Bitwise Right Shift The final two operators allow us to shift our bit values directly sideways by a certain number of positions. To shift our bits to the right we'll use the bitwise right shift operator which is >>. Our initial values are on the left-hand side and the number of positions to shift is on the right:
>>> a = 0b110
>>> bin(a >> 2)
'0b1'
>>> bin(a >> 4)
'0b0'
Notice that if we shift beyond the number of bits in our number then we simply get 0 as the result. Bitwise Left Shift Bitwise left shift uses the << operator with the same rules as the right shift operator. For each position that we shift then we'll add a new 0 bit to the right.
>>> a = 0b110
>>> bin(a << 2)
'0b11000'
>>> bin(a << 4)
'0b1100000''

Boolean Operators

00:03:12

Lesson Description:

Believe it or not, now that we understand bitwise operators we've learned the basics of doing boolean logic. We're in a great spot to learn about boolean operators. Python Documentation For This Video Boolean Operators The not Operation Sometimes we want to know the opposite boolean value for something. To do this, we use the unary operators not:

>>> not True
False
>>> not False
True
The or Operation The boolean or operator works the same way that the bitwise OR operator did if we are only considering one bit. The bit of 1 is equivalent to True and 0 is equivalent to False
>>> True or True
True
>>> True or False
True
>>> False or False
False
>>> False or True
True
The and Operation The and operator is the opposite of or, and both of the operands need to be true.
>>> True and True
True
>>> True and False
False
>>> False and False
False
>>> False and True
False

Comparison Operators

00:08:57

Lesson Description:

The last operators that we need to learn about are the comparison operators. These operators allow us to know if two items are equivalent, or if one is great than the other. Documentation For This Video ComparisonsThe ord function The Greater Than and Less Than Operators We're going to work our way through the comparison operators by starting with the ones that will feel most familiar from mathematics. The four greater than and less than operators work exactly as you'd expect:

>>> 1 < 2
True
>>> 2 > 1
True
>>> 2 < 1
False
>>> 1 <= 1
True
>>> 2.0 >= 3
False
A few things to note are that we can compare numeric types to one other, so it's not hard to compare floats with integers. Another thing to notice is that these comparison operators always return a boolean value. Remember that individual types dictate whether or not they work with specific operands. And strings, for instance, work with these comparison operators too:
>>> 'a' > 'b'
False
>>> 'b' > 'a'
True
>>> 'bb' >= 'ba'
True
>>> 'a' <= 'c'
True
When comparing strings, each character is compared with the character at the same index in the other string to determine which one is larger. Behind the scenes, each character as a numeric value that we can find using the [ord] function, and these are used to do the comparisons. Once again, if we try to compare types that aren't comparable, then we'll receive an error indicating such:
>>> 'a' <= 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<=' not supported between instances of 'str' and 'int'
The Equals Operators The equals operators are a little different than you might expect, because we already use a single equals sign for variable assignment operations. Because of this, to see if two things are equal we use a double equals sign ==:
>>> 1 == 1
True
>>> 1.0 == 1
True
>>> 2 == 1.0
False
>>> 'a' == 2
False
>>> 'a' == 'a'
True
Notice that this checks equivalence, so comparing an equivalent float and integer will return True. Additionally, we're able to compare two completely different types without receiving an error because they're not equivalent. If we want to know if two objects aren't equivalent, then we can use the not equal operators !=. This will return True only if the items aren't equivalent:
>>> 1 != 1
False
>>> 1.0 != 1
False
>>> 2 != 1.0
True
>>> 'a' != 2
True
>>> 'a' != 'a'
False
The Identity Operators If we want to know if two objects are or are not exactly the same object, then we can use the identity operators. The identity operator is the keyword is and the opposite is is not (with a space).
>>> 1 is 1
True
>>> 1 is 1.0
False
>>> 'a' is 'a'
True
>>> 'a' is not 'b'
True
>>> 'a' is not 'a'
False
The identity operators work based on the id of the object, and most of the basic types in Python are immutable (meaning they cannot be changed), so every time that we reference a specific literal it will point to the same item in memory. We can check the id of an object by using the id function (your return values will be different):
>>> id('a')
4444195248
>>> id('a')
4444195248
>>> id('a') == id('a')
True
We'll discuss immutability later, but not all objects are immutable, so you'll run into situations where you can compare two objects that look the same using is and have False returned. Here are two list literals (which aren't immutable):
>>> [] is []
False

Operator Priority (Binding)

00:05:00

Lesson Description:

Now that we've learned about quite a few operators, we're ready to learn how Python determines the order to run them if there are multiple in a single expression. Documentation For This Video Operator precedence Operator Precedence In mathematics, we have the order of operations that tell us how we're going perform our calculations, and in Python, we have operator precedence. We haven't covered all of the contents of this table just yet, but we can look at how everything that we have used so far will be processed. For whatever reason, the Python documentation shows the least binding operators first, but we'll talk about them from most binding to least. We'll leave the ones that we won't cover in this course out of the list though: Parenthesis and List/Dictionary/Set literalsAccessing attributes (subscription, slicing, function/method call, attribute reference)Exponentiation (**)Positive, Negative, and bitwise complementMultiplication *, Division /, Floor Division //, Modulo %Addition +, Subtraction -Bitwise Shifts << & >>Bitwise AND &Bitwise XOR ^Bitwise OR |Comparison operators (in, not in, is, is not, <, >, <=, >=, ==, !=)Boolean NOT notBoolean AND andBoolean OR orConditions if Let's look at some examples:

>>> 14 & 3 * 2 + 4
10
>>> 14 & 3 * (2 + 4)
2
>>> (14 & 3) * 2 + 4
8
>>> 14 & (3 * 2) + 4
10

Input and Output Operations

Typecasting

00:09:21

Lesson Description:

Up to this point, we've worked with a lot of different types, but before we can start taking user input and do interesting things with it we'll need to convert from one type to another. This process is called "typecasting". Documentation For This Video Typecasting: intTypecasting: floatTypecasting: strTypecasting: boolTrust Value Testing Converting from a Number Type to a Number Type We've already seen some typecasting happen behind the scenes when we performed some of the mathematical operations. For instance, performing "true division" (using the / operator) will always return a float even if we provide two integer operands. How do we go about converting from an integer to a float ourselves though? The answer is by using the float initializer.

>>> float(1)
1.0
We can do the same thing going from a float to an integer using the int initializer:
>>> int(1.3)
1
>>> int(2.6)
2
Notice that the result from converting 2.6 to an integer doesn't round, it truncates. It's as though the decimal point value doesn't exist. Converting between number types is pretty straight forward because they're both numbers, but what happens if we try to convert to and from a string? Converting to and from a String Converting to a string is done by using the str initializer and the results are what you would expect:
>>> str(1)
'1'
>>> str(2.6)
'2.6'
>>> str(False)
'False'
As we see, even booleans can be typecast to strings. More interesting than converting to strings is trying to convert strings into other usable types, like integers and floats:
>>> int('1')
1
>>> float('1')
1.0
>>> float('1.2')
1.2
>>> int('1.2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '1.2'
If the string contains something that would be a valid int or float if we typed it into the interpreter, then we're able to typecast it. But as soon as the type doesn't match, or we try to convert something that's not a number to a float or int, then we'll run into issues. Converting to a Boolean One of the more important, and subtle type, conversions that we use in programming is casting to a boolean. We can cast anything to a boolean in Python by using the bool function.
>>> bool(1)
True
>>> bool(2.4)
True
>>> bool('Tada')
True
>>> bool('Tada'.lower)
True
>>> bool(0)
False
>>> bool(0.0)
False
>>> bool("")
False
There are a select few items that convert into False. These are detailed in the Python truth value testing documentation, but can be summed up as False, None, any 0 value, and any empty sequence (an empty string for instance). Boolean Operators with Non-Boolean Objects Now that we know that every object has a boolean representation, we're ready to revisit the boolean operators of and, or, and not. These operators will operate on any objects by using their boolean representations automatically. These operations get a little more complicated as we use non-boolean operands:
>>> 1 and 0
0
>>> 'This' and 'That'
'That'
>>> 'This' and 0 and 'That'
0
>>> 0.0 and 1
0.0
Remember that and requires both operands to be true in order to return true, and this means that it will automatically return the first falsy value that it finds or the rightmost operand if they're both true. The or operator works in the opposite way. It will return the first object that would evaluate to true, or the rightmost falsy value.
>>> 1 or 0
1
>>> 0 or 1
1
>>> 0 or ""
""
>>> 0 or 1 or 'This'
1
Lastly, the not operator will simply return the opposite boolean value for whatever we pass to it:
>>> not ""
True
>>> not 1
False

The `input` Function

00:05:09

Lesson Description:

With an understanding of the basic types in Python, we're finally ready to start writing some programs. In this lesson, we'll take a look at the input function that allows us to write command-line scripts that take in user input. Documentation For This Video The input function Prompting for User Input Computer programs aren't that interesting until they can be more dynamic. Over the next few short lessons, we'll be learning about how we can receive input from a user who's running our program from the command-line, and then how we can manage to present information back to the screen. Before we dig into the input function, let's talk a little bit about functions in general. Functions allow us to package up bits of code to be able to run them more than once. Additionally, functions specify expected inputs and can also return information. If we take a look at a function from mathematics, we can see the same thing:

f(x) = x + 2
In this case, the name of the function is f, the input is x, and the code that will be executed is x + 2. We can provide a variety of values for x and get a different return value. So f(1) would return 3. In Python, we can reference functions by name, allowing us to pass them around like variables. But a function won't be executed unless we "call it" by using parenthesis. We can see this in the REPL by typing in input without any parenthesis:
>>> input
<built-in function input>
The input function is the easiest way that we can make our programs request user interaction. This function is simple in that it only takes one optional argument to be the prompt that we present the user. Whatever the user types will be returned by the input function as a string, and that means we can store it in a variable. Let's try this out in the REPL now:
>>> favorite = input("Favorite Color: ")
Favorite Color:
Now we're left in a new prompt and we can type our answer. When we hit Enter/Return it will submit all of what we wrote and store it in the variable favorite. Note that the prompt argument is optional, so we can simply run input() without an argument and it will leave us at an empty prompt waiting once again for us to hit Enter/Return before then returning that value. Prompting for Multiple Values Now that we know how the input function works, let's create our first real script. In this script, we're going to ask the user to answer a series of questions, and store those answers in variables. In the next lesson, we'll then use these values. Let's call our script bio.py, and in this script, we'll ask for the following: The user's nameThe user's favorite colorThe user's age Create and open bio.py in your text editor and call input three different times, once for each piece of information that we want: ~/code/bio.py
name = input("What is your name? ")
color = input("What is your favorite color? ")
age = input("How old are you today? ")
Both name and color make sense to be strings, but age should be a number. Let's cast the value returned from the age prompt to be an int before assigning it to the variable. We can do this by placing the parenthesis for the int function around the entire input function call: ~/code/bio.py
name = input("What is your name? ")
color = input("What is your favorite color? ")
age = int(input("How old are you today? "))
Now that we've written our script, let's run it:
$ python3.7 bio.py
What is your name? Kevin Bacon
What is your favorite color? Orange
How old are you today? 61
$
We didn't do anything with the values that were returned, but since we were returned to our shell without an error we know that everything executed properly. If we were to give an invalid answer for the age question (something that wasn't an int) Python will raise an error. We need to keep that in mind.

The `print` Function

00:08:04

Lesson Description:

Now that we've taken in some user input, we're going to look at how we can customize some information and write it out to the screen. In this lesson, we're going to dig into how the print function works, and see how we can place variable values into strings. Documentation For This Video The print function Printing to the Screen In the first program that we wrote, we printed "Hello, World!" out to the screen using the print function. That's as simple as it gets, but printing in Python is incredibly easy. Now that our bio.py script is taking in some input from a user, we're ready to write some code to print information back out. Our goal is to take the information from the user for their name, color, and age and print out this sentence with the variables substituted in:

NAME is AGE years old and loves the color COLOR.
We're going to take a look at a few different ways to do this using the print function. The print Function As with most things in programming, there's more than one way for us to achieve our goal of printing the user's information in the proper format. For the exam, we need to understand how to use the sep and end optional arguments to the print function. Let's take a quick look at how the print function works by default and also when we set the sep and end arguments. ~/code/bio.py
name = input("What is your name? ")
color = input("What is your favorite color? ")
age = int(input("How old are you today? "))

print(name)
print("is " + str(age) + " years old")
print("and loves the color " + color + ".")
If we run this now we'll see this:
$ python3.7 bio.py
What is your name? Kevin Bacon
What is your favorite color? Orange
How old are you today? 61
Kevin Bacon
is 61 years old
and loves the color Orange.
Every time we call print, the string will be printed to the screen with a trailing newline, so the next print will always be on the next line. We can change this by setting the end value using a keyword argument. The end argument is set to 'n' by default, but if we change it to ' ' then it should print the three lines as one. When a function takes multiple arguments, then we separate them using commas. And for keyword arguments, we use the argument's name = the value that we want it to use. We'll learn more about how arguments work for functions later, but this is enough for now. Let's modify our script to set the end value: ~/code/bio.py
name = input("What is your name? ")
color = input("What is your favorite color? ")
age = int(input("How old are you today? "))

print(name, end=" ")
print("is " + str(age) + " years old", end=" ")
print("and loves the color " + color + ".", end=" ")
Running it again shows this:
$ python3.7 bio.py
What is your name? Kevin Bacon
What is your favorite color? Orange
How old are you today? 61
Kevin Bacon is 61 years old and loves the color Orange.
We've successfully printed out what we needed to, but it feels a little tedious. The print function can take any number of arguments before we use keyword arguments like sep and end. It will then print each argument separated by the sep character which is '' by default. If we set this to a single space then we should be able to use a single print call to print the sentence properly. Let's see what this looks like: ~/code/bio.py
name = input("What is your name? ")
color = input("What is your favorite color? ")
age = int(input("How old are you today? "))

print(name, 'is', age, 'years old and loves the color', color, '.', sep=" ")
Running it again shows this:
$ python3.7 bio.py
What is your name? Kevin Bacon
What is your favorite color? Orange
How old are you today? 61
Kevin Bacon is 61 years old and loves the color Orange .
We're so close, but there's an extra space between the color and the period. We'll need to combine those into a single string instead. ~/code/bio.py
name = input("What is your name? ")
color = input("What is your favorite color? ")
age = int(input("How old are you today? "))

print(name, 'is', age, 'years old and loves the color', color + '.', sep=" ")

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Making Calculations from User Input with Python

00:30:00

Strings, Operations, and Calculations

Understanding Immutability

00:03:07

Lesson Description:

As we start digging into sequence types like strings, lists, tuples, and dictionaries, we need to start thinking about the mutability of a type or whether or not it can change. Normally, we'll talk about whether or not a type is "immutable," meaning that it can't be changed, and most of the types we've looked at thus far are immutable. Documentation For This Video Immutable Sequences Why Does Immutability Matter? Immutability is something that we don't always have to think about, but it does matter in a few very common cases: Understanding why we can't modify a string in-placeUsing objects as keys for dictionaries (we'll get to this later) We'll cover dictionaries in a different section, but when it comes to strings, wanting to modify a string variable is fairly common. Strings are an immutable type in Python, so we can't change a string object. We can only create new strings with the modifications that we wanted. This means that the only way for us to change the string value of a variable is to explicitly reassign it. As we learn about mutable types, we'll see that other types allow us to modify the value of a variable without explicitly reassigning it. Immutability of Strings When looking at str class there are many methods that return a str to us, such as capitalize:

>>> my_str = 'testing'
>>> my_str.capitalize()
'Testing'
>>> my_str
'testing'
We won't find a method that changes the value of my_str in this example. Beyond this, each unique string that we can only type will only exist once in memory. In our case, we referenced the literal 'testing' when we assigned the value to our variable, and if we ever use the literal of 'testing' again it will point to the same point in memory, because that value can't be modified.
>>> id(my_str)
4522355248
>>> id('testing')
4522355248
This feature prevents the same value being allocated more than once and taking up more spots in our computer's memory than we need it to.

The `len` Function

00:01:13

Lesson Description:

In this short lesson, we're going to take a look at a built-in function that will help us see how long any sequence or collection type is, including strings: the len function. Documentation For This Video The len function The len Function Needing to know the length of a string is very common. Thankfully, the len function will return how many characters are in a string:

>>> len('testing')
7
>>> len('')
0
This may seem a little boring, but it will help us to keep from causing too many errors when we start learning about indexing and slicing in the next lesson.

String Indexing and Slicing

00:08:32

Lesson Description:

Sometimes we need to access a specific item, or a subset of items, in a sequence. To do that in Python, we'll use indexing and slicing. Documentation For This Video Text Sequence Type str Indexing When we need to access a single item from a sequence, like a string, we'll use "indexing." Every item in a sequence type has an index that indicates the item's position in the sequence. The first item in a Python sequence has the index of 0, and each subsequent item's index increases by one. To perform indexing, we'll use square brackets ([ and ]) on the right-hand side of our string (or string variable), and within the square brackets we'll put the index number that we'd like to access:

>>> test_str = 'testing'
>>> test_str[0]
't'
There isn't a character type in Python, so the return value will be a length one string. When indexing a string, the index must exist, otherwise, Python will raise an error:
>>> test_str[10]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
This is one of the areas where using len can help us avoid using an index that is too high. But since the starting index is 0, then the final index will always be len(test_str) - 1:
>>> test_str[len(test_str) - 1]
'g'
If we try to use a negative index, it will actually start giving us items relative to the end of the string:
>>> test_str[-1]
'g'
>>> test_str[-4]
't'
>>> test_str[-8]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
Slicing If we want to get a subsection of our string then we'll do what is called slicing. Slicing allows us to specify the index of the first element that we would like, followed by the index just beyond the last item that we'd like. We separate these indexes by using a colon (:)
>>> test_str[0:2]
'te'
>>> test_str[3:5]
'ti'
If we'd like to get all of the items after our starting index then we can use the length of the string as our second index, even though it's technically out of range. Or we can simply put nothing after the colon:
>>> test_str[2:len(test_str)]
'sting'
>>> test_str[2:]
'sting'
The last thing to mention about slicing is that there is a third number that we can use: the "step" value. By default, this value is 1 and just means that we'll go one-by-one through the sequence. But we can change this to grab every other item if we'd like by adding a second colon and the step size that we'd like to use:
>>> test_str
'testing'
>>> test_str[1:5:2]
'et'
>>> test_str[1::2]
'etn'
One neat thing that we can do with this step option is stepping backward by using a negative step value. We can reverse an entire string by leaving off the start and end indexes and setting the step value to -1:
>>> test_str[::-1]
'gnitset'

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Indexing and Slicing Python Strings

00:30:00

Data Collections: Lists, Tuples, and Dictionaries

Lists

Lists

00:07:59

Lesson Description:

In Python, there are a few different sequence types that we're going to work with, the most common of which is the list type. In this lesson, we'll go through how we can create and modify lists. Python Documentation For This Video Sequence TypesLists Lists We create a list in Python by using the square brackets ([]) and separating the values with commas. Here's an example list:

>>> my_list = [1, 2, 3, 4, 5]
For standard use, there's not a limit to how long our list can be. Lists are a heterogeneous collection type, so the items within the list do not all need to be of the same type:
>>> other_list = ['a', 1, 1.0, False]
Reading from Lists To access an individual element of a list, we index it the same way that we would for a character in a string:
>>> my_list[0]
1
>>> my_list[2]
2
If we try to access an index that is too high (or too low) then we'll receive an error:
>>> my_list[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
To make sure that we're not trying to get an index that is out of range, we can test the length using the len function (and then subtract 1):
>>> len(my_list)
5
Additionally, we can access subsections of a list by "slicing" it. We provide the starting index and the ending index (the object at that index won't be included):
>>> my_list[0:2]
[1, 2]
>>> my_list[1:0]
[2, 3, 4, 5]
>>> my_list[:3]
[1, 2, 3]
>>> my_list[0::1]
[1, 2, 3, 4, 5]
>>> my_list[0::2]
[1, 3, 5]
Modifying a List Unlike strings, which can't be modified (we can't change a character in a string), we can change a value in a list using the subscript equals operation:
>>> my_list[0] = "a"
>>> my_list
['a', 2, 3, 4, 5]
Lists can be added together (concatenated). This operation will return a new list, but we can use the += compound operator to add items to the end of our lists:
>>> my_list + [8, 9, 10]
['a', 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> my_list += [8, 9, 10]
>>> my_list
['a', 2, 3, 4, 5, 6, 7, 8, 9, 10]
Items in lists can be set using slices as well:
>>> my_list[1:3] = ['b', 'c']
>>> my_list
['a', 'b', 'c', 4, 5, 6, 7, 8, 9, 10]
Slicing and assigning can still be used if the slice size is smaller than the list being assigned. This will insert additional elements:
>>> my_list[3:5] = ['d', 'e', 'f']
>>> print(my_list)
['a', 'b', 'c', 'd', 'e', 'f', 6, 7, 8, 9, 10]
We can remove a section of a list by assigning an empty list to the slice:
>>> my_list = ['a', 'b', 'c', 'd', 5, 6, 7]
>>> my_list[4:] = []
>>> my_list
['a', 'b', 'c', 'd']
Removing Items from a List Another way that we can remove an item from a list is by using the del statement and the indexing operation:
>>> my_list = ['a', 'b', 'c', 'd']
>>> del my_list[0]
>>> my_list
['b', 'c', 'd']
One thing to note about del is that it will remove the entire list variable if we don't pass it an index:
>>> del my_list
>>> my_list
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'my_list' is not defined

List Functions and Methods

00:06:42

Lesson Description:

We've learned how to use some list operators to interact with our lists, but there are quite a few useful methods and functions that will make working with lists even easier. Documentation For This Video List MethodsThe sorted functionThe reversed functionCommon Sequence Operations List Methods When it comes to lists, some methods allow us to easily achieve the same things that we previously did using operators, and in an arguably more readable way. Indexing and slicing for the sake of reading objects is easy enough, but when it comes to adding new items to a list, there are better methods. If we want to add an object to the end of a list, then we can use the append method:

>>> my_list = [1, 2, 3]
>>> my_list.append(4)
>>> my_list
[1, 2, 3, 4]
Additionally, if we'd like to insert an item at a particular index, we can use the insert method:
>>> my_list.insert(0, 'a')
>>> my_list
['a', 1, 2, 3, 4]
Notice that we didn't replace the item that had previously been at the 0 index. We moved all items at or after the desired index, further back in the list. If we need to know the index of an item in a list (if the item is in the list), then we have the index method:
>>> my_list = [1, 2, 3]
>>> my_list.index(2)
1
>>> my_list.index(15)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 15 is not in list
Since index raises an error, it's not something that we'll usually want to use by itself. Thankfully, there's an easy way for us to determine if an item is in a list. The in and not in Operators Sequence types have a few additional operators that make it easy for us to check the contents. The in and not in operators take a value that we'd like to search the sequence for on the left-hand side and a sequence on the right-hand side:
>>> my_list = [1, 2, 3]
>>> 4 in my_list
False
>>> 4 not in my_list
True
>>> 2 in my_list
True
These operators are great to use before employing the index method to ensure that we don't get a ValueError. Helpful Functions Besides methods, some built-in functions work great with lists. We've already seen the len function that will return the length of the list to us, but if we need to sort the contents of a list, then we have the sorted and reversed functions:
>>> my_list = [1, 3, 4, 8, 2]
>>> sorted(my_list)
[1, 2, 3, 4, 8]
>>> reversed(my_list)
<list_reverseiterator object at 0x110330d90>
The reversed function doesn't return a list, but typecasting works for the list type also, and when we have a list iterator we can turn it back into a list using the list function:
>>> reversed(my_list)
<list_reverseiterator object at 0x110330d90>
>>> list(reversed(my_list))
[2, 8, 4, 3, 1]
If we want to sort, reverse, and get a list back, we can combine all three of these functions:
>>> list(reversed(sorted(my_list)))
[8, 4, 3, 2, 1]

Nested Lists: Matrices and Cubes

00:04:14

Lesson Description:

Lists are a heterogeneous data structure and can hold onto a variety of data types, this includes other lists. In this lesson, we'll take a look at how we can model matrices in Python by nesting lists. Creating a Matrix Matrices are a structure that has rows and columns. To model a matrix in Python, we need a new list for each row, and we'll need to make sure that each list is the same length so that the columns work properly. Here's an example matrix not in code:

1 2 3
4 5 6
To model this matrix in Python, we'll do this:
>>> my_matrix = [[1, 2, 3],
...              [4, 5, 6]]
>>> my_matrix
[[1, 2, 3], [4, 5, 6]]
To determine how many rows are in a multi-dimensional list, we need to use the len function on the matrix itself. To get the number of columns, we would use len on any row in the matrix (assuming that it's a proper matrix with each row having the same number of columns):
>>> row_count = len(my_matrix)
>>> column_count = len(my_matrix[0])
>>> row_count
2
>>> column_count
3
Now if we want to interact with an individual item in the matrix, we need to index our variable two times, first with the row, and second with the column:
>>> my_matrix[0][1]
2
Squares and Cubes Matrixes with specific dimensions have names. If a matrix has the same number of rows as columns, then it can be classified as a "cube", and some cubes have unique names. A square is 2x2, and a cube (like the 3D shape) is 3x3. The matrix that we've already created is a 2x3 matrix, and this doesn't have a special name.

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Using Python Lists

00:30:00

Tuples

Tuples

00:03:48

Lesson Description:

The most common immutable sequence type that we're going to work with is going to be the tuple. Documentation For This Video Sequence TypesTuples Tuples Tuples are a fixed width, immutable sequence type. We create tuples using parenthesis (()) and at least one comma (,):

>>> point = (2.0, 3.0)
Since tuples are immutable, we don't have access to the same methods that we do on a list. We can use tuples in some operations like concatenation, but we can't change the original tuple that we created:
>>> point_3d = point + (4.0,)
>>> point_3d
(2.0, 3.0, 4.0)
One interesting characteristic of tuples is that we can unpack them into multiple variables at the same time:
>>> x, y, z = point_3d
>>> x
2.0
>>> y
3.0
>>> z
4.0
When we'll most likely to see tuples is while looking at a format string that's compatible with Python 2 (though this will go away soon):
>>> print("My name is: %s %s" % ("Keith", "Thompson"))

Tuples Versus Lists

00:04:24

Lesson Description:

One of the biggest questions that we'll have when working with collections is whether we should use a tuple or a list. In this lesson, we'll take a look at when each is useful. Tuples vs Lists When determining if we should use a list or a tuple, we need to ask ourselves one important question: Will we ever not know the exact number of items that we're storing? If we answer "yes" to this question, then we should use a list. Lists are great for holding onto real collections: users, phone numbers, etc. Tuples make more sense in two general situations: When we're trying to return more than one piece of information from a functionIf we want to model something that has a specific number of fields that we can positionally hold in a tuple: This would be something like a point in 2D or 3D space having x, y, and potentially z. Those values should always be in a specific spot. Another way that this could be used is to quickly model a "person" that has a name, age, and phone number:

>>> person = ('Kevin Bacon', 61, '555-555-5555')
>>> person2 = ('Bob Ross', 76, '')
>>> person[0]
'Kevin Bacon'
>>> person2[0]
'Bob Ross'
In this case index, 0 will always return the "name" for a person stored as a tuple. Lists in Tuples and Tuples in Lists To be thorough, we need to understand how having lists within tuples (and tuples within lists) works. Let's start with lists within tuples, followed by tuples within lists:
>>> my_list = [1, 2, 3]
>>> my_tuple = (my_list, 1)
>>> my_tuple
([1, 2, 3], 1)
>>> other_list = [1, 2, my_tuple]
>>> other_list
[1, 2, ([1, 2, 3], 1)]
We're able to embed lists in tuples and tuples in lists without issues. It's worth noting that tuples are immutable, but they do not require that the items within the tuple be immutable. We can modify the list that is inside of my_tuple:
>>> my_tuple
([1, 2, 3], 1)
>>> my_list.append(1)
>>> my_tuple
([1, 2, 3, 1], 1)

Dictionaries

Dictionaries

00:06:20

Lesson Description:

Learn how to use dictionaries (the dict type) to hold onto key/value information in Python. Python Documentation For This Video Dictionaries Dictionaries Dictionaries are the main mapping type that we'll use in Python. This object is comparable to a Hash or "associative array" in other languages. Things to note about dictionaries: Unlike Python 2 dictionaries, Python 3.7 keys are ordered in dictionaries. We will need OrderedDict if we want this to work on another version of Python.You can set the key to any IMMUTABLE TYPE (no lists).Avoid using things other than simple objects as keys.Each key can only have one value (so we don't have duplicates when creating with dict). We create dictionary literals by using curly braces ({ and }), separating keys from values using colons (:), and separating key/value pairs using commas (,). Here's an example dictionary:

>>> ages = { 'kevin': 59, 'alex': 29, 'bob': 40 }
>>> ages
{'kevin': 59, 'alex': 29, 'bob': 40}
We can read a value from a dictionary by subscripting using the key:
>>> ages['kevin']
59
>>> ages['billy']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'billy'
Keys can be added or changed using subscripting and assignment:
>>> ages['kayla'] = 21
>>> ages
{'kevin': 59, 'alex': 29, 'bob': 40, 'kayla': 21}
Items can be removed from a dictionary using the del statement:
>>> del ages['kevin']
>>> ages
{'alex': 29, 'bob': 40, 'kayla': 21}
>>> del ages
>>> ages
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'ages' is not defined
The in and not in Operators Just like with lists and tuples, dictionaries have access to the in and not in operators. Notably, this only considers the keys:
>>> ages = {'kevin': 59, 'bob': 40}
>>> 'kevin' in ages
True
>>> 59 in ages
False
Alternative Ways to Create a dict Using Keyword Arguments There are a few other ways to create dictionaries that we might see, which are those using the dict constructor with key/value arguments and a list of tuples:
>>> weights = dict(kevin=160, bob=240, kayla=135)
>>> weights
{'kevin': 160, 'bob': 240, 'kayla': 135}
>>> colors = dict([('kevin', 'blue'), ('bob', 'green'), ('kayla', 'red')])
>>> colors
{'kevin': 'blue', 'bob': 'green', 'kayla': 'red'}

Dictionary Methods

00:01:58

Lesson Description:

The dict type has plenty of useful methods that we should know, in order to make them even more useful in our code. This lesson illustrates the main methods that we'll use: keysvaluesitems Documentation For This Video Dictionary Methods Dictionary Methods When we're working with dictionaries, we often need to perform actions on all of the keys, all of the values, or each pair (item). Thankfully the keys, values, and items methods each return something to make this easier. Let's take a look at the key method first:

>>> ages = {'kevin': 61, 'bob' 79}
>>> ages.keys()
dict_keys(['kevin', 'bob'])
Take notice of the return value, it's a dict_keys item. This by itself may not seem useful, but it can be cast to a list if that type makes more sense for what we're doing:
>>> list(ages.keys())
['kevin', 'bob']
We'll also follow this pattern for both values and items:
>>> ages.values()
dict_values([61, 79])
>>> list(ages.values())
[61, 79]
>>> ages.items()
dict_items([('kevin', 61), ('bob', 79)])
>>> list(ages.items())
[('kevin', 61), ('bob', 79)]
Because each item in a dictionary is a key and value, the result of items (when typecast to a list) is a list of 2-tuples (often called "pairs"). This is a good example of using a tuple, because we know these items will always be two items long. As we learn about iterating, these methods will become incredibly valuable for doing useful things with dictionaries.

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Using Python Dictionaries

00:30:00

Strings

String Encodings and Functions

00:06:10

Lesson Description:

Strings hold onto characters and those characters don't need to be alphanumeric. Depending on how a string is encoded, some characters might not be valid. Before we can dig into string encodings, we need to take a look at some of the functions that allow us to interact with Unicode code points (the numbers behind characters). In this video, we'll delve into the ord and chr functions. Documentation For This Video The ord FunctionThe chr Function What are Unicode Code Points? In Python 3, strings are Unicode by default (specifically UTF-8 encoded). Behind the scenes, each character is stored as its Unicode code point, but what does that mean? Unicode is an encoding standard that allows all sorts of unique characters across different languages to have consistent, unique numeric values. For instance, the code point for the letter a is 97, but the character that isn't commonly typed out like the trademark symbol has a code point of 8482. Unicode is a standard, but there are different encodings, one of the most commonly used being UTF-8. UTF-8 stands for "Unicode Transformation Format," with the "8" meaning that values are 8-bits in length. 1,112,064 valid Unicode code points can be encoded with UTF-8. Up to this point, we've been working with strings that use standard ASCII characters (letters, numbers, and common punctuation). ASCII is an older specification with 256 named characters. Their corresponding code points and the first 128 are also valid UTF-8 values. The trademark symbol is in the ASCII specification under the extended characters table, so it has an ASCII numeric value between 128 - 255, but a completely different Unicode code point. To make things even more confusing, Unicode code points are sometimes represented in decimal form and other times by using a 'U+' with the hexadecimal form of the same number. So '™' is 8482, but if you search the internet, you'll usually see it written as U+2122. Going from Code Point to String and Vice Versa Now that we have an idea of what code points are and how encodings work let's see how we can work with them in Python. If we want to see the code point for a character that we know how to type, then we can use the ord function. This function takes a single character and will return the decimal code point. Let's see what this looks like for the letter l:

>>> ord('l')
108
If we try to use ord with more than one character, then it will raise an error:
>>> ord('la')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    ord('la')
TypeError: ord() expected a character, but string of length 2 found
If we already know the Unicode code point for a character that is more difficult to type, like the trademark symbol, then we can type it out using the hexadecimal notation if we prefix the number with u:
>>> ord('u2122')
8482
Notice that ord took a single character as the argument, but didn't give us an error when we escaped the Unicode code point by using the u. This is because a Python string is UTF-8 encoded by default, and although it looks like more than one character to us, that is a single character in UTF-8. It's also worth noting that when the string u2122 is evaluated in Python, it will print the character that we're expecting:
>>> 'u2122'
'™'
>>> 'u2124'
'?'
Say we want to take a decimal code point and convert it back into a string. To do that we'll need to use the chr function:
>>> chr(8482)
'™'
Because we can write integers in hexadecimal notation using the 0x prefix, and those numbers then get converted into the decimal value, we are also able to use that form with the chr function:
>>> chr(0x2122)
'™'

Useful String Methods, Part 1

00:09:30

Lesson Description:

As strings are one of the most important and common types that we work with, we're going to dive into some different sets of methods that we have at our disposal when working with strings. In this lesson, we'll take a look at some capitalization methods and how to evaluate the contents of a string against common patterns. Documentation For This Video The str.lower MethodThe str.upper MethodThe str.capitalize MethodThe str.is___ Family of Methods Changing String Capitalization When working with strings, it's not uncommon for us to want to change the capitalization of the string. We can make comparisons easier or to improve the way that we display the value. Thankfully, Python provides us with simple methods on the str class for just these purposes.

>>> my_str = 'tEsTinG'
>>> my_str.lower()
'testing'
>>> my_str.upper()
'TESTING'
>>> my_str.capitalize()
'Testing'
The lower and upper methods are great for changing all of the characters in a string to either lowercase or uppercase. This is handy to do when capitalization doesn't matter and we want to compare against a value that we already know. For all intents and purposes, an email address: Kevin@example.com is the same as kevin@example.com. If we want to compare a user-provided value that could have odd capitalization with a known email address, then we could call lower before comparing the two values.
email = input("Your Email: ")
print("Email is test@example.com:", email.lower() == 'test@example.com')
The capitalize method is a little different, as it will lowercase every character besides the first one. It doesn't take into consideration if that's the right thing to do for the words within the string. Because of this, you might not find yourself using capitalize all that often, but in many cases, it will work for single-word strings. Checking String Patterns with .is___ Methods Since strings are collections of characters, they can hold onto an incredible variety of information. But that doesn't mean that there aren't different patterns that the information could fall into. For instance, the string '12' is completely numeric. For these types of patterns, the str class provides a whole family of methods that start with is, such as isnumeric:
>>> "12".isnumeric()
True
There are quite a few of these methods. Here's a list: isascii - Return True if all characters in the string are ASCII, False otherwise.islower - Return True if the string is a lowercase string, False otherwise.isupper - Return True if the string is an uppercase string, False otherwise.istitle - Return True if the string is a title-cased string (all words capitalized), False otherwise.isspace - Return True if the string is a whitespace string, False otherwise.isdecimal - Return True if the string is a decimal string (whole number), False otherwise.isdigit - Return True if the string is a digit string (whole number), False otherwise.isnumeric - Return True if the string is a numeric string (whole number), False otherwise.isalpha - Return True if the string is an alphabetic string, False otherwise.isalnum - Return True if the string is an alphanumeric string, False otherwise.isidentifier - Return True if the string is a valid Python identifier, False otherwise. String could be used as a variable, function, or class name.isprintable - Return True if the string is printable, False otherwise. Meaning that if the character can't be printed as-is, then it's not printable. So escape characters like n are considered not printable even though they change how the string is printed.

Useful String Methods, Part 2

00:07:39

Lesson Description:

As strings are one of the most important and common data types that we work with, we're going to dive into some different sets of methods that we have at our disposal when working with strings. In this lesson, we'll take a look at how to split strings apart, build them up from a list, and substitute information into a string using the format method. Documentation For This Video The str.split MethodThe str.join MethodThe str.format MethodPython Format String Syntax Splitting and Joining Strings Sometimes we have strings that we want to break into smaller pieces to work with. If we have a delimiter that we'd like to use to separate the string into smaller strings, then we're able to use the split method to get a list of substrings. A simple example of this would be getting the individual words in a string by splitting on a single space (the default separator):

>>> phrase = "This is a simple phrase"
>>> words = phrase.split()
>>> words
['This', 'is', 'a', 'simple', 'phrase']
Another way I've personally used this is to get the final segment of a URL by splitting on slashes and then selecting the last item in the list:
>>> url = 'https://example.com/users/jimmy
>>> user = url.split('/')[-1]
>>> user
'jimmy'
Being able to split a string is useful, but we might also want to create a single string from a list of strings that we already have. To do this we can use the join method. It's interesting because the string we start with will be the separator that we want inserted between the strings in the list. Let's take our words list and insert commas between the words instead of spaces:
>>> phrase = "This is a simple phrase"
>>> words = phrase.split()
>>> ", ".join(words)
'This, is, a, simple, phrase'
A common way that join is used is by taking a list of lines forming them into a single string with new lines between the lines:
>>> lines = ['First line', 'Second line', 'Third line']
>>> output = 'n'.join(lines)
>>> print(output)
First line
Second line
Third line
Formatting Strings with format The last method that we're going to talk about is the format method. We often have a good idea of what a message needs to look like, but we want to have some dynamic information inserted into the middle of a string. Up to this point, we've been using the multiple arguments available to the print function, but sometimes we don't want to print the formatted string out. The format method allows us to place {} segments into a string and then have values added into those positions:
>>> "Hello, my name is {}, and I really enjoy {}. Have a nice day!".format('Keith', 'Python')
'Hello, my name is Keith, and I really enjoy Python. Have a nice day!'
If we want to use the same value multiple times within the string, then we can place the item index within the {} values:
>>> "Hello, my name is {0}, and I really enjoy {1}. Have a nice day! - {0}".format('Keith', 'Python')
'Hello, my name is Keith, and I really enjoy Python. Have a nice day! - Keith'
It's worth noting that these two approaches can't be mixed. There's a lot more that we can do with the format method, and reading the Format String Syntax documentation can help.

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Using Python String Methods

00:15:00

Control Flow: Loops and Conditional Blocks

Conditionals

The `if` and `else` Statements

00:04:23

Lesson Description:

Up to this point, all of the code that we've written will always execute sequentially regardless of the inputs that we provide (assuming that we don't cause an error). In this lesson, we're going to learn about conditionals. Conditionals allow us to add branching logic to our code, and take different actions based on conditions. Documentation For This Video The if and else Statements The if and else Statements With a grasp on comparisons, we can now look at how to use conditionals to run different pieces of logic based on values. The main keywords for conditionals in Python are if and else. Conditionals are the first language feature we're using that require us to utilize whitespace to separate our code blocks. We will always use 4 spaces as indentation. The basic shape of an if statement is this:

if CONDITION:
    print("CONDITION was True")
The CONDITION portion can be anything that evaluates to True or False, and if the value isn't explicitly a boolean then it will be implicitly converted to determine how to proceed past the conditional (essentially wrapping the CONDITION with the bool constructor):
>>> if True:
...     print("Was True")
...
Was True
>>> if False:
...     print("Was True")
...
>>>
To add an alternative code path, we'll use the else keyword, followed by a colon (:), and indent the code underneath:
>>> if False:
...     print("Was True")
... else:
...     print("Was False")
...
Was False

Handling Multiple Cases with `elif`

00:05:46

Lesson Description:

Being able to perform one thing or another based on a condition is useful. But there are many situations where we want to check multiple possible conditions, and have more than two possible branches. In this lesson, we'll learn about how we can use the elif statement to have multiple branching paths in our conditionals. Documentation For This Video The if, elif, and else Statements The elif Statement When we want our programs to have more than two possible outputs, then the elif statement will work perfectly for us. The elif statement looks a lot like the if statement:

if CONDITION:
   # do something
elif CONDITION_2:
   # do a different thing
else:
   # do something if all conditions are False
We can chain as many elif statements together as we need, so the number of cases that we can handle is effectively limitless. Let's put elif to use by creating a script to evaluate the length of a name provided when we run the script: learning-conditionals.py
name = input("What is your name? ")
if len(name) >= 6:
   print("Your name is long.")
elif len(name) == 5:
   print("Your name is 5 characters.")
elif len(name) >= 4:
   print("Your name is 4 or more characters.")
else:
   print("Your name is short.")
When we run this, we can see the various results:
$ python3.7 learning-conditionals.py
What is your name? Keith
Your name is 5 characters.
$ python3.7 learning-conditionals.py
What is your name? Alex
Your name is 4 or more characters.
$ python3.7 learning-conditionals.py
What is your name? Alex
Your name is 4 or more characters.
$ python3.7 learning-conditionals.py
What is your name? Bob
Your name is short.
$ python3.7 learning-conditionals.py
What is your name? Cynthia
Your name is long.
Notice that we fell into the first elif statement's block, and then the second elif block was never executed even though it was true. We can only exercise one branch in an if statement.

Utilizing `pass`

00:02:48

Lesson Description:

Occasionally, we want to add a branch or other code block without providing any useful code in the block. This is a useful approach if we're outlining some code. In this lesson, we'll learn how to achieve this by using the pass statement. Documentation For This Video The pass Statement The pass Statement When we're first working through a conditional, it's good to handle all cases, even if we don't have an else case that we'd like to run. This is good practice, just to ensure that we're thinking about the whole problem. We can remove it later. To add an else statement without a body, we'll place a pass statement within. The pass statement is what is known as a null operation. Absolutely nothing happens when we execute a pass statement, but they are useful as a code placeholder:

>>> name = "Keith"
>>> if name == "Kevin":
...     print("Hello Kevin")
... else:
...     pass
...
>>>
There are other types of code contexts with Python such as functions, classes, and loops. In all of these, we're able to leverage pass if we want to create the context and not do anything.

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Using Python Conditionals

00:30:00

Looping

The `while` Loop

00:03:20

Lesson Description:

We work with collections of data and sequence a lot in programming, and it is common for us to want to perform the same action on each item or a subset of items in the content. To handle this, we need iteration and looping. In this lesson, we'll learn about one type of loop that we can use: the while loop. Documentation For This Video while statement The while Loop The most basic type of loop that we have at our disposal is the while loop. This type of loop repeats itself based on a condition that we pass to it. Here's the general structure of a while loop:

while CONDITION:
    pass
The CONDITION in this statement works the same way that it does for an if statement. When we demonstrated the if statement, we first tried it by simply passing in True as the condition. Let's see when we try that same condition with a while loop:
>>> while True:
...     print("looping")
...
looping
looping
looping
looping
That loop will continue forever, we've created an infinite loop. To stop the loop, press Ctrl-C. Infinite loops are one of the potential problems with while loops. If we don't use a condition that we can change from within the loop, then it will continue forever if it's initially true. Here's how we'll normally approach using a while loop, where we modify something about the condition on each iteration:
>>> count = 1
>>> while count <= 4:
...     print("looping")
...     count += 1
...
looping
looping
looping
looping
>>>

The `for` Loop

00:04:18

Lesson Description:

We work with collections of data and sequence a lot in programming, and it is common for us to want to perform the same action on each item or a subset of items in the content. To handle this we need iteration and looping. In this lesson, we'll learn about the most common type of loop that we will use: the for loop. Documentation For This Video The for statement The for Loop The most common use we have for looping is when we want to execute some code for each item in a sequence. For this type of looping or iteration, we'll use the for loop. The general structure for a for loop is:

for TEMP_VAR in SEQUENCE:
    pass
The TEMP_VAR will be populated with each item as we iterate through the SEQUENCE, and it will be available to us in the context of the loop. After the loop finishes one iteration, then the TEMP_VAR will be populated with the next item in the SEQUENCE, and the loop's body will execute again. This process continues until we either hit a break statement or we've iterated over every item in the SEQUENCE. Here's an example that loops over a list of colors:
>>> colors = ['blue', 'green', 'red', 'purple']
>>> for color in colors:
...     print(color)
...
blue
green
red
purple
>>> color
'purple'
Other Iterable Types Lists will be the most common type that we iterate over using a for loop, but we can also iterate over other sequence types. Of the types we already know, we can iterate over strings, dictionaries, and tuples. Here's a tuple example:
>>> point = (2.1, 3.2, 7.6)
>>> for value in point:
...     print(value)
...
2.1
3.2
7.6
>>>
In this dictionary example, by default, will first unpack each key:
>>> ages = {'kevin': 59, 'bob': 40, 'kayla': 21}
>>> for key in ages:
...     print(key)
...
kevin
bob
kayla
If we leverage what we've learned about dictionaries, we can actually get the key and value on each iteration by using dict.items and unpacking the tuple in each iteration:
>>> for key, value in ages.items():
...     print(key, value)
...
kevin 59
bob 40
kayla 21
A string example:
>>> for letter in "my_string":
...     print(letter)
...
m
y
_
s
t
r
i
n
g
>>>

Nesting Loops and Conditionals

00:02:46

Lesson Description:

Now that we've learned how to use loops and conditionals, we can do a lot more with our programs. We can do even more when we combine them by nesting loops within conditionals or conditionals within loops. Nesting Conditionals within Loops We've seen two of the most common types of code contexts in Python: the body of a conditional and the body of a loop. To signify code contexts in Python, we use indentation. If we need to nest contexts, like conditionals or loops, then we can add more indentation. Let's say we're looping through a list of numbers, and we only want to print the number if it's a multiple of 4. In this case, we can add a conditional check within our loop:

>>> counter = 1
>>> while counter <= 25:
...     if counter % 4 == 0:
...         print(counter)
...     counter += 1
...
4
8
12
16
20
24
For each nested context, we'll need to indent an extra 4 spaces. When we're done doing what we need to do in a nested context, then we go back to the previous indentation level to continue at that level. This is how we're able to continue past the if statement to increment the counter, all still within the while loop.

Controlling Loop Execution with `break` and `continue`

00:04:39

Lesson Description:

There are times while working with loops, that we want to skip a single iteration, or even completely stop a loop before it is finished. We can accomplish these two things by using the continue and break statements. Documentation For This Video The break and continue statements The continue and break Statements If we want to continue to the next iteration in a nested context or stop the loop entirely, we have access to the continue and break keywords:

>>> count = 0
>>> while count < 10:
...     if count % 2 == 0:
...         count += 1
...         continue
...     print(f"We're counting odd numbers: {count}")
...     count += 1
...
We're counting odd numbers: 1
We're counting odd numbers: 3
We're counting odd numbers: 5
We're counting odd numbers: 7
We're counting odd numbers: 9
>>>
The continue statement will cause the nearest loop (if we have nested loops) to go directly to the next iteration. This means that we will not execute any of the remaining lines of the loop for the current iteration. This can be an issue if we continue without incrementing the count value in our example loop's conditional. We're demonstrating "string interpolation" in Python 3 by prefixing a string literal with an f and then using curly braces to substitute in variables or expressions (in this case, the count value). The break statement works similarly to the continue statement in that it keeps our current iteration from executing the remaining lines in the loop, but it also causes the entire loop to stop. Here's an example using the break statement:
>>> count = 1
>>> while count < 10:
...     if count % 2 == 0:
...         break
...     print(f"We're counting odd numbers: {count}")
...     count += 1
...
We're counting odd numbers: 1
Using break and continue with a for Loop The break and continue statements work with for loops as well. If we didn't want to print out certain colors, we could utilize the continue or break statements again. Let's say we want to skip the string 'blue' and terminate the loop if we see the string 'red':
>>> colors = ['blue', 'green', 'red', 'purple']
>>> for color in colors:
...     if color == 'blue':
...         continue
...     elif color == 'red':
...         break
...     print(color)
...
green
>>>

Integrating `else` with Loops

00:03:13

Lesson Description:

Unlike many languages, loops in Python have an additional clause that we can use: the else clause. In this lesson, we'll take a look at why and when we might want to use this additional Python feature. Documentation For This Video The break and continue statements and the else clause The else Clause The else clause for loops in Python allows us to define an additional code context that will execute when the loop has naturally finished its iteration. In a for loop, this means that we've reached the end of our iteration, and in a while loop it means the conditional has evaluated to False. Here's an example for each of these:

>>> counter = 1
>>> while counter <= 4:
...     print(counter)
...     counter += 1
... else:
...     print("While loop completed")
...
1
2
3
4
While loop completed
>>> for i in [1, 2, 3, 4, 5]:
...     print(i)
... else:
...     print("For loop completed")
...
1
2
3
4
5
For loop completed
>>>
This might seem a little useless because we could have just as easily written these additional print statements on the line directly following the loop and achieved the same result. That's true. The else clause isn't that valuable unless we utilize it in conjunction with the break statement. The else clause's body will execute if the break statement is not hit. We can leverage this when we're iterating through a list:
>>> colors = ['red', 'pink', 'blue', 'orange', 'green']
>>> for color in colors:
...     if color == 'orange':
...         print("Orange is in the list")
...         break
... else:
...     print("Orange is not in the list")
Orange is in the list
This is not the most efficient way to search through a list, but it's a good example of when the else clause of a loop has an effect besides just being the expression run after the loop.

Using `range`

00:03:44

Lesson Description:

Sometimes we want to iterate a set number of times, but we don't necessarily have a collection to work with. An easy way to achieve this is by creating a range object and iterating over it. Python Documentation For This Video Sequence TypesRanges Ranges A range is an immutable sequence type that defines a start, a stop, and a step value. The values within the range start with the beginning value and are incremented until the last value in the range is reached. This allows for ranges to be used in place of sequential lists while taking less memory and including more items.

>>> my_range = range(10)
>>> my_range
range(0, 10)
>>> list(my_range)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 14, 2))
[1, 3, 5, 7, 9, 11, 13]
Notice that the "stop" value (in this example, 10) is not included in the range. By using a range with a for loop, we can specify the number of times we would like to iterate without needing to manually worry about incrementing a counter like we had to do with a while loop. Here's a previous example where we printed "looping" four times using a while loop:
>>> count = 1
>>> while count <= 4:
...     print("looping")
...     count += 1
looping
looping
looping
looping
>>>
We could achieve this same thing using for and range like this:
>>> for _ in range(1, 5):
...     print("looping")
...
looping
looping
looping
looping
>>>

List Comprehensions

00:05:28

Lesson Description:

Iterating over a sequence is great, but needing to transform a list into a different list is fairly common. Python has a special feature to make doing this concise, called "list comprehensions". Documentation For This Video List Comprehensions List Comprehensions If we want to loop through a list, modify each item, and have a new list with the modified items, then we could do something like this:

>>> colors = ['red', 'blue', 'orange', 'green', 'yellow']
>>> uppercase_colors = []
>>> for color in colors:
...     uppercase_colors.append(color.upper())
...
>>> uppercase_colors
['RED', 'BLUE', 'ORANGE', 'GREEN', 'YELLOW']
This procedure is common enough that Python provides a shorthand method for doing it in the form of "list comprehensions." These have a unique syntax where we essentially put the for loop within square brackets ([]). Here's the equivalent for the above, using a list comprehension:
>>> colors = ['red', 'blue', 'orange', 'green', 'yellow']
>>> uppercase_colors = [color.upper() for color in colors]
>>> uppercase_colors
['RED', 'BLUE', 'ORANGE', 'GREEN', 'YELLOW']
The biggest difference here is that we don't need to create an empty list and append to it. Whatever we place to the left of the for statement within the comprehension will be returned as part of the final list. List Comprehensions for Filtering List comprehensions also have another feature that allows for filtering while iterating through the initial list by adding a trailing if statement within the square brackets ([]). If we wanted to iterate through our colors and only return "warm" colors (red, orange, yellow) then we could write this loop to achieve these results:
>>> colors = ['red', 'blue', 'orange', 'green', 'yellow']
>>> warm_colors = []
>>> for color in colors:
...     if color in ['red', 'orange', 'yellow']:
...         warm_colors.append(color.upper())
...
>>> warm_colors
['RED', 'ORANGE', 'YELLOW']
If we remove the concept of warm_colors being used within the loop, we can write it as a list comprehension:
>>> colors = ['red', 'blue', 'orange', 'green', 'yellow']
>>> warm_colors = [color.upper() for color in colors if color in ['red', 'orange', 'yellow']]
>>> warm_colors
['RED', 'ORANGE', 'YELLOW']
The syntax for list comprehensions are a little odd to get started with. But if you read it as a sentence, then it will start to make more sense and feel more useful. The sentence would read something like this: Uppercase each color in the colors variable if the colors are red, orange, and yellow.

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Utilizing Python Loops

01:00:00

Functions

Function Basics

Defining and Using Functions

00:05:29

Lesson Description:

Being able to write code that we can call multiple times without repeating ourselves is one of the most powerful things that we can do when programming. Let's learn how to define functions in Python. Documentation For This Video Defining Functions Function Basics We can create functions in Python using the following: The def keywordThe function name - lowercase starting with a letter or underscore (_)Left parenthesis (()0 or more parameter namesRight parenthesis ())A colon :An indented function body Here's an example without any parameters:

>>> def hello_world():
...     print("Hello, World!")
...
>>> hello_world()
Hello, World!
>>>
If we want to define a parameter, we will put the variable name we want it to have within the parentheses:
>>> def print_name(name):
...     print(f"Name is {name}")
...
>>> print_name("Keith")
Name is Keith
Let's try to assign the value from print_name to a variable called output:
>>> output = print_name("Keith")
Name is Keith
>>> output
>>>
Neither of these examples has a return value, but we will usually want to have a return value unless the function is our "main" function or carries out a "side-effect" like printing. If we don't explicitly declare a return value, then the result will be None (as you saw when our body used print). We can declare what we're returning from a function using the return keyword:
>>> def add_two(num):
...     return num + 2
...
>>> result = add_two(2)
>>> result
4
Working with Multiple Parameters When we have a function that takes multiple parameters, we need to separate them using commas and give them unique names:
>>> def add(num1, num2):
...     return num1 + num2
...
>>> result = add(1, 5)
>>> result
6

Parameters vs. Arguments

00:06:51

Lesson Description:

When talking about functions, the words "parameter" and "argument" are often used interchangeably. But they represent two different things. In this lesson, we'll look at the differences between parameters and arguments, and the different ways we can use arguments when calling functions. Documentation For This Video Defining Functions Parameters VS Aruguments The difference between a parameter and an argument is all about timing. When we're working with the definition of a function, then the variables defined in the function declaration are the "parameters." When we're calling the function, the data that we provide for each parameter is the "argument." Accidentally using these words interchangeably in practice isn't an issue, because other programmers will know exactly what you're talking about. But it is good to know that there is a distinction. With the semantic differences covered, we're ready to move onto the more interesting topic of the various types of arguments that we can use: position and keyword arguments. Using Keyword Arguments Every function call we've made up to this point has used what are known as positional arguments. But if we know the name of the parameters, and not necessarily the positions, we can all them all using keyword arguments like so:

>>> def contact_card(name, age, car_model):
...     return f"{name} is {age} and drives a {car_model}"
...
>>> contact_card("Keith", 29, "Honda Civic")
'Keith is 29 and drives a Honda Civic'
>>> contact_card(age=29, car_model="Civic", name="Keith")
'Keith is 29 and drives a Civic'
>>> contact_card("Keith", car_model="Civic", age="29")
'Keith is 29 and drives a Civic'
>>> contact_card(age="29", "Keith", car_model="Civic")
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
When we're using position and keyword arguments, every argument after the first keyword argument must also be a keyword argument. It's sometimes useful to mix them, but oftentimes we'll use either all positional or all keyword. Defining Parameters with Default Arguments Along with being able to use keyword arguments when we're calling a function, we're able to define default values for parameters to make them optional when the information is commonly known and the same. To do this, we use the assignment operator (=) when we're defining the parameter:
>>> def can_drive(age, driving_age=16):
...     return age >= driving_age
...
>>> can_drive(16)
True
>>> can_drive(16, driving_age=18)
False
Parameters with default arguments need to go at the end of the parameters list when defining the function so that positional arguments can still be used to call the function.

Recursion

00:07:34

Lesson Description:

It might not seem immediately obvious, but we're capable of calling a function from within itself. This practice is called recursion. In this lesson, we'll learn how we can use recursion and some of the pitfalls that surround it. Documentation For This Video Defining FunctionsThe sys.getrecursionlimit Function Solving Problems with Recursion Recursion is the practice of calling a function from within itself. This might not seem like something that you'd ever do at first, but occasionally the best way to solve a problem is to break it up into smaller versions of the same problem. The canonical example of this is calculating the Fibonacci Sequence (1, 1, 2, 3, 5, 8, etc.). In the Fibonacci sequence, the next number is always the sum of the previous two numbers in the sequence. If we write this out as a mathematical function, then calculating the nth item in the Fibonacci sequence would look something like this:

f(n) = f(n-2) + f(n-1)
So, for the 5th item in the sequence (which coincidently is also 5), we would expand it like this:
f(5) = f(3) + f(4)
f(5) = f(1) + f(2) + f(2) + f(3)
f(5) = 1 + f(0) + f(1) + f(0) + f(1) + f(1) + f(2)
f(5) = 1 + 0 + 1 + 0 + 1 + 1 + f(0) + f(1)
f(5) = 1 + 0 + 1 + 0 + 1 + 1 + 0 + 1
f(5) = 5
For recursion to work, there has to be what is called a "base case," where something is returned other than the result of the function calling itself. In the case of our Fibonacci sequence function, the base case(s) are that f(0) will return 0, and f(1) will return 1. Now that we can visualize exactly what is going on, let's write this function in Python: ~/fib.py
def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1

    return fib(n - 2) + fib(n - 1)

item_to_calculate = int(input("What Fibonnaci item would you like to calculate? "))

print(fib(item_to_calculate))
In writing our function, we needed to remember a few things: We need to handle the base cases first.We return what we would normally consider the implementation of the function. This return allows us to essentially gather all of the results at the end. Let's run our script:
$ python3.7 fib.py
What Fibonacci item would you like to calculate? 15
610
That was pretty fast, but as we increase the number from 15 to 30, we should see it take significantly longer to return. This is because the number of recursive function calls that happen as we try to calculate higher and higher terms gets excessively large. Trying to calculate the 50th term using our implementation might not ever return. The Limits of Recursion We've run into the main issue with recursion, every time we recurse it, we're adding more and more function calls to the stack of calls that need to be completed. Some languages are optimized to handle this by implementing something called "tail-call optimization," but Python is not one of those languages. Recursion is a useful tool at times, but it does require being delicate and layering in some manual optimization (which we won't be covering here).

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Defining and Using Python Functions

00:30:00

Generators

Creating and Using Generators

00:05:21

Lesson Description:

Normal functions are the primary way that we'll be bundling up logic that we want to use over and over, but Python also provides a way for us to define functions that behave like iterators. These functions are called "generators." In this lesson, we'll learn why we might want to use generators and how to create and use them. Documentation For This Video Python Wiki: GeneratorsThe Built-In next Function What is a Generator? A generator is a function that behaves like an iterator. This means that we can ask a generator function for its "next" value and it will calculate it, and return it to us. Similar to how a range doesn't calculate all of the values at once, a generator function essentially "pauses" its execution after returning a single result until the next result is requested. To learn about generators, let's go ahead and implement a function that works like the built-in range type. Writing a Generator Function Generator functions are defined the same way that traditional functions are, except that instead of using the return keyword to provide a result back to the caller, we use the keyword yield. When defining a generator, we will almost always include a loop in the body of the function, and then we'll yield from within the loop. Let's create a new file called gen.py to create our gen_range function.

def gen_range(stop, start=1, step=1):
    num = start
    while num <= stop:
        yield num
        num += step
Unlike the built-in range function, if we call this function with three arguments, they're in the order of stop, start, and step instead of starting with start. But this function effectively works the same way (although not as performant). Let's load our file into the REPL to test out this function:
$ python3.7 -i gen.py
>>> gen_range(10)
&lt;generator object gen_range at 0x1054a8550>
>>>
The first thing to note here is that when we call the generator function, it returns a generator object to us instead of giving us the result. To get each result, we'll use the built-in next function to execute the generator until it hits a yield statement. Let's assign the generator object to a variable and pass it to next a few times:
>>> generator = gen_range(4)
>>> next(generator)
1
>>> next(generator)
2
>>> next(generator)
3
>>>
This is how a generator works. It loops internally, yielding a result each time it's passed to the next function until it reaches the end of the function because it stops looping. Here's what we see if we pass the generator to next too many times:
>>> next(generator)
4
>>> next(generator)
Traceback (most recent call last):
  File "&lt;stdin>", line 1, in &lt;module>
StopIteration
In practice, we won't normally be calling the next function on our generators. We'll be using them with for loops like this:
>>> for num in gen_range(10, step=2):
...     print(num)
...
1
3
5
7
9
>>>
The for loop automatically knows how to work with generators, so we don't have to worry about running into the StopIteration error.

Converting Generators to Lists

00:04:15

Lesson Description:

Generators are functions that behave like iterators, and that means that they can be used to dynamically calculate items in a loop. But that also means that they can be converted into lists. In this lesson, we'll take a look when and how we can convert a generator into a list. Documentation For This Video Python Wiki: GeneratorsThe Built-In next Function Converting a Generator to a List When we're working with generators, we'll often write them in such a way that eventually they won't have anything left to yield. And in that case, we can turn the generator into a list. This might sound like it would be difficult, but it's as easy as passing the generator object into the list function that we've used many times before, to convert things like dict_keys objects to be lists. Let's load our gen.py file into the REPL again so that we can utilize the gen_range function that we wrote in the previous lecture:

$ python3.7 -i gen.py
>>> generator = gen_range(10)
>>> list(generator)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
That was pretty simple. But, it is possible to run into issues with this. Let's say that we define an infinite generator that will always calculate the next item in the Fibonacci sequence we looked at in our recursion lesson. gen.py
def gen_range(stop, start=1, step=1):
    num = start
    while num <= stop:
        yield num
        num += step

def gen_fib():
    a, b = 0, 1
    while True:
        a, b = b, a + b
        yield a
This function might look a little weird, but to calculate the next item in the Fibonacci sequence, we combine the previous two items with 0 and 1 being our two starting points. This should yield us 1, 1, 2, 3, 5, 8, etc. as we continue to call next on an instance of this generator object:
$ python3.7 -i gen.py
>>> fib = gen_fib()
>>> next(fib)
1
>>> next(fib)
1
>>> next(fib)
2
>>> next(fib)
3
>>> next(fib)
5
We'll never reach the end of this generator function because it includes an infinite loop, and we never use a break statement. Let's see what happens if we try to turn this into a list (don't follow along with this):
>>> list(fib)
We'll see that the prompt hangs. That's because it's looping forever. This is the situation when you can't convert a generator to be a list because the list function will never return.

Hands-on Labs are real live environments that put you in a real scenario to practice what you have learned without any other extra charge or account to manage.

Defining and Using Python Generators

00:30:00

Scoping

Python Scopes

00:02:53

Lesson Description:

We've lightly touched on this already, but when working with any programming language, the variables and objects that we're working with are only accessible within certain scopes. In this lesson, we'll take a closer look at how scopes work and when our variables might not be what we expect them to be. What is a Scope? When we say that we're working in a different "scope" in Python, we mean that we're within the boundaries of a function or a class. This is important because while within the body of a function or class, the variables that we create are not automatically accessible outside of that context. Let's create a new file called scopes.py so that we can experiment with how scopes work. To start, let's see how variables work when dealing with conditionals and loops. scopes.py

if 1 < 2:
    x = 5

while x < 6:
    print(x)
    x += 1

print(x)
Here we're creating a variable (x=5) within the body of a conditional (if 1 < 2:1). Afterward, we attempt to access that variable within the context of a loop (while x < 6:) and at the highest level of our script. Will this work? Let's find out by running this through the interpreter:
$ python3.7 scopes.py
5
6
$
We didn't run into an error because conditionals and loops do not create scopes. Now, let's change our conditional to be a function instead. scopes.py
def set_x():
    x = 5

set_x()

while x < 6:
    print(x)
    x += 1

print(x)
Now if we run this we'll see the following:
$ python3.7 scopes.py
Traceback (most recent call last):
  File "scopes.py", line 7, in &lt;module>
    while x < 6:
NameError: name 'x' is not defined
$
We see this error because x is defined within the set_x function and only exists during the execution of the function.

Name Hiding (Shadowing)

00:02:58

Lesson Description:

Now that we've looked at how scopes work initially, we're ready to look at what happens when we have a function parameter that is the same as a variable that exists at a higher level. This is sometimes called shadowing or name hiding. Name Hiding in Action We know that functions create scopes. But, what happens when a parameter name is the same as a variable that has already been defined? Let's continue using scopes.py to see what happens when we set y before we define the set_x function, and then change our function to have a y parameter: scopes.py

y = 5

def set_x(y):
    print("Inner y:", y)
    x = y
    y = x

set_x(10)
print("Outer y:", y)
Now if we run this, we'll see the following:
$ python3.7 scopes.py
Inner y: 10
Outer y: 5
Since our function defines the y parameter, it's as though the outer y variable doesn't exist within the set_x function. Name hiding makes it possible for us to be confident that our parameters won't be affected by values at a higher scope. That doesn't mean that name hiding is something that we should always use though because it can make our code a little harder for people to understand.

The `global` Keyword

00:04:55

Lesson Description:

Occasionally, we want to be able to modify a global variable from within a more specific context. In this situation, Python provides us with the global keyword. In this lesson, we'll learn how to use the global keyword. Documentation For This Video The global Statement Modifying the Global State from a Nested Scope If we would like one of our functions to have the side effect of changing or creating a global variable, we can utilize the global statement. This isn't something that we'll use all that often since it is better to keep global state to a minimum as we start working on larger and more complex programs. But it is useful now and then. Let's modify scopes.py so that we can change the global y variable from within our set_x function: scopes.py

y = 5

def set_x(y):
    print("Inner y:", y)
    x = y
    global y
    y = x


set_x(10)
print("Outer y:", y)
If we run this, we should see the following:
python3.7 scopes.py
  File "scopes.py", line 7
    global y
    ^
SyntaxError: name 'y' is parameter and global
It's important to know that we can't utilize the global statement if we have a parameter with the same name. Let's change our parameter to be z before running this again: scopes.py
y = 5

def set_x(z):
    x = z
    global y
    global a
    y = x
    a = 7

print("y Before set_x:", y)
set_x(10)
print("y After set_x:", y)
print("a After set_x:", a)
We've also created a global variable from within our set_x function called a. This variable won't be available before the first time that set_x is called, but we should be able to print it after we've called our function for the first time. Let's run scopes.py again:
$ python3.7 scopes.py
y Before set_x: 5
y After set_x: 10
a After set_x: 7
This example shows how potentially confusing using global can be. We have a function called set_x that will change the global state for the variable y. Someone who didn't write this code could be completely confused as to why the value of the variable y that they've been working with was changed right out from under them. Keep this in mind when considering whether or not it's a good idea to use the global statement.

Course Conclusion

Final Steps

How to Prepare for the Exam

00:01:29

Lesson Description:

To feel fully prepared to take the Certified Entry-Level Python Programmer Certification Exam, do the following: Take and pass the practice exam multiple timesTake a look at the study guideDo all of the hands-on labs in this course The majority of the exam involves determining what a snippet of code does. The code is intentionally written to have uninformative or confusing variable and function names, so be patient reading through the code in each question. Registering for the Exam To register for the exam, go here to purchase a voucher. After acquiring a voucher, one can take the exam at any time because it isn't proctored. To do so, head here to register or log in. Once logged in, hit Take Exam, enter the code from the voucher, and take the exam. Good luck!

What's Next After Certification?

00:01:32

Lesson Description:

Thanks for taking the time to go through this course! I hope you learned a lot, and I want to hear about it. Please take a moment to rate the course. It'll help with determining what works and what doesn't. Be sure to share your results in the community. Everyone at Linux Academy wants to celebrate your successes with you.

Practice Exam

Certified Entry-Level Python Programmer Certification

00:30:00

Take this course and learn a new skill today.

Transform your learning with our all access plan.

Start 7-Day Free Trial