Introduction
If you are already familiar with OOP (object-oriented programming) in Javascript or any other language, then learning Python won't be very hard. If you want to learn Python with some Javascript sprinkled in for contrast, then this guide is for you.
Also, if you want to learn python with no background in computer programming, this guide is for you.
If you already know python but want to learn Javascript, you may be able to reverse engineer this article to learn Javascript, no promises though.
I hope that you find a ton of value from this guide!
A few things I like about Python over Javascript in no particular order:
- Less punctuation, no need to end every line with stuff.
is
/is-not
comparators are more verbose than ===- loops are way easier
- The hard cut over from python2 to python3 makes learning just 1 language without a ton of the weird "this is how we used to do it so now you learn that way to understand how we do it in the new way"
- The readability of the language is pretty good, not as good as dart but pretty good for the level of power it can wield.
- It's super easy to pick up from a 2nd language perspective. If you already understand a lot of the underlying basics of functional and OOP then you will breeze through it.
- The global keyword for specifying when a variable inside a function is referring to global scope.
- *args and **kwargs
- Maps are not confusing in python!
- Modules are not super confusing and there is a "standard library" like deno/golang.
- Python is already installed on my mac
- Import modules from anywhere! ๐ต R.I.P. npm!
- There are no "bindings" like in javascript that have to be spelled out. It's much more straight forward.
A few things I dislike about Python and prefer Javascript for:
- There is no distinction in javascript between the various kinds of arrays but in python, you have dictionaries, tuples, sets, and lists and each one with their own builtin functions/methods. I think this makes javascript easier to wrap your mind around these concepts but manipulating data appears to be a bit easier with python comparatively - this isn't really a +1 in either corner, just a distinction and I have an obvious bias to my first language (Javascript).
- Javascript is carrying a lot of baggage from old ES versions and would be super cool if it just sunset support for them and came out with a standardized backwards compatible model or forked from it.
- const and let are foreign concepts to python and partially the reason there is so many types of array equivalents.
- ++ syntax is a fantastic shorthand
- Interpolation of strings is way less confusing - no f"statement {text}" just some good'ole backticks.
- Backticks!
- The node console for debugging and the
debugger;
keyword is builtin.
A little history
Versions of hardware is always changing - look at your iPhone, it's probably on iPhone XX by the time you read this. Improvements are made, security is improved, features are added, you get the idea. Software and languages are no different.
Back in 2008, the creator of Python, Guido Van Rossum, who was unhappy about some of the early architectural problems of Python1 & Python2. The goal was to make Python3 the version everyone uses for the present & future of the python language.
But... It's more complicated than that. Python 3 isn't backwards compatible meaning that any code that was written in python2 cannot work in python3 - this is something that javascript has resolved by still supporting really old versions. Because of this, python2 was still commonly used up until recently and some companies may still be on python2 without upgrading (even though it's no longer supported).
It created a divide in the python community for a long time and also created some difficulty in deciding which to learn for job outlook. It's been 13 years though, all of the arguments to continue to use python2 over python3 are no longer valid.
As of writing this, < Python 3.5 including Python 2.x are past EOL (End of Life) - meaning it's no longer supported. You can check the current supported versions here: https://pyreadiness.org/.
Ironically, New mac operating systems come with Python2 and Python3 installed by default.
Terminal tips and tricks (non-python)
You'll need a mastery of terminal basics to really be able to leverage any language but especially python.
We will use it to execute python scripts and more.
You should have a command line installed, if nothing else you can open a terminal in Visual Studio Code.
Section Table of contents
- Learning Python from a Javascript Perspective
- Introduction
- A few things I like about Python over Javascript in no particular order:
- A few things I dislike about Python and prefer Javascript for:
- A little history
- Terminal tips and tricks (non-python)
- Section Table of contents
- OS File Structure
- Absolute path (PWD)
- Tilde
- Moving/changing the directory you are working in.
- Create new directory and files
- Moving and renaming files and directories
- How do we delete files?
- How do you see what files are in your working directory
- Wait, what does that
drwxr-xr-x
part mean? - So how do we modify the permissions?
- Advanced - Chaining commands together
- Running and Exiting Python
- Section recap
- Install Python
- Section Table of contents
- Brew installation
- Setup your Gitlab and git
- Install VSCode
- Section Recap
OS File Structure
Computers operating systems (OS) organized with hierarchy structure (like a tree). Each directory and it's children are all relative to the base root directory.
root /
|-- tmp
|-- Users
|--- drew ~
So in the example above you'd need to state the full file path to reference the file you want, specifically /Users/drew/
.
Absolute path (PWD)
What if you are in the /Users/
? What if you don't know where you are in your terminal currently? Well you could start by leveraging some customizations like in my article: https://codingwithdrew.com/how-to-customize-your-zsh-terminal-with-bash/
You can use the pwd
(print working directory) command to identify your current location in reference to the /
directory.
Tilde
Pronounced "Till-Dee", Tilde represents "home" or your user's directory. In the example above, /Users/drew/
and ~
are the same exact things, one is just easier to type and reference and is agnostic of the actual name so commands will work even if the user directory is changed or another user is running a script you write.
Moving/changing the directory you are working in.
cd
is used to move from the path you are on to another. The way you use it is cd /path-to-file.txt
.
You can also move up 1 directory using cd ..
or you can move.
Another cool tool you can use is tab. Tab will auto complete paths/filenames for you. If you typed cd Des
and then typed the tab
key you'd get an output of Desktop
auto filled into the command line.
Create new directory and files
We are going to learn Python so we want to add a directory on our Desktop to store all the python things we build.
mkdir <insert directory name>
("Make directory") is the command to use.
We are going to do that now:
cd ~/Desktop/
mkdir python
cd python
Now we are in that directory, let's make some files.
The first thing I'd recommend doing on any project folder is to add a readme.md - this will lend you well for notes and if you make your directory public when you push using github or gitlab (etc) your repository will have your human readable notes/instructions visible.
So how do we create a new file you ask?
Easy, touch <filename>
, this command will create files (not directories). Run:
touch readme.md
Moving and renaming files and directories
mv
command is used for both moving and renaming a file.
There are 2 arguments mv <source> <destination>
If the source and destination are the same but the file name is different, you will change the file name.
Example: mv path/file1.md path/file2.md
changed the files name from file1 to file2 but if we wanted to move it we just need to do it like this: mv path/file1.md path2/file1.md
How do we delete files?
rm <path/file name>
is the command to use. This is only for deleting files.
To delete a directory, you have more opportunities to delete unintended files. You can use rm -rf
where the -rf
stands for "recursive force" meaning to delete all the files inside of the directory including inside of any nested directories and their nested directories ad nauseam.
Bear in mind, there is no undo for an rm command.
Let's delete our python directory - rm -rf ~/Desktop/python/
. We will recreate it in the next stage.
How do you see what files are in your working directory
ls
is a command that will allow you to see the contents of a particular directory.
You can pass options for more details:
-a
: all files (including .hidden files).-l
: long format-h
: human readable format (turns bytes to mb/gb as applicable).
You can open a file using open <filename>
command.This will use the default application for the file type.
home@Computer ~ % ls -lah
total 384
drwxr-xr-x 23 home staff 736B Apr 9 10:23 python
...
Wait, what does that drwxr-xr-x
part mean?
r
= read accessw
= write accessx
= executed
= indicates a directoryl
= indicates a symbolic link i.e. shortcut/pointer to another file/folder
Permissions are separated into 3 columns:
- Owner Permissions
- Group Permissions
- Everyone's permissions (default)
These columns are separated by a -
.
In the example from the previous section, our user has `a directory with read, write, execute. Our group has execute and read permissions and everyone has execute permissions.
So how do we modify the permissions?
You can easily modify permissions with a command called chmod
pronounced "C.H. Mod". To run this command though, you may need to specifically request higher permissions on the command to run it as the "root user" - enter sudo
.
sudo
is like saying "super user please do" and then you run the command afterwards.
You have 2 ways to do this - with values or the directory listing (shown below). Numbers and the associated directory listing do the same things but really come down to preference.
value | Permission | Directory Listing |
---|---|---|
7 | Read, write, execute | rwx |
6 | Read, write, no execute | rw- |
5 | Read, no write, execute | r-x |
4 | Read, no write, no execute | rโ |
3 | No read, write, execute | -wx |
2 | No read, write, no execute | -w- |
1 | No read, no write, execute | โx |
0 | No read, no write, no execute (Most restrictive) | "--" |
Advanced - Chaining commands together
If you wanted to run a command and then when it's completed, immediately execute the next command, you could do this using ;
or &&
(there is another use for single &
- basically run a command in the background and continue running other commands).
The main difference is that if you end a command with ;
and it fails, it will still run the subsequent commands - in my experience this is typically something we want to avoid. This is the benefit of the &&
which will allow you to string together multiple commands (you'll see me do this a ton) and if the command to the left of the &&
fails, it will terminate the rest of the command.
Running and Exiting Python
To run python, just open your terminal and type the command:
python3
You will be presented a >>>
prompt meaning you are in a python repl much like if you ran "node" or opened the console in a browser for javascript.
You can close this repl by mashing control
+d
keys.
Section recap
You should be able to create, delete, navigate, list files, and modify permissions at this point. If you don't feel confident with these just yet, that's ok! We will be using these frequently. In the next section we will setup our computer for use with Python.
Install Python
Section Table of contents
- Install Python
- Section Table of contents
- Brew installation
- Setup your Gitlab and git
- Install VSCode
- Section Recap
Note: All instructions on codingwithdrew.com are Mac specific. If you are using windows, you can run most of these commands using powershell or other tools but I don't get into the details on it. In fact, I know there is a ton of debate in the industry related to mac or pc but if you are a developer or DevOps engineer, Mac reigns supreme.
Verify that you have Python 3 already installed:
python3 --version
If you already have python3 installed, you should see an output like this:
home@Computer ~ % python3 --version
Python 3.9.1
If this outputs version information and no error, then python3 is already installed and you can skip the next section.
Brew installation
If you haven't already read one of my tutorials, you will find that I'm a massive fan of homebrew and you will be too. It's basically software package manager your computer should have come with but didn't.
Head over to https://brew.sh/ and follow the instructions to install or follow along here.
Run:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" && xcode-select --install
You will be prompted to accept terms and conditions for xcode (I'm not entirely sure if xcode is required to run that last step as I've already downloaded and installed it).
Since your computer (as of writing this) will come standard with Python 2.7 out of the box, you can use python version 3 separately - follow these steps:
brew cleanup && brew update
This removes stale lock files and updates brew.
Install python3 and git - Run:
brew upgrade python3 && brew install git
If you want to check that python 3 has been installed, you can run python --version
and python3 --version
separately to validate it was installed.
home@Computer ~ % python --version
Python 2.7.16
home@Computer ~ % python3 --version
Python 3.9.1
Setup your Gitlab and git
Go to gitlab.com and setup an account - totally free.
Log into your gitlab account and create a new repository named "python" and initialize it with a README.md file.
Set up SSH on your account, open terminal and run
sh-keygen -t ed25519 -C "[email protected]โ
Feel free to change the email to your own ๐.
The -C flag, with a quoted comment, such as an email address, is an optional way to label your SSH keys.
Youโll see a response similar to:
Generating public/private ed25519 key pair. Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Paste in from the prompt the path /Users/home/.ssh/id_ed25519 (for example) and then press return.
Enter a passphrase 2 times and press return. You just created secure ED25519 SSH keys for gitlab!
ow we just have to get those keys into gitlab so we can clone the repo.Run:
pbcopy < ~/.ssh/id_ed25519.pub
Navigate to https://gitlab.com & select your avatar in the upper right corner, and click Settings > SSH Keys.
Paste the public key from step 5 above into the Key text box. Make sure your key includes a descriptive name in the Title text box
Click the Add key button.
Clone the repository:
Create a development directory then clone your new gitlab repository into it. You'll use the copied SSH path from above into this command. Run
mkdir ~/Dev/ && cd ~/Dev/ && git clone [email protected]:DrewK/python.git && cd ~/Dev/python
It should look something like this:
home@Computer Dev % git clone [email protected]:Drewk/python.gitCloning into 'python'...The authenticity of host 'gitlab.com (2606:4700:90:0:f22e:fbec:5bed:a9b9)' can't be established.ECDSA key fingerprint is SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUtgiXFzSnUw.Are you sure you want to continue connecting (yes/no/[fingerprint])? yesWarning: Permanently added 'gitlab.com,2606:4700:90:0:f22e:fbec:5bed:a9b9' (ECDSA) to the list of known hosts.Enter passphrase for key '/Users/home/.ssh/id_ed25519':
Bear in mind, you may have to enter your passphrase if applicable
Install VSCode
Navigate in your browser to: https://code.visualstudio.com/ and download Visual Studio Code for your operating system and install it.
Install language support for python like this:
Section Recap
At this point, you should have a solid grasp on terminal commands. You should also have python3 and your visual studio code editor set up for Python development. Lastly, you should have gitlab set up to commit code to.
In the next section we will learn all about the operators, numbers, and how to make comments in Python. That section will be foundational knowledge we will continue to build off of and practice in each section.
Numbers, Operators, and Comments
Section Table of contents
- Numbers, Operators, and Comments
- Understand the difference between
ints
andfloats
- Work with simple mathematical operators
- Add comments to your code
- Section recap
Understand the difference between ints
and floats
There are two types of numbers in Python:
Integer | Floating Point |
---|---|
4 | 3.14 |
33 | 3.33333 |
-1 | 0.0 |
There are two others, one named complex and another called long. We likely won't use these so I'm glazing over them.
Work with simple mathematical operators
Commonly used operators in Python.
Symbol (Operator) | Name |
---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
** | Exponentiation |
% | Modulo |
// | Integer Division |
Important notes with the operators above:
- Division will always produce a float.
- Order of operations matters - Remember PEMDAS?
- Parenthesis
- Exponents
- Multiplication
- Division
- Addition
- Subtraction
- 2 ** 3 = 8. The syntax for exponents is the same as you'd expect "2 to the 3rd power".
- Modulo is a remainder division, it'll divide what ever number you provide, then it will provide the remainder. This is especially helpful if trying to determine even/odd integers. Example 13 % 2 = 1. So it would be odd but 12 % 2 = 0 => We can use this consistent logic to determine if the number is even or odd.
- Integer Division - Floors the output. 6//7 = 0 instead of some odd float result. It's not as common but basically it rounds down the result to the nearest whole number. Could save a line of code later.
Add comments to your code
Commenting your code is a really important tool that allows us to leave notes for ourselves or other people who may be trying to understand our code later.
You can comment code in VS code by highlighting it and typing the command
key + /
key. This will put a #
(an octothorpe or more commonly referred to as a hashtag) in front of the line of code. This will prevent the line from being ran.
There is no multiline commenting in Python like there is with HTML/Javascript.
Section recap
At this point we have covered a bit of ground, you have set your computer up and are a whiz at command line and now you have a basic understanding of numbers, operators, and how to comment code.
The next section we will look into python variables and focus heavily on the string type.
Data Types and variables in Python
Section Table of contents
- How to assign and use variables
- Python Variable naming restrictions and conventions
- Learn and use some of the different data types available in Python
- Python is a Dynamically Typed Language
- None
- Learn the ins and outs of Strings
- What is string escape sequences?
- What is string concatenation ๐ผ?
- Interpolation has entered the room
- Strings and Indices
- Converting Data Types
How to assign and use variables
Firstly, what are variables?
In development, there is a strong desire to avoid repetition of code commonly referred to as "DRY" or "Don't Repeat Yourself".
Variables hold data to be used later and can be reused. They can be numbers, booleans, strings, and more. We haven't learned all the types yet but we'll get there.
Remember x in basic algebra class where you assign a value to it, then solve for y? Well the same thing applies to python (and well computer programming in general). Variables are assignable.
In python you can also re-assign a variable. Let's take a look
Example:
variable_one = 1
variable_one * 2 # The output here is going to be 2
# What is the value of variable_one now?
If you said the value is still 1, you'd be correct. This is because we did not re-assign the value of variable_one. To reassign it, we could make a minor change:
variable_one = 1
variable_one = variable_one * 2
Variables can be reassigned at any time.
You can also set multiple variables all at the same time. This one is a bit weird:
all, at, once = 5, 10, 15
In the example above, all is 5, at is 10, and once is 15. This is not something I'd recommend or likely ever use to avoid confusion. I'm sure there is an edge case, I'm struggling to think of a good reason to do this.
Python Variable naming restrictions and conventions
Here are the rules:
- You cannot name variables certain pre-defined names - specifically data types like "int" or "None".
- Must start with a letter or underscore. The rest of the name must consist of letters, numbers, or underscores.
- Names are case-sensitive. Charlie isn't the same as charlie.
- Naming conventions - these aren't required but if you work in a team, it's recommended to stick with the standard naming conventions:
- Use snake case (underscores between words)
- Variables should be lower case unless it's a constant (variables that shouldn't be changed like "Pi").
- Variables that start and end with two underscores commonly referred to as a "dunder" are supposed to be private or left alone.
__no_touchy__
Learn and use some of the different data types available in Python
This isn't a comprehensive list but it is the most commonly used data types:
Data type | Description |
---|---|
bool | True or False |
int | An integer (1,2,3) |
str | String - a sequence of Unicode characters |
list | Some languages call these arrays. Ordered sequence of values of other data types. e.g. [1,2,3] |
dict | A collection of key:value pairs |
We will learn more types like floats soon.
Important Note: Don't make variables named using these reserved data type names. They are not protected, you can actually create a new variable named "int" or "str" and that would not be desired.
Python is a Dynamically Typed Language
Dynamic typing is a topic that differentiates languages. Python is highly flexible about reassigning variables to different types unlike Typescript, Dart, and others.
This is good and bad. In a statically typed language, it's considered "safer" because variables cannot be reassigned to a new type and the type must be established when assigning the variable. This allows compile time to say "hey - error: the data provided isn't the correct/expected type" - meaning you're more likely to find errors before code is in production.
Dynamically typed languages are not limited by this strict typing because you can change a variable from having an int to a string on the fly.
Python is Dynamically typed.
None
None
is a special value in python. It is case sensitive. It is Python's equivalent of Null. It is used to define that there is no value (but that nothing value is not 0).
Learn the ins and outs of Strings
Strings start and end with a quote mark and are a series of Unicode characters, you can use "
or '
(single or double quotes.) as long as you use the same to open and close the string. These are only used to establish string variables. You cannot use double quotes inside of double quotes. i.e.: example_message = "She said "hello world" in her first python app"
. Note that basically the first double quote is closed out before hello world and then there is just a bunch of extra content that doesn't meet python's expectations. You'd need to escape the internal quote marks like this: example_message = "She said \"hello world\" in her first python app"
or you could use single quotes inside the double quotes like this: example_message = "She said 'hello world' in her first python app"
Sadly, back-ticks "`" are deprecated in python which is one of my favorite tools in Javascript.
What is string escape sequences?
These are meta-characters that get interpreted by Python do to something special. \
is the escape character typically the thing that comes after it is the "sequence".
Escape sequence | Meaning |
---|---|
\newline -or- \n | Backslash and "newline" ignored |
\ \ | Backslash (\) |
\' | Single Quote (') |
\" | Double Quote (") |
\t | Horizontal Tab (Tab) |
Find more here: https://www.python-ds.com/python-3-escape-sequences
What is string concatenation ๐ผ?
Concatenation is the combination of strings where it "adds" them together. Check out this example below:
string_one = "one"
string_two = "two"
string_three = "three"
cat_string = string_one + string_two + string_three
Short hand for concatenation is +=
so we could also use this example below for the same results.
string_one = "one"
string_two = "two"
string_three = "three"
string_one += string_two += string_three
The output for the above is "onetwothree" which isn't super human readable but Python followed our instructions exactly which read "Combine these strings".
To combine them in a way that makes more sense we could use " "
in between each variable like this:
string_one = "one"
string_two = "two"
string_three = "three"
cat_string = string_one + " " + string_two + " " + string_three
That's painful to write though, there has to be a better way.
Interpolation has entered the room
Interpolation allows you to leverage variables within a string. In Javascript, you use ${}
and back-ticks to pull this off. In Python this is called an "f-string" and yes the f
in front of the quotes is correct in the example below. Weird right?
string_one = "one"
message = f"I have {string_one} dog named Charlie"
print(message)
The output for the above is "I have one dog named Charlie". You can also use the {} to perform logic like addition or concatenation inside it.
Another important note is that you cannot escape inside of an f-string.
Strings and Indices
Just like in Javascript - "Hello World"
is a string, pretty straight forward but what we haven't covered yet is that all strings are indexed (also like javascript). Meaning something like this:
String | H | e | l | l | o | W | o | r | l | d | |
---|---|---|---|---|---|---|---|---|---|---|---|
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
In the example above you can see each letter of the string has an index associated with it and they are ordered starting from 0 to 10, even though there are technically 11 characters.
In computer programing languages indexes/arrays/lists always start from 0.
To demonstrate we need to open our Python3 Repl (read evaluate print loop), it's the python interactive shell we can sandbox in terminal.
In terminal just run python3
and you should see >>>
on a new line as a prompt.
To exit mash the command
+ d
keys.
In the Repl, type "Hello World!"[0]
- the [0] is telling the repl " look for the letter at index 0 of this string (ignoring the quote marks obviously).
The output would be H
.
"Hello World!"[8]
would be r
.
Not that it matters but, the same thing works in Javascript:
let one = "drew";
console.log(one[2]);
Hopefully you get the idea.
Converting Data Types
In string interpolation (f-strings), data types are implicitly converted to string form.
You can also explicitly convert variables by using the name of the builtin type as a function.
decimal = 123.456789
integer = int(decimal) # 123
You can do the same thing with a list for example:
my_list = [1,2,3]
my_list_as_a_string = str(my_list) # "[1, 2, 3]"
You can also convert an int to a float.
num = 1234
type(num)
# output is <class 'int'="">
num = float(num)
type(num)
# output is <class 'int'="">
print(num)
# output is 1234.0
Booleans and Conditional Logic
- What is a Boolean?
- How to get user input in python
- How to make decisions based on inputs (Conditionals)
- Comparators
- Does python support "truthy" & "falsy"
- How do we chain comparisons to say "if this is true and this is true"?
- Logical Negation (Not)
What is a Boolean?
A boolean ("boo-lee-an") is basically just a true or false value. This binary logic is a cornerstone of all development languages. Booleans allow you (well, your application) to make decisions! If you are familiar with javascript this section should be an absolute breeze.
In python these "True" or "False" statements are always capitalized; also, all comparator statements resolve to true or false. We will get more into that in a moment but this is foundational to this section.
How do you get user input in python?
There is a builtin function in python called "input" that will prompt a user to input requested data and will then store that data as a variable that your application can then use to make decisions. This is very similar to the window.prompt()
method in javascript.
name = input("Enter Your Name Here: ")
How do you make decisions based on inputs (Conditionals)?
If you are familiar with Javascript, conditional logic is very similar. I think the biggest difference is "elif" instead of "else if" in javascript.
Here is some not-real pseudo code that demonstrates if, elif, and else statements.
**if** some value is true:
do something # indentation matters here.
**elif** some other condition is true:
do something # indentation matters here.
**else**:
do something if all other conditions are false # indentation matters here.
- You can use as many or as few elif statements.
- Colon is required at the end of an if/elif/else statement.
- Must have at least 1 "if" statement.
- Can only have 1 "else" statement.
What do Comparators look like in Python?
Python leverages a few different comparators - these allow you to evaluate "if" 2 sides of the comparator are "true" or "false". Note that !=
and ===
doesn't exist like Javascript.
Comparator | What it does | Example |
---|---|---|
= | Important A single = is not a comparator! This is an operator and it is used to assign a value to a variable | my_variable = 1 # not a comparison! |
== | Compares two values/variables to see if they are the same. If they are, it returns "truthy" | if my_variable == 1 : |
> | Compares two values/variables to see if the value on the left is greater than the right. If they are, it returns "truthy" | if my_variable > 0 : |
< | Compares two values/variables to see if the value on the left is less than the right. If they are, it returns "truthy" | if my_variable < 2 : |
<= | Compares two values/variables to see if the value on the left is less than or equal to the right. If they are, it returns "truthy" | if my_variable <= 1 : |
>= | Compares two values/variables to see if the value on the left is greater than or equal to the right. If they are, it returns "truthy" | if my_variable >= 1 : |
is | Compares two values/variables to see if they occupy the same space in memory - slightly different from == | if my_variable is 1 : |
Does python support "truthy" & "falsy"?
This is just like javascript! Every value has a boolean value by default. We can leverage this to craft logic in our application. For example if a string is empty, do this thing. If there is no value, do something.
None
, 0
, False
, empty strings, and empty objects all default to having a falsy value. Everything else is truthy by default.
x = 1
x == 1 # true
x is 1 # true - this is a truthy expression
x is 2 # false - this is a falsy expression
Question: What do you think the output of both of these if statements will be?
if 0:
print("This will only run if 0 is true - aka truthy")
else:
print("0 is false - aka falsy")
if 1:
print("This will only run if 1 is true - aka truthy")
else:
print("1 is false - aka falsy")
Answer: 1 is truthy, 0 is falsy
How do we chain comparisons to say "if this is true and this is true"?
Javascript uses || for an "or" statement, && for an "and" statement. and != for a not statements, so how is it different with python? The theory is exactly the same, the operator is just different and more human readable. I actually like this part better.
Operator | What it does | Example |
---|---|---|
and | Truthy if a and b are true | if a and b: |
or | Falsy if a or b are false | if a or b: |
not | Truthy if the opposite is true | if not a: |
The important thing to remember on or
statements is only 1 side has to be true for the whole value to be true.
Example:
1 < 3 OR 1 == 9
In the example above, the left side is True but the right side is False, the whole statement resolves to True. The same would be True in Javascript.
Logical Negation (Not)
In Javascript this operator is !=
, in python it's simply not
. Anything that is the opposite of the right side of the statement will be truthy.
if not is_weekend
print("Go to work, ya bum!")
Loops - how to repeat parts of code
Looping is identical for python and Javascript with the exception of keywords. If you aren't familiar with loops at all, this section is a good introduction.
What is DRY Code
Let's say you have to print the numbers 1-10 and you went about it like this:
print(1)
print(2)
print(3)
print(4)
print(5)
print(6)
print(7)
print(8)
print(9)
print(10)
That's pretty ugly right? In our Variables section we introduced the concept of "DRY" or "Don't Repeat Yourself". There has to be a better way!
Loops have entered the chat.
We are going to learn how to make a loop, and why you'd want to use them. We are going to learn what an iterable object is, we are going to discuss for
and while
loops to iterate over ranges and strings and lastly, how to exit a loop.
"for"
In python, a for loop is written like this:
for item in iterable_object:
# do something with item
for
and in
are python syntax that you cannot change but you can change "item" and "iterable_object" to anything you like.
"item" represents where you are in our iterator within the iterable.
That makes no sense. So what does it mean?
It will run through every item of the collection on the right side of "in" then stop running when it's visited every item.
What are Ranges?
We need to know for loops to know ranges. In order to know ranges, we need to know for loops.
Ranges are an immutable sequence of numbers. A range is just a slice of a number-line. python ranges come in multiple forms. range(7)
gives you integers from 0-6.
You can splice using 2 digits. The first specifying where in the range to start, the second where to end like this: range(1, 10)
, this would give you integers from 1 to 9.
You can splice it and specify even digits: range(2, 22, 2)
- this will give you all even numbers from 2 to 22. This is even because you are starting on an even digit, if you made the 3rd parameter passed a 2 but the first (start) was 1, it would result in 1, 3, 5, 7 ... 22
You can reverse the direction with that same 3rd parameter passed. Count up with +
numbers, and down with -
. For example: range(10, 0, -1)
would count down from 9 to 0.
What are "While Loops"?
Just like Javascript while
and for
loops can both do the same things but while
can loop through an iterable while a condition is truthy.
my_condition = 3
while my_condition < 3:
print("this number is is less than $my_condition")
my_condition += 1
Also like javascript, you can cause a crash with an infinite loop if a condition is never met.
What is a Controlled Exit?
While loops and for loops can run for ever and you can force the loop to stop whenever you want using a key word break
.
Example:
while True:
command = input("Type 'exit' to exit:")
if (command == exit):
break
In this example, the loop would run infinitely until "exit" were typed into the terminal.
Lists
Section Table of contents
- Intro to lists and objectives
- How do we Describe, create, and access a list data structure?
- How do you Access values in a list?
- What if you want to check if a value is in a list?
- Iterate over lists using loops and list comprehensions
- List Methods
- how to add items to a ListHow to delete items from a List
- Less common list methods:Fruit Ninja (slice method)
- How to swap values in python
- How does list comprehension work?
- List Comprehension with Conditional Logic
- Nested Lists
- What about nested list comprehension?
- Lists Recap
Intro to lists and objectives
Are you familiar with Arrays in Javascript? If so, just replace the word "Array" with "List" - you don't really need to dig super deep but there are some subtle differences you'll want to take note of. Lists are a collection or grouping of items. It's a way of combining that data into a common structure.
How do we Describe, create, and access a list data structure?
Here is a fundamental data structure for organizing collections of items
first_task = "Install Python"
second_task = "Learn Python"
third_task = "Take a break"
The above isn't super dry is it? How about:
tasks = ["Install Python", "Learn Python", "Take a break"]
Or
tasks = ["first_task", "second_task", "third_task"]
If you wanted to find out the length of an array in Javascript you'd use a builtin method
tasks.length
but in python you do this withlen(tasks)
which would result in "3". You can also usenum_list = list(range(1,4))
which would list out[1, 2, 3]
and convert the range to a list effectively
How do you Access values in a list?
example_list[ 1, 2, 3, 4, 5, 7, 8, 9, 10]
This is done in the same way you would do it in Javascript. Every item in the list will have an index, to access a specific item at that index just use example_list[0]
which would show us the 1st indexed item (1).
What number would `example_list[7] result in? Comment below!
What if you want to check if a value is in a list?
In the example list in the previous section - if we wanted to search for a number we could run 6 in example_list
and the result would be false (I left it out of the list above).
How do you iterate over lists using loops and list comprehensions?
How do we access all the values in a list 1 at time?
numbers = [1,2,3,4]
print(numbers[0])
print(numbers[1])
print(numbers[2])
print(numbers[3])
In the example above, this isn't very DRY so we want to use one of our fancy loops from the last section.
numbers = [1,2,3,4]
for numbers in numbers:
print(numbers)
The same thing from the 1st example would be the would result in the same outcome. What about a while loop?
numbers = [1,2,3,4]
i = 0
while i < len(numbers):
print(numbers[i])
i += 1
What are the List Methods
A method is a type of function, we have been using a number of functions like len() and print() but a method is added to the function at the end with a dot separating them. We will go into a deeper dive on this topic later but this foundational knowledge is necessary.
There is a bit of a new concept related to how lists are modified, in some cases these methods will modify the original list without copying it in the same memory store while others will just return a value that needs to be captured by creating a variable and then assigning it's value the list.method().
If the object in question is immutable (can't be changed), it will return a new object. If it is mutable, it will modify the existing one. For example, lists will modify in place because a list is a mutable object. Tuples, strings and numbers would not because they are immutable. Since you can't change a tuple, the method must return a new object. But enough about tuples, we aren't there yet. Let's learn list methods!
How to add items to a List?
list.append()
: in javascript this would belet newLength = fruits.push('Orange')
or "add this single item to the end of the list".list.insert()
: in javascript this would belet newLength = fruits.unshift('Strawberry')
or "add this item to the 0 index on the list. If you pass 2 items as arguments into the function, the 1st will be what index you'd add the item to and push the rest after the insertion and the second value you'd pass would be the value you'd like to actually insert.list.extend()
: will add to the end of a list all values passed into the extend method. In javascript, this still a push.
How do I delete items from a List?
list.clear()
: will remove all the items in the list at once. This is probably less common than other array methods.list.pop()
: this will remove a single item at a given position in the list and return it. Similar to pop in Javascript but it does return the value. If no index is passed as the first argument, it will remove the last item in the list.list.remove()
: instead of passing an index, you pass an item. This is similar to Javascript'svariable.exec()
method.
Less common list methods:
list.index()
: returns the index of the first matching condition passed as an argument. In Javascript, this would be done withArray.indexOf()
.list.count()
: I don't think there is a builtin Javascript equivalent of this python builtin method but what it does is searches through an index for a matching condition and returns the number of times the condition was matched.list.sort()
: This sorts the order of a list in place. This actually updates the list that the method is called on, there is no returned item or copies made. The most similar thing in javascript would beArray.sort()
.list.reverse()
: This reverses the order of a list in place. This actually updates the list that the method is called on, there is no returned item or copies made. Probably the most similar thing in javascript would beArray.reverse()
.list.join()
: This is commonly used to convert Lists to strings, similar toArray.join()
in Javascript. This method creates and returns a new string by concatenating all of the items in the List. To use this one, you specify what you want to separate it by followed by.join(list_name)
(example:friends = ", ".join(names)
).
Fruit Ninja (slice method)
This is very different from Javascript. The syntax for slicing is different than what we have been using for example it's syntax is some_list[start:end:step]
. While we don't have to have all 3 items inside the square brackets, you do have to include at least 1 colon.
Start: example_list[1:]
would return all the items starting from index 1 to the end of the list. You can also use negative numbers which would return all the items starting from the last item of the list.
If you'd like to copy a list, you can use example_list[:]
or example_list[0:]
.
End: This is an argument passed to allow you to copy up to the index specified (aka exclusive counting). If we pass a start and an end then it will provide a "range" of indexes to return.
Step : just like step from python ranges, step indicates the number to count by. If you put 2 in this space (example_list[::2]
), it would only return the even index's value from the list. Negative values reverse the order - I'm not entirely sure of a good use case for this but you could do it.
How to swap values in python
You can swap the values of a list using comma syntax. To understand this, you'll probably want to just see an example:
example_list = ["learns", "drew"]
example_list[0], example_list[1] = example_list[1], example_list[0]
print(example_list)
# The output will be "drew", "learns"
How does list comprehension work?
List Comprehension is a new concept that is unique to python that allows you to use shorthand to make copy of lists and manipulate the data.
The syntax is odd, it starts with []
s and will have 3 variables passed separated like this [______for_____ in______]
similar to a for loop.
An example:
example_list[1,2,3,4,5]
[x*10 for x in example_list]
## ^ This list comprehension will be interpreted as for every item in my list multiply it by 10 in a new list.
## This will return: ## [10,20,30,40,50]
This is basically a loop but allows you to save a few lines of code when taking the loop data and manipulating it. This data must be captured as it will not update the original memory store.
Another example:
[bool(some_list) for some_list in [0, [], '']]
## This will return: [False, False, False]
This example will loop over the list and determine whether each item in the list is truthy or false and then return the value in a new array (you'd need to set it equal to a value in order to capture it).
Here is another example:
example_list = [0, 1, 2, 3, 4, 5]
string_of_example_list = [str(example_number) for example_number in example_list]
print(string_of_example_list)
## This will print out: ['0', '1', '2', '3', '4', '5']
List Comprehension with Conditional Logic
This is where manipulating data in lists gets a bit more complicated. Follow along - I promise we will get there.
In the example below, we pass conditional logic after the "in" statement
numbers = [1, 2, 3, 4, 5, 6]
evens = [num for num in numbers if num %2 == 0]
print(evens)
## [2, 4, 6]
odds = [num for num in numbers if num %2 != 0]
print(odds)
## [1, 3, 5]
Here is another example where the if statement is actually used before the "for" statement.
example = [num*2 if num % 2 == 0 else num/2 for num in numbers]
print(example)
## As you can see in the first line above, everything before the "for" in this statement is conditional.
## If the number is even, double it. If the number is odd, half it.
## [[0.5, 4, 1.5, 8, 2.5, 12]]
What if we wanted to combine strings from a list using list comprehension?
example = '... '.join(["cool", "dude"])
print(example)
## 'cool... dude'
Let's take that a bit further.
base_string = "Learning Python is so much fun!"
## FYI - character is a made up variable
without_vowels = ''.join([character for character in base_string if character not in "aeiouy"])
#sometimes "y" right?
print(without_vowels)
# Outputs: 'Lrnng Pthn s s mch fn!'
Nested Lists
Nested lists are just "multi-dimensional elements" meaning it's a list within a list. In Javascript we call this an Array, not a ton different here.
Example:
example_nested_list = [1, [1, 2], [1, 2, 3], [1, 2, 3, 4]]
print(example_nested_list[-1][0])
## [1]
## The result would be the last item in the main list, then the first element inside it which is 1.
Common use cases are games, mazes, rows & columns for visualizations, tabulation, and grouping of data.
Here is another example:
coordinates = [[10.1232, 91.12312], [ 32.112, 348.232], [23.234, 22.234]]
for location in coordinates:
print (location)
for coordinates in location:
print(coordinates)
What about nested list comprehension?
In the example below we create a nested list, then we run a list comprehension inside of a list comprehension, we are getting a little "Inception-y" here.
nested_list = [[1,2,3],[4,5,6],[7,8,9]]
[[print(value_of) for value_of in thing] for thing in nested_list]
## 1
## 2
## 3
## 4
## 5
## 6
## 7
## 8
## 9
Here is another example of nested list comprehension (bear in mind "number" is a made up variable):
example = [[number for number in range(1,4)] for thing in range(1,4)]
print(example)
## [[1, 2, 3,], [1, 2, 3,], [1, 2, 3,]]
turned_x_or_o = [["X" if number % 2 !=0 else "O" for number in range(1,4)] for thing in range(1,4)]
print(turned_x_or_o)
## [['X', 'O', 'X'], ['X', 'O', 'X'], ['X', 'O', 'X']]
Lists Recap
Lists in Python are very similar to Arrays in Javascript and even some of the builtin methods in Python have the same name and function, know the differences and you will be a pro a lists. Here are some key highlights from this section on Lists.
- Lists are fundamental data structures for ordered information
- Lists can include any data type
- Lists can be modified used a number of builtin methods
- Slice is useful for making copies of lists
- List Comprehension is shorthand when iterating over lists, strings, ranges, and even more data types.
- Nested lists are essential for building more complex data structures like matrices
- swapping is useful when shuffling or sorting.
Dictionary Data Structure
Section Table of contents
- I created a dictionary, how do I pull the value out?
- builtin methods to modify and copy dictionaries
- Iterate over dictionaries using loops and dictionary comprehensions
- Dictionary ComprehensionUsing 'in' with Dictionaries
- Dictionary methods
- .clear() method
- .copy() method
- .fromkeys() method
- .get() Method
- .pop()
- .popitem()
- .update()
Lists are great but there are some limitations, specifically an inability to describe data in more detail, perhaps something like an Array of objects (or object notation) with a key value pairs from Javascript would be cool?
Python Dictionaries has entered the chat.
A Dictionary is a structure that consists of key value pairs. Here is a cheap example of what one might look like:
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
The syntax is almost exactly the same as Javascript. This dictionary notation is much more verbose than just a list that has:
my_description = ["Drew", True, "codingwithdrew.com", "number of kids", "value"]
Just like in Javascript where an array can nest/contain objects, you can do the same thing with python lists and dictionaries because lists can contain multiple data types.
You can create dictionaries like the example above or you can use another approach called dict()
where you assign keys by passing in keys and values separated by an =
sign. Here is an example:
dog = dict(name="Charlie", age=0.5)
This is not my preference but I thought it would be good to mention it.
I created a dictionary, how do I pull the value out?
Just like in Javascript when working with objects you can call the dictionary and then request a key. From the first example above with my_description, we will call for "name":
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
print(my_description["name"])
# 'Drew'
Built in methods to modify and copy dictionaries
What if I'd like to access all the values in a dictionary? There is a builtin method in python called .values()
. Let's look at an example:
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
print(my_description.values())
## dict_values(['Drew', True, 'codingwithdrew.com', 2, 'value'])
We can also use another builtin method called .keys()
which allow us to search for a value and return the key. Here is an example:
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
print(my_description.keys())
## dict_keys(['name', 'has_dog', 'website_url', 'number of kids', 'key'])
We also have another useful method builtin called .items()
which will output all the key value pairs as individual objects in the list.
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
print(my_description.items())
## dict_items([('name', 'Drew'), ('has_dog', True), ('website_url', 'codingwithdrew.com'), ('number of kids', 2), ('key', 'value')])
Iterate over dictionaries using loops and dictionary comprehensions
So how can we loop over a list and pull out data? Let's look at an example:
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
for thing in my_description.keys():
print(thing)
## name
## has_dog
## website_url
## number of kids
## key
Something else to look at is the use of a for loop on the items() method. Here is an example:
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
for key, value in my_description.items():
print(key, value)
## name Drew
## has_dog True
## website_url codingwithdrew.com
## number of kids 2
## key value
There is no specific order that a dictionary will output but a list is always going to output based on it's index.
Dictionary Comprehension
The syntax for this is a little weird but it'll look like this: {_____:____ for ____ in ____}
Check out this example:
numbers = dict(first=1, second=2, third=3)
numbers_x_2 = {key: value * 2 for key, value in numbers.items()}
print(numbers_x_2)
## {'first': 2, 'second': 4, 'third': 6}
Note: the "key: value" and "key, value" can literally be anything as long as they match.
Don't forget you can use conditional logic with your
Using 'in' with Dictionaries
What if you want to see if a key or a value exists in a dictionary?
In python there is a way to test this by using "in", check out this example.
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
print("name" in my_description)
## True
I can also do the same thing with one of our methods, let's look at another example.
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
print('name' in my_description) # True
print('name' in my_description.values()) # False
print('name' in my_description.keys()) # True
Dictionary methods
Compared to lists there is fewer methods to use with dictionaries. None the less, knowing these fundamentals will lend you well when manipulating data sets in the future.
Let's look at some examples:
.clear() method
example_dictionary = dict(a = 1, b = 2, c = 3, d = 4, e = 5)
print(example_dictionary)
## {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
example_dictionary.clear()
print(example_dictionary)
## {}
.copy() method
example_dictionary = dict(a = 1, b = 2, c = 3, d = 4, e = 5)
clone = example_dictionary.copy()
if clone == example_dictionary:
print('These dictionaries are clones')
if clone is not example_dictionary:
print('These dictionaries do not occupy the same block of memory, meaning they are separate')
.fromkeys() method
This one is a bit odd and works differently than the others. Typically we use it on an empty dictionary.
Example 1:
{}.fromkeys("a","b")
## {'a':'b'}
Example 2:
{}.fromkeys(["email], 'unknown')
## {'email': 'unknown'}
Example 3:
{}.fromkeys("a", [1,2,3,4,5])
## {'a', [ 1, 2, 3, 4, 5]}
So why would you ever want to do this?
If we have a ton of keys to set to a default value, this would be especially useful.
Take this example to get a better idea of the concept here. Imagine you are trying to create a user dictionary and pre-fill all of it's values with None
until the user fills out the data in some form later on. We could easily create that and save a ton of lines of code using this short hand.
new_user = {}.fromkeys(['name', 'score', 'email', 'profile bio'], None)
print(new_user)
## {'name': None, 'score': None, 'email': None, 'profile bio': None}
An important "gotcha"! Be sure to use a List for your keys otherwise it will try to iterate over each letter of the string you pass as the first argument. You can also pass a range as the first argument.
.get() Method
.get is probably the most useful of these examples. It will retrieve a key in an object and return None instead of a KeyError if the key does not exists.
Let's look at an example:
example_dictionary = dict(a = 1, b = 2, c = 3, d = 4, e = 5)
example_dictionary['a'] # 1
example_dictionary.get('a') # 1
example_dictionary['b'] # 2
example_dictionary.get('b') # 2
example_dictionary['no_key'] # KeyError
example_dictionary.get('no_key') # None
.pop()
This dictionary method is very similar to the list method by the same name. We can use it to remove a single key-value-pair for a given key. Example time!
example_dictionary = dict(a = 1, b = 2, c = 3, d = 4, e = 5)
example_dictionary.pop('a')
## {'b': 2, 'c':3, 'd':4, 'e':5}
.popitem()
This method is used to remove the key and value just like the .pop() method.
example_dictionary = dict(a = 1, b = 2, c = 3, d = 4, e = 5)
print(example_dictionary.popitem())
## ('e', 5)
.update()
Update keys and values in a dictionary with another set of key value pairs, check out an example
example_dictionary_1 = dict(a = 1, b = 2, c = 3, d = 4, e = 5)
example_dictionary_2 = {}
example_dictionary_2.update(example_dictionary_1)
Another example that may be a little easier to follow since we have used it before, let's consider that we want to create a new "person" and add a country to their dictionary:
my_description = {
"name": "Drew",
"has_dog": True,
"website_url": "codingwithdrew.com",
"number of kids": 2,
"key": "value",
}
person = {"city": "Charlotte"}
person.update(my_description)
print(person)
## {'city': 'Charlotte', 'name': 'Drew', 'has_dog': True, 'website_url': 'codingwithdrew.com', 'number of kids': 2, 'key': 'value'}
If there is a key:value from the list you are passing into the arguments of .update() then it will overwrite the value in the dictionary the method is being applied to.
Tuples and Sets
Section Table of contents
-Describe, create and access tuples
- What is a tuple? (too-pul or tupple)
- Use builtin functions and methods to modify sets and access values in tuples
- What functions are built into tuples
- What methods are builtin for tuples?
- How to Loop over tuples
- What is a set?
- What are the builtin methods for sets?
- Iterate over sets using loops and set comprehensions
Describe, create and access tuples
What is a tuple? (too-pul or tupple)
An ordered collection or grouping of items.
A tuple uses comma separated values inside of parenthesis like this:
example = (1, 2, 3, 4)
So what's the difference between a tuple and a list? The main difference is like a const in Javascript, tuples are immutable which is the defining difference between javascript and python.
*/Javascript equivalent*/ const variableName = [1,2,3,4] == variable_name = (1,2,3,4) # Python equivalent
Tuples are faster than lists and it makes your code safer but may not necessarily be the right tool for every job.
In javascript you have "const" and "let" and in es5 there is only "var" (this is some of that old javascript support garbage that hasn't been cleared out). const means the variable that follows is immutable. let and var mean that the variable is likely to change. So in python instead of having spelt out the difference between immutable (const) and mutable (let/var), you do it with syntax.
The main syntactical difference between a list and a tuple is that it's got a parenthesis instead of square brackets.
Single item tuples will have a
,
after the single item to differentiate it from just parenthesis wrapping the variable.
Use builtin functions and methods to modify sets and access values in tuples
What functions are built into tuples
You can create tuples just like you would a dictionary with dict()
but instead use .tuple
like this:
example_tuple = tuple(1, 2, 3, 4, 5)
You can then access the data in the tuple the same way you would a list:
example_tuple = tuple(1)
print(example_tuple)
You can only pass 1 argument into a tuple unless you pass it a tuple within a tuple, which is weird.
example_tuple = tuple(1, 2, 3)
print(example_tuple)
Fails with TypeError: tuple expected at most 1 argument, got 3
so to make it work you have to do it like this:
example_tuple = tuple((1, 2, 3))
print(example_tuple)
Another interesting note: Tuples can be used as keys in dictionaries and some dictionary methods like .items() return tuples.
What methods are builtin for tuples?
.count()
returns the number of times a matching value appears in a tuple - much like the .count method on lists.index()
returns the index of the first matching value of a tuple much like the index method on lists. Javascript equivalent is "indexOf()"
How to Loop over tuples
A simple for loop should do the trick:
months = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
for month in months:
print(month)
i = len(month[i])
i += 1
What is a set?
Sets are like formal mathematical sets that don't have duplicate values and are in no particular set order. Another important distinction is the lack of an index. You create one by using a simple syntax: variable_name = set({x, y, z, etc})
.
Example:
example_set = set({1,2,3,4,5,5,5})
print(example_set)
## {1,2,3,4,5} note the duplicates are removed
You can convert lists to sets to deduplicate their data and then convert bck to a list. Here is an easy way to do that:
example_set = set({1,2,3,4,5,5,5})
print(list(set(example_set)))
What are the builtin methods for sets?
.add()
- Adds an element to a set. If the element is already in the set, the set doesn't change. Example:example_set = set({1,2,3,4,5,5,5}) example_set.add(5) ## Nothing happens.
.remove()
- removes a value form the set and will return a KeyError if the value is not found.example_set = set({1,2,3,4,5,5,5}) example_set.remove(5) print(example_set) ## {1, 2, 3, 4}
.copy()
- Creates a copy of a set (not in the same memory block)example_set = set({1,2,3,4,5,5,5}) clone = example_set.copy() print(clone is example set) ## False
.clear()
- removes all the contents of a setexample_set = set({1,2,3,4,5,5,5}) example_set.clear() print(example_set) ## set()
|
- Set Math "union" allows you to combine two sets.example_set1 = set({1,2,3,4,5,5,5}) example_set2 = set({6,7,3,4,1,4,8,9,10,3,4}) math_examples = example_set1 | example_set2 print(math_examples) ## {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
&
- Set math "intersection" - allows you to find where values exist in 2 sets.example_set1 = set({1,2,3,4,5,5,5}) example_set2 = set({6,7,3,4,1,4,8,9,10,3,4}) math_examples = example_set1 & example_set2 print(math_examples) ## {1, 3, 4}
Iterate over sets using loops and set comprehensions
Set Comprehension is the same concept as it is with dictionaries but we don't specify a key value pair, we just specify 1 thing. It looks like this:
{x*2 for x in range(5)}
## {0, 2, 4, 6, 8}
Functions
Section Table of contents
- How are Python and Javascript different with functions?
- What is a function in python and how are they useful?
- How do I create a function?
- What is the return keyword and how does it work?
- What are parameters?
- How do you set default parameters?
- How does scope work in a function?
- What is global scope?
- What is functional scope?
- What are Non-local variables?
- Documenting Functions
- How do we use * and * operators as parameters to a function and outside of a function? Also known as "args"
- What is a **kwargs? (pronounced "QWARGS")
- Ordering Parameters
- How do we leverage dictionary and tuple unpacking to create more flexible functions?
- What is unpacking of tuples and how do I do it?
- How do I unpack a dictionary?
- Lambdas (anon functions)
- Maps
- What are maps?
- Filter
- What is filter with python?
- How can I combine filter and map?
- builtin Functions:
- Higher Order Functions
How are Python and Javascript different with functions?
The easiest way I'm going to be able to contrast functions for javascript and python is to point you to my resource on Javascript functions: https://codingwithdrew.com/javascript-functions/
What is a function in python and how are they useful?
We have been working with functions like print()
or len()
, officially they are a process for executing a task. It's typically reusable and it can accept input and return an output.
Functions are excellent tools for keeping our code "DRY".
How do I create a function?
The best way to describe how to create a function is with an example:
def name_of_function ():
#block of code that will run in the function must be indented
print('This is a function')
name_of_function()
## This is a function
What is the return keyword and how does it work?
The return keyword is used to export the contents of a function so that it's accessible outside of the function but as soon as return runs, it will exit the function. Let's consider the following function:
def example_no_return():
1+2
result = example_no_return()
print(result)
What do you think the result would be?
If you said None, you'd be correct because the inside of that function isn't accessible on a global scope, only inside the function. To make it accessible and print 3 as it should, you'd need to return the value so that it can output.
def example_no_return():
return (1+2)
result = example_no_return()
print(result)
Keep in mind if you had any code run outside of the return statement - it wouldn't run because
return
will exit the code that is running. The function will no longer be in the call stack. Without getting into too much detail you can see more at https://sites.cs.ucsb.edu/~pconrad/cs8/topics.beta/theStack.prev/01/
What are parameters?
Parameters is data passed into a function which will capture an input for the function.
Parameters are different from Arguments, arguments are the actual data passed where as the parameters are placeholder names.
How do you set default parameters?
This is just like in javascript where you set a value using =
to a parameter, like this:
def example_default_value(parameter1, parameter2=10):
return(parameter1 * parameter2)
print(1)
print(2,1)
print(5,2)
What do you think the result would be?
10
2
10
You can also pass key-value-pairs as parameters which makes things easier to read and is not order dependant as comma separated values.
How does scope work in a function?
This section isn't super interesting but understanding it's fundamentals is going to be key.
If you know nothing about Javascript scope, I recommend that you read up on it here in this article I wrote about javascript scope: https://codingwithdrew.com/scope-hoisting-and-closures/.
Scope in both languages appears to be the same.
What is global scope?
Global Variables are variables that are at the root and are unavailable to a function unless you prefix it within the function with global
like this:
total = 0
def increment():
global total
total += 1
return total
print(increment())
## 1
What is functional scope?
Functional scope is basically a variable defined inside a function is not available outside the function unless it's returned.
What are Non-local variables?
If you have a function inside a function and would like to call the outer function using the inner function's scope, you can prefix that function with "nonlocal". It's very similar to global but it just allows inner functions to access outer function's variables not at the global scope level.
Documenting Functions
Python comes with internal documentation tools for functions using """
(three double-quotes) before and after your documentation of the function.
This is similar to just writing comments to your code - it's super useful for more complex code.
How do we use * and * operators as parameters to a function and outside of a function? Also known as "args"
*args is a special operator we can pass to functions that will gather remaining arguments as a tuple. Basically it's just a parameter and we can name it anything we want as long as it starts with a *
.
Example part 1:
def sum_all_numbers(ex1, ex2, ex3)
return ex1, ex2, ex3
print(sum_all_numbers(4,6,9))
## 19
What if you wanted to make it so you could pass in more numbers as arguments into your print function but you don't know how many?
Example part 2:
def sum_all_numbers(*args):
return args
print(sum_all_numbers(1,2,3,4,5,6,7,8,9))
As you can see it will output a tuple of "(1, 2, 3, 4, 5, 6, 7, 8, 9)".
Example part 3:
def sum_all_numbers(*args):
a = 0
for b in args:
a += b
return a
print(sum_all_numbers(1,2,3,4,5,6,7,8,9))
## 45
What is a **kwargs? (pronounced "QWARGS")
*kwargs or "keyword args" is a special operator we can pass to functions just like the args that outputs extra arguments as a dictionary. 2 **
characters and then any name you like is the only requirement.
Ordering Parameters
- parameters
- *args
- default parameters
- **kwargs
How do we leverage dictionary and tuple unpacking to create more flexible functions?
What is unpacking of tuples and how do I do it?
Let's look at our original example on *args here:
Example Part 1:
def sum_all_numbers(*args):
a = 0
for b in args:
a += b
return a
print(sum_all_numbers(1,2,3,4,5,6,7,8,9))
## 45
Example Part 2:
In this example we will be setting the value of b
to a tuple of numbers 1-6 and then we will pass b
as an argument to our main function. What do you think will be the outcome?
b = (1,2,3,4,5,6)
sum_all_numbers(b)
We get a error:
TypeError: unsupported operand type(s) for +=: 'int' and 'tuple'
The way we fix this is by passing a *b
as an argument instead. This is a bit weird but the reason for this is that without parsing out the individual values in b
from the tuple, you would be passing a single value tuple as an argument. Instead, what this *b
argument does is that it "unpacks" the tuple and then passes each individual value from the tuple into the sum_all_numbers()
function. When it's all said and done, it should look like this:
def sum_all_numbers(*args):
a = 0
for b in args:
a += b
return a
print(sum_all_numbers(1,2,3,4,5,6,7,8,9))
## 45
b = (1,2,3,4,5,6)
print(sum_all_numbers(*b))
## 21
How do I unpack a dictionary?
Just like the previous example for tuples, you cannot pass a whole dictionary into an function as an argument, so you just need to pass your argument with a **
as a prefix to the dictionary name.
Example:
def add_and_multiply_numbers(a,b,c):
print(a+b+c)
a = dict(a=1,b=2,c=3)
add_and_multiply_numbers(**a)
## 6
Lambdas (anon functions)
This topic is a little weird. Follow along though. Let's start with an example.
Example Part 1:
def square(a):return a * a
print(square(2))
Above is a traditional functional declaration and it's been shortened to a single line. It's also a named function square()
meaning you can call it over an over again using it's name and passing an argument. In Javascript this would be a traditional functional declaration.
Example Part 2:
square = lambda a: a * a
print(square(2))
## 4
Above you can see some funkiness going on but if you are familiar with Javascript anonymous functions, this will all make sense. Basically a python lambda is just a javascript anon function (typically, they aren't stored as a variable but for demonstration purposes, we are).
Maps
What are maps?
A map in Javascript and Python are very similar - it's a standard function that accepts 2 or more arguments, a function, and an "iterable".
An iterable is something can be iterated over (lists, strings, dictionaries, sets, & tuples).
It will run a lambda for every value in the iterable and then return a map object which can be converted to any other data type.
Example:
example_list = [2, 4, 6, 8, 10]
doubles = list(map(lambda a: a*2, example_list))
print(doubles)
## [4, 8, 12, 16, 20]
Filter
What is filter with python?
There is a lambda for each value in the iterable which will return filter objects which can be converted into other iterables (lists, strings, dictionaries, sets, & tuples). The object contains only the values that return true to the lambda.
Example:
example_list = [1,2,3,4]
evens = list(filter(lambda x: x % 2 == 0, example_list))
print(evens)
## [2,4]
How can I combine filter and map?
Return a new list with the string "Drew is" + each value in the list, but only if the value is less than 5 characters.
my_description = [
"Drew.",
"has a dog.",
"the owner of codingwithdrew.com.",
"has 2 kids.",
"two",
"dog",
"tree"
]
print(
list(
map(
lambda a: f"Drew {a}",
filter(
lambda b: len(b)>5,
my_description
)
)
)
)
## ['Drew has a dog.', 'Drew the owner of codingwithdrew.com.', 'Drew has 2 kids.']
Builtin Functions:
all()
will return True if all elements of the iterable are truthy (or if it's empty). Here are a few examples:
Example 1:
all([0,1,2,3]) # False
Example 2:
all([a for a in 'eio' if char in 'aeiou'])
## True - because all letters eio are found in aeiou
any()
will return True if any element of the iterable are truthy, if it's empty, it will return false.sorted()
will return a new sorted list from the items in iterable. You can pass 2 arguments, the first being the iterable you'd like to pass and optionally you can passreverse=True
which will sort the order in descending. It can accept a tuple but not a dictionary unless you pass akey=len
(counts the number of keys) or you can pass a lambda into the key= like this:key=lambda x: x['key_name']
.max()
will return the largest item in an iterable or the largest of 2 or more arguments. Just like sorted, you can pass the "key" argument with a lambda or a key name if you need.min()
similarly will return the smallest item in an iterable or the smallest of 2 or more arguments. Just like sorted, you can pass the "key" argument with a lambda or a key name if you need.reversed()
(past tense of reverse) - This method will return the reverse order of an iterable. You can also just usevariable_name[::-1]
as welllen()
- (short for "length"). We have already used this one in the past but felt we should include it here.abs()
"Absolute value - returns the absolute value of a number - the argument may be an integer or a floating point numbersum()
This builtin function will take an iterable as an argument and an optional start then returns the sum of the "start" and will add together all of the subsequent iterables from left to right. The default value for start is set to 0.round()
this builtin function will return a number routed to ndigits precision after the decimal point. If ndigits is not specified or is None, it will return the nearest whole number (int) by default.zip()
- this one is weird but I cannot count how many times this would have been useful in Javascript! Make an iterator that aggregates elements from each of the iterables passed into the function (there is a minimum of 2 but you can have as many as you'd like). It will return an iterator of tuples where the i-nth tuple contains the i-nth element from each of the argument sequences or iterables. The iterator will continue to run through the iterables until it reaches the end of the shortest one.
Example 1 (combining 2 lists):
example_list1 = [1,2,3,4,5]
example_list2 = [6,7,8,9,10,11,12,13,14,15]
example_zip = dict(zip(example_list1, example_list2))
print(example_zip)
## {1: 6, 2: 7, 3: 8, 4: 9, 5: 10}
## note that it stopped at 10 because
## the len(example_list1 == 5) and
## the len(example_list2 > 5)
## So it will only run through a total of 5 indexes before
## exiting the function
Example 2 (unpacking a list of tuples using *
and then zipping them):
example_list_of_tuples = [(1,1), (2,2), (3,3), (4,4),(5,5)]
unpacked_list = list(zip(*example_list_of_tuples))
print(unpacked_list)
## [(1, 2, 3, 4, 5), (1, 2, 3, 4, 5)]
Example 3 (advanced use of zip):
game_1 = [80,91,78]
game_2 = [98,89,53]
players = ["Tj", "Eugene", "Drew"]
grades = dict(
# specify a dictionary to output the kind of info we want
zip(
players,
map(
lambda foo: max(foo),
zip(game_1, game_2),
),
)
)
print(grades)
## {'Tj': 98, 'Eugene': 91, 'Drew': 78}
Higher Order Functions
If you are new to programming, you can skip this one and it will make more sense in the decorators section.
These are functions that accept one or more functions as an argument.
def sum(a, func):
total = 0
for b in range(a):
total += func(b)
return total
def double(c):
return c*2
print(sum(5, double))
Debugging!
Debugging in general is the same across Javascript and Python but there are different naming conventions which you will want to know and a difference in the debugger tools.
Section Table of contents
- What are the common error types (exceptions) and how to cause them in Python?
- How do I create custom error messages?
- How do you use try and except block to handle errors?
- How do you use pdb to set breakpoints and step through code in python?
- What are the common PDB commands?
What are the common error types (exceptions) and how to cause them in Python?
You are going to make mistakes (in your code) so you should probably know how to identify them.
SyntaxError
- typically will be the result of python running through code and something that doesn't parse blocks further code from running. This is usually due to typos or not knowing python well enough.NameError
- This happens when a variable is not defined or hasn't been assigned yet.TypeError
- Occurs when there is a mismatch of data types. Python cannot interpret an operation on two data types. For example - you cannot calculatelen(5)
because the number 5 isn't a string and it doesn't have a length.IndexError
- This will happen if you try to access an element in a list using an invalid index (i.e. one that is outside the range of the iterable)ValueError
- If you use a builtin operation or function and pass an argument that doesn't have the right data type or an inappropriate value.KeyError
- like the ValueError, this occurs on a dictionary when the dictionary doesn't have the specific key.AttributeError
- This occurs when a variable does not have an attribute. Basically if you call method that is misspelled you'd cause this.
For more details on all the error types, you can reference this handy document: https://docs.python.org/3/library/exceptions.html
How do I create custom error messages?
In python we can throw errors using the "raise" keyword. This is helpful when creating our own kinds of exceptions and error messages. In Javascript we "throw" errors, the difference is pretty negligible.
Basically just create if statements and if a condition is met, pass an error like this:
raise ExampleErrorName("foo boo bar")
You'll want to be descriptive with the name and error messaging here so that your end user doesn't struggle.
def colorize(text, color):
if type(text) is not str:
raise TypeError("text must be a string")
print(f"Printed {text} in {color}")
colorize("hello", "red") # successful
colorize("43", "red") # Exception raised: TypeError: "Text must be a string"
How do you use try and except block to handle errors?
In Javascript we have try/catch and similarly we have try/except blocks in python. These are used to catch exceptions when we can do something about them.
If we open a python3 repl, we can call python3 foobar
we will get a NameError
but if we do the same thing with a try except function
try:
foobar
except NameError as err:
print("PROBLEM!")
print("This line is called after the try has happened")
What we are doing here is catching every error, which means we are not able to correctly identify "what" specifically went wrong. This is highly discouraged. You will want to be explicit in the error conditionals that your error will output.
Important to note, you can only use one except block.
There is also an else:
and finally:
syntax which I will demonstrate below.
try:
foobar
except NameError as err:
print("PROBLEM!")
else:
print("I'm in the else and I'm great for conditionals")
finally:
print("I will run no matter what!")
How do you use pdb to set breakpoints and step through code in python?
Nothing super ground breaking here for Javascript learners. Unlike Javascript's built in debugger;
Python debugger (pdb) is a module that we have to import with a single line like this:
import pdb; pdb.set_trace()
# commonly imported on the same line it's called
Like Javascript, pdb.set_trace()
inserted into any function will produce a breaking point which will stop the code from running further without manual intervention.
What are the common PDB commands?
l
- listn
- next line (allows you to step through your code line by line)p
- printc
- continue (finishes debugging and closes the debugger - like saying "quit")
There are others and a deeper explanation of the various commands than I have provided here: https://web.stanford.edu/class/physics91si/2013/handouts/Pdb_Commands.pdf
Modules
Section Table of contents
- How does Javascript import/export modules?
- What is a module and why do we care?
- How do you import code from builtin modules?
- What if you want to import only a part of a module?
- How can we make a custom module?
- How to import code from external modules using pip
How does Javascript import/export modules?
There are modules in Javascript that allow you to import and export from one file to another with a few options based on "EchmaScript" version on how to do it.
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
const promise = import("module-name");
const React = require('react');
const Component = React.Component;
require('./App.css');
It's actually kind of a mess, right? I prefer the Python modules more, let's look at it in depth:
What is a module and why do we care?
A module is just a Python file. Modules keep our code small - we can import prebuilt solutions or we can make a much larger program and make that code reusable.
There are a ton of builtin modules we can import that are local to python - for a full list go here: https://docs.python.org/3/py-modindex.html
How do you import code from builtin modules?
Importing builtin modules is easy:
Example:
import random
print(
random.choice(
[1, 2, 3, 4, 5]
)
)
You can also rename imports to anything you want using as
, for example:
import random as oh_my_goodness_thats_random
What if you want to import only a part of a module?
The from
keywords lets you import parts of a module - typically you only want to import what you need and nothing extra to avoid security flaws and file size issues. Do it like this:
from random import choice, randint
Interestingly enough, you no longer have to call "random.choice()" or "random.randint()" you can just call the method alone like this: "choice()" or "randint()"
Even though it's frowned upon, if you still want to import everything, you can use from module_name import *
.
How can we make a custom module?
You can import your own code from one file to another by just specifying the file location in the same fashion as you would with a builtin module.
Example:
import my_custom_hello-world.py as hello_world
How to import code from external modules using pip
In Python you can import modules from external sources like in javascript with yarn or npm. These modules can be located anywhere online, not necessarily from a single centralized repository (if you've read my deno articles, you'll understand why I dislike npm/node). In python, you'll just use pip
. Pip comes preinstalled with python3 (supported versions) so no need to do anything fancy here since if you are on a mac, python2 and python3 come pre-installed.
You can install any package you want following this simple terminal command:
python3 -m pip install CORRECT_NAME_OF_PACKAGE
You can view all the terms available to use on an imported module by running dir(CORRECT_NAME_OF_PACKAGE)
or you can use help(name_of_term)
for a manual of how to use the terms/submodule.
The __name__ Variable
To my knowledge there is no built in equivalent of this in Javascript and you could pull this off using Javascript's .main()
but you have to use a ===
comparator - with that being said - read on!
The "Dunder" (double underscore) "name variable" is a hard concept to fully understand but I full appreciate it's application when writing CI/CD pipelines. We will see that every python file has a __name__
variable. If the file is the main file being run, it's value is __main__
.
That's hard to abstractly conceptualize. Basically, it will call a variable "__main__
" if the __name__
variable is set and called in it's own module but if the module is on another file that is being imported then __name__
will be replaced with the actual file name (without the .py part).
if __name__ == '__main__':
do_thing()
In the example above, you can run the script but only if it's run directly (the if
will evaluate to True)
__BUT__
If you import something from the script at the Python CLI or from another script, it will evaluate to False and not trigger the scripts default behavior.
Javascript was not designed to be run directly from the command line like Python was so it doesn't have a similar import mechanism to what Python has. Python doesn't need a clunky work around like using the .main() method in Javascript.
It is done this way because Python doesn't want to make assumptions of where an application entry point is (ie CLI or from another module) and what files can and cannot be run directly.
OOP - Object Oriented Programming
Section Table of contents
- What is OOP?
- What is a class?
- What is an instance?
- Why OOP?
- How do I make a variable private in Python?
- What is Encapsulation?
- What is Abstraction?
- How do I create a class in Python?
- How do you make a method or function private to a specific class?
- How do we add instance methods?
- What is a class attribute and how do I use it?
- How do class methods in python work?
- What is string representation? (The
__repr__
method) - What is Inheritance?
- How do we implement inheritance?
- How do I use @properties in Python?
- How does Super() work with python?
- What is polymorphism?
_The core tenants of OOP are the same across languages that support it, implementation and syntax may be slightly different but the concept is the same. If you already understand classes well in Javascript, this will be a total breeze but I do recommend you read this section anyways. Javascript this
also seems to have some similarities with Python's MARKDOWN_HASH2eacefd9a69c9d858e68ad3e94691bf9MARKDOWNHASH
which we will get into in a moment, but it's not a 1:1 similarity.
What is OOP?
OOP is code that represents something in the real world objects as an abstract model to create new objects with. It is stored as a class or object and it has 4 main pillars:
- Abstraction
- Encapsulation
- Inheritance
- Polymorphism
What is a class?
A class is a blueprint for objects that can contain methods (functions) and attributes (like keys in a dictionary). Think of it like a blueprint for a house - it defines all the things that make a house a house but each individual house built from that blueprint can have different characteristics like the height of the windows or color of the walls.
What is an instance?
An instance is an object constructed from a class (blueprint) that contains all of the class' methods and properties. In our house analogy, imagine it's a specific house that was built from the house blueprint with it's own characteristics like a blue door, yellow exterior paint, green trim.
list for example is a class and when you create a new list, you are basically just creating an instance of class list.
Why OOP?
OOP is a human way of thinking to classify objects and group them in a logical, hierarchical grouping using classes so that you can reason about your code at a higher level.
How do I make a variable private in Python?
There is no real way to prevent someone from accessing a variable outside of a class but if you wanted to you can leverage naming conventions like _name
to identify an attribute as private to the class and one that shouldn't be publicly exposed.
What is Encapsulation?
Encapsulation is the grouping of public and private attributes and methods into a programmatic class making abstraction possible.
What is Abstraction?
Abstraction is the idea of hiding the complicated inner workings and exposing only the relevant data in a class interface - specifically hiding private attributes and methods from users.
How do I create a class in Python?
Naming convention - use Capitalize the first letter and camel case. You will want to instantiate (create) the class by creating an object that is an instance of the class.
Check out the easiest class ever.
class ExampleObjectClass:
pass # this line basically says "ignore me"
ExampleObjectClass() # instantiating or "creating"
print(type(ExampleObjectClass()))
# <class '__main__.exampleobjectclass'="">
See that fancy dunder main?
Classes in Python can have a special __init__
method which will get called every time you create an instance of a class (instantiate it). Let's look at an example of it:
class User:
def __init__(self, first, score, color):
self.name = first
self.score = score
self.color = color
user1 = User("Drew", 57, "Blue")
user2 = User("TJ", 99, "Red")
user3 = User("Eugene", 88, "Yellow")
print(user1.name, user1.score, user1.color)
print(user2.name, user2.score, user2.color)
print(user3.name, user3.score, user3.color)
## Drew 57 Blue
## TJ 99 Red
## Eugene 88 Yellow
Important note: self must always be the first parameter to init and any methods and properties on the class instances.
"self" is not a required name but it's standard naming convention for Python. It's very similar to "this" in Javascript. If you want to learn more about it - check out my article on "this" here: https://codingwithdrew.com/javascript-this-keyword/
How do you make a method or function private to a specific class?
Double underscore as a prefix to a method name will cause it to be a method that can only be called with the parent class name in it. Here is what I mean:
class Example:
def __init__ ()
How do we add instance methods?
With our current understanding of classes, we don't really see a massive benefit to this OOP methodology until we start to talk about class methods.
Let's consider an example loosely based on the previous one
class User:
def __init__(self, first, last, score, color):
self.first = first
self.last = last
self.score = score
self.color = color
def full_name(self):
return f"{self.first} {self.last}"
user1 = User("Drew", "Karriker", 57, "Blue")
user2 = User("TJ", "Ninneman", 99, "Red")
user3 = User("Eugene", "Serdiouk", 88, "Yellow")
print(user1.full_name(), user1.score, user1.color)
print(user2.full_name(), user2.score, user2.color)
print(user3.full_name(), user3.score, user3.color)
## Drew Karriker 57 Blue
## TJ Ninneman 99 Red
## Eugene Serdiouk 88 Yellow
As you can see in the example above, we created a new class object in the __init__
called self.last and then a function that is called full_name()
that we passed the self
parameter inside of it (similar to React.js props, I guess?) then you can call that function as a method to instantiate by saying "user1.full_name()
".
That's a neat tool but these methods are specific to instances, let's look at class attributes then class methods.
What is a class attribute and how do I use it?
Class attributes allow you to apply a method across all instances of that class, they are defined directly on a class. Remember global scope and local scope, well we can apply variables that are present for the whole class by adding them above the __init__
statement. The benefit is that it's defined one time instead of for each instance.
Let's take a look at class attributes in action.
class User:
active_users = 0
def __init__(self, first, last, score, color):
self.first = first
self.last = last
self.score = score
self.color = color
User.active_users += 1
def full_name(self):
return f"{self.first} {self.last}"
def logout(self):
User.active_users -= 1
return f"{self.first} {self.last} has logged out."
print(User.active_users)
## 0
user1 = User("Drew", "Karriker", 57, "Blue")
print(User.active_users)
## 1
user2 = User("TJ", "Ninneman", 99, "Red")
user3 = User("Eugene", "Serdiouk", 88, "Yellow")
print(User.active_users)
## 3
print(user2.logout())
## TJ Ninneman has logged out.
print(User.active_users)
## 2
As you can see, class attributes are good for keeping track of things from a macro view of the status of instances.
Another use case is for validations, let's take a look:
class Hoa_permission:
allowed = ["cat", "dog", "bird"]
def __init__(self, name, species):
if species not in Hoa_permission.allowed:
raise ValueError (f"{name} is NOT allowed per the HOA")
else:
print(f"{name} is allowed per the HOA")
self.name = name
self.species = species
Hoa_permission("Charlie", "dog")
Hoa_permission("Happy", "bird")
Hoa_permission("Jaimie Lanister", "goat")
## Charlie is allowed per the HOA
## Happy is allowed per the HOA
## Traceback (most recent call last):
## File "~/Dev/python/hello-world.py", line 379, in
## Hoa_permission("Jaimie Lanister", "goat")
## File "~Dev/python/hello-world.py", line 371, in __init__
## raise ValueError (f"{name} is NOT allowed per the HOA")
## ValueError: Jaimie Lanister is NOT allowed per the HOA
We can also define attributes directly on a class that are shared by all instances of a class and the class itself.
How do class methods in python work?
Remember syntactic sugar? Well class methods are invoked with an @classmethod
much like Javascript prototypes and classes. Class methods are not concerned with instances but only with the class itself.
Syntactic sugar is abstract syntax (shorthand, simplified, easy to understand, exposed whats necessary)
It's basically the same as an instance method but you preface it with the @classmethod
- it adds a little boilerplate to your code but class methods are less frequently used than the default instance methods which is why they don't need any syntactic sugar.
The main difference between a class and an instance method is that you would use cls
instead of self
.
Check this abbreviated code for an example:
class Example_class_method():
# ...
@classmethod
def from_csv(cls, file_name):
return cls(*params) # this is the same as calling Example_class_method(*params)
What is string representation? (The __repr__
method)
The __repr__
method is one of several ways to provide a nicer string representation. This is certainly not my favorite. Again, there doesn't seem to be a 1:1 equivalent from Javascript.
class Person:
def __init__(self, name="someone", language="Python"):
self.name = name
self.language = language
def __repr__(self):
return self.name
mdude = Person()
print(mdude)
## someone.
drew = Person(name="Drew")
print(f"{drew} learns {drew.language}!")
## Drew learns Python!
It's a bit confusing but if you tried to run the example above with out the string representation, you'd get a weird error
<'__main__.Person object at 1x2345abc6>
returned because python isn't able to actually pull the string out of the example above and is the reason you cannot pull language out without the "drew" prefix.
What is Inheritance?
Inheritance allows us to define a class that inherits all the methods and properties from another class.
Parent class is the class being inherited from, also called base class.
Child class is the class that inherits from another class, also called derived class.
How do we implement inheritance?
In python this works by passing the parent class as an argument to the definition of a child class - we will go into fairly deep discussion on this later.
class Animal:
def make_sound(self, sound):
print(f"this animal makes the {sound} sound")
class Cat(Animal):
pass
a = Animal()
a.make_sound("beep")
c = Cat()
c.make_sound("Meow")
## this animal makes the beep sound
## this animal makes the Meow sound
How do I use @properties in Python?
Python classes have this a feature where you can decorate (syntactic sugar) a class method with the @property decorator, which makes the method appear as a statically-valued member instead of a callable method. In Javascript the closest thing to @properties
is a getter. Basically the get syntax binds an object property to a class function that will be called when the property is looked up. Let's look at two examples:
Example without @properties
:
class Human:
def __init__(self, first, last, age):
self.first = first
self.last = last
if age >= 0:
self._age = age
else:
self._age = 0
def get_age(self):
return self._age
def set_age(self, new_age):
if new_age >= 0:
self._age = new_age
else:
self._age = 0
drew = Human("Drew", "Karriker", 55) # I'm not really 55
## print(drew.age) ## This errors because there is only _age
## so what we use instead is:
print(drew.get_age())
## 55
drew.set_age(21)
print(drew.get_age())
## 21
Example with @properties
:
class Human:
def __init__(self, first, last, age):
self.first = first
self.last = last
if age >= 0:
self._age = age
else:
self._age = 0
@property
def age(self):
return self._age
@age.setter
def age(self, thing):
if thing >= 0:
self._age = thing
else:
raise ValueError ("That's not an age")
drew = Human("Drew", "Karriker", 55) # I'm not really 55
print(drew.age)
## 55
drew.age = 21
print(drew.age)
## 21
I'd like to mention that both of these are accurate ways to do the same things. Aside from that I think it's important to recognize a different way to do things in other people's code. I feel like the later method is easier to read but thats just a personal preference.
How does Super() work with python?
In Javascript, the super
keyword is used to access and call functions on an object's parent. Remember our animal / cat example from earlier? Imagine that you'd want to be able to reach out to the Animal from within the Cat function you've created and changed.
In the real world, all animals share a set of basic characteristics and a specific animal would have it's own characteristics at the species level and so on. This basically allows the dog from this example to reach out to the animal class and pull it's attributes without repeating them.
Take a look at this example:
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def __repr__(self):
return (f"{self.name} is a {self.species}")
class Dog(Animal):
def __init__(self, name, species, breed, toy):
super().__init__(name, species) ## This is pulling data from Animal class
self.breed = breed
self.toy = toy
def __repr__(self):
return (f"{self.name} is of the {self.species} species of the {self.breed} breed and loves his {self.toy} toy.")
charlie = Dog("Charlie", "dog", "French Bulldog", "Bone")
print(charlie)
## Charlie is of the dog species of the French Bulldog breed and loves his Bone toy.
When ever you create a class, Python sets a Method Resolution Order, or "MRO", for that class. MRO is the order which Python will look for methods on instances of a class. You can use __mro__
attribute to programmatically reference the MRO.
What is polymorphism?
This is a complex topic, but you have made it this far, nothing is too hard for you! The word polymorphism means having many forms. In programming, polymorphism means same function name (but different signatures) being uses for different types. Basically reusable code.
In Python, Polymorphism lets us create and define methods in the child classes that have the same name as the methods in the parent class. With inheritance, the child class inherits the methods from the parent class.
Basically, what that means is that Python is able to use a class method that works in a similar way for different classes and will work for different kind of objects.
A common use case is to have a parent class with a method that is overridden by it's subclass so each subclass will have a different implementation of the method.
Iterators and Generators
Section Table of contents
- What are iterators and iterables?
- How do I write my own version of for loops?
- What are Generators?
- What is a generator Expression?
What are iterators and iterables?
Iterable
- a string, list, dictionary, tuple, or set. Basically an object which will return an iterator when iter() is called on it.Iterator
- an object that can be iterated upon. An object which returns data, one element at a time when the next() function is called on it."Hello" ## is an iterable but is not an iterator. "iter(HELLO") ## returns an iterator
next()
- whennext()
is called on an iterator, the iterator returns the next item it keeps doing so until it raises a StopIteration error.
How do I write my own version of for loops?
The best way to demonstrate is with an example, it's pretty straight forward.
def my_for(iterable):
iterator = iter(iterable)
while True:
try:
print(next(iterator))
except:
return (print("End Of Iterator"))
## my_for("hello world!")
## h
## e
## l
## l
## o
##
## w
## o
## r
## l
## d
## !
## End Of Iterator
What are Generators?
Generators are iterators - they are a short way to create an iterator. They can be created with generator functions and they use the yield
keyword. Generators can be created with generator expressions. They loosely store the state at the yield.
These are regular old functions but instead of using the return
keyword it uses yield
but instead of only being able to "return" once, yield can yield multiple times.
Here is the Javascript equivalent by the same names: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#advanced_generators
Generator-Generator function example:
You will need to run this in the REPL to get it to run. Just open terminal and type
python3
then press enter.def count_to(max): # this is the generator function
... count = 1
... while count <= max:
... yield count
... count += 1
...
counter = count_to(4) # this is the generator
<generator object count_to at 0x106713eb0>Above it output a generator object.
So how do we access the output of the generator object? If we use the next()
function and pass it the generator, we can see our expected results.
>>> def count_to(max): # this is the generator function
... count = 1
... while count <= max:
... yield count
... count += 1
...
>>> counter = count_to(4) # this is the generator
>>> next(counter)
1
>>> next(counter)
2
>>> next(counter)
3
>>> next(counter)
4
What is happening here is that Python is storing it's state between each step.
What is a generator Expression?
You can create a generator from a generator expression which look similar to list compressions - they use ()
instead of the []
notation.
Example time:
>>> a = (b for b in range(1,4))
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
Decorators
What is a Decorator?
Decorators are functions that wrap other functions and extend their behavior. Decorators are examples of higher order functions and they even have their own syntactic sugar.
What is a "Higher Order Function"?
These are functions that accept one or more functions as an argument or return an argument. Let's look at an example:
def sum(a, func):
total = 0
for b in range(a):
total += func(b)
return total
def double(c):
return c*2
print(sum(5, double))
How do I use decorators as functions?
Let's look at a cheap example:
def hello(fn):
def inner_example():
print("Hello!")
fn()
print("Ok, bye!")
return inner_example
def name():
print("My name is Drew")
greet = hello(name)
greet()
## Hello!
## My name is Drew
## Ok, bye!
In this example, you can see that the two functions hello() and name() have nothing to do with each other except that we are passing a function called inner_example into a function called hello and returning the inner_example. We are also calling that hello function and passing the name() function as an argument - this is where they intersect. Now print("Hello!")
, then name()
followed by print("Ok, bye!")
How can I return decorator functions with less lines of code?
Decorator syntax has entered the chat.
def hello(fn):
def inner_example():
print("Hello!")
fn()
print("Ok, bye!")
return inner_example
@hello
def name():
print("My name is Drew")
greet()
## Hello!
## My name is Drew
## Ok, bye!
By using this, we don't need to set greet = hello(name)
File I/O (Input and Output)
Section Table of contents
- File I/O (Input and Output)
- Section Table of contents
- How do we read in?
- So what about inputs from a file? Can Python read files?
- What are the modes I can use?
- What does an example of file opening and reading look like?
- Why does a subsequent read() return an empty string?
- So how do we move the cursor?
- How do you close a file in Python?
- What is a
with
block? - How do we write to a text file?
Since Javascript doesn't have a direct method for accessing files and manipulating them (you can use node and deno to do this but it's not core to the language), so it's an important distinction between the two languages and needs some focus.
How do we read in?
Python provides two built-in functions to read a line of text from standard input, which by default comes from the keyboard. The simplest way to produce output is using the print statement where you can pass zero or more expressions separated by commas.
These functions are โ
raw_input()
- The raw_input([prompt]) function reads one line from standard input and returns it as a string (removing the trailing newline).input()
- The input([prompt]) function is equivalent to raw_input, except that it assumes the input is a valid Python expression and returns the evaluated result to you.
So what about inputs from a file? Can Python read files?
That's a great question with a ton of information to consume, I'll try to break it down but the answer is simple, yes Python can and it's with a simple built in function...
open()
- up until now, you have been reading and writing to the standard input and output but with this function we can open a file. At a minimum, you must state the file name.file object = open(file_name, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
file_name
โ The file_name argument is a string value that contains the name of the file that you want to access.MARKDOWN_HASH6597e98f9fdc6ab6b87187b88957b87eMARKDOWNHASH
โ If the buffering value is set to 0, no buffering takes place. If the buffering value is 1, line buffering is performed while accessing a file. If you specify the buffering value as an integer greater than 1, then buffering action is performed with the indicated buffer size. If negative, the buffer size is the system default(default behavior)._mode
โ The access_mode determines the mode in which the file has to be opened, i.e., read, write, append, etc. A complete list of possible values is given below in the table. This is optional parameter and the default file access mode is read (r).
What are the modes I can use?
Mode | Meaning |
---|---|
'r' | Default - open for reading, synonym of 'rt' |
't' | Default - text mode |
'w' | Open the file for writing, truncating the file first |
'x' | Open file for exclusive creation, failing if the file already exists |
'a' | Opens file for writing, appending to the end of the file if it exists |
'b' | Binary mode |
'+' | Opens a disk file for updating (read/write) |
'r+b' | Opens the file without truncation |
w+b | Opens the file and truncates the file to 0 bytes |
'r+' | Read and write to a file (writing based on cursor -will not create a file) |
What does an example of file opening and reading look like?
Example story.txt file:
This is very short story.
Example.py reading a file:
story_file = open("story.txt)
## Defaults to:
## <_io.TextIOWrapper name='story.txt' mode='r' encoding='UTF-8'>
story_file.read() # if not specified, the buffer = -1
## This is very short story.
story_file.read() ## ''
So why does it work the first read but the second it returns an empty string? We will get into the why in a moment!
Why does a subsequent read() return an empty string?
Python reads files by using a cursor - just like the one you see when you are typing and after python reads a file, it leaves the cursor at the end of the file so if you wanted to read it twice, you would have an empty string.
There is an open connection while your python code is running to that file so any updates to the file will also be accessible to your python code.
If we edit the story.txt file to have extra lines like this:
This is very short story.
It just got a little longer.
The end.
What will happen? Will the file update automatically and where will the cursor be?
At the end of the 1st example, the cursor was at the end of the first line. It's still there so if we ran story_file.read()
we would just get the 2nd two lines.
So how do we move the cursor?
seek()
method allows you to move the cursor. story_file.seek(0)
will move the cursor to the very beginning allowing the whole story to output. The number you pass as an argument is a character count.
If the file is super long, we can use story_file.readline()
and pass the line number which will move the cursor to that line.
Lastly, there is story_file.readlines()
which will preserve the lines and separate them in a list.
How do you close a file in Python?
You can close a file with the close method (close()
) - you cannot read the file until it is opened again.
You can check if a file is closed with file_name.closed
which will return a boolean with True == closed and False (obviously) == open.
What is a with
block?
a with block does basically the same thing as our previous example with regards to reading and opening a file. Let's look at an example comparing the two:
Original method example:
story_file = open("story.txt)
story_file.read()
story_file.close()
file.closed # True
with block syntax example:
with open('story.txt') as file:
file.read()
file.closed # True
The main benefit is that no matter what you do inside the with block, the file automatically closes when it's done which is helpful.
How do we write to a text file?
Regardless of whether a file exists or not, you still have to use the open function to write to a file. You will need to specify the 'w'
flag to specify that we are using the mode='w'
. You can then write to the file using the .write()
method. Focusing on the with syntax, that will look like this:
with open('~/Dev/some-other-directory/story_file2.txt', 'w') as file:
file.write('Being a writer is fun!\n') # \n is newline
When working with the 'w'
flag, if you were to write to the same file twice, it will continue writing where the cursor left off BUT if you were to run the with open(filepath, 'w') as file:
again and wrote to the file, you'd overwrite the entire contents of the file.
If the file didn't exist before running it with that 'w'
flag then it will be created. To avoid this, you can pass the a
to append the file's contents.
Drew is a seasoned DevOps Engineer with a rich background that spans multiple industries and technologies. With foundational training as a Nuclear Engineer in the US Navy, Drew brings a meticulous approach to operational efficiency and reliability. His expertise lies in cloud migration strategies, CI/CD automation, and Kubernetes orchestration. Known for a keen focus on facts and correctness, Drew is proficient in a range of programming languages including Bash and JavaScript. His diverse experiences, from serving in the military to working in the corporate world, have equipped him with a comprehensive worldview and a knack for creative problem-solving. Drew advocates for streamlined, fact-based approaches in both code and business, making him a reliable authority in the tech industry.