<style>
.present {
text-align: left;
}
</style>
# Python Data Types & Basic Control Flow
## Week 17 Day 2
---
## Lecture videos 1 (20 min)
Watch:
- Python Basics (7:06)
- Number Types (9:00)
---
### `print()`
We can use `print` to write messages to the console terminal
```python=
print("Hello world")
```
Equivalent to `console.log` in JavaScript
```javascript=
console.log("Hello world")
```
---
### Commenting code
In Python, comments start with `#`
```python=
# this is a comment
print("Hello") # can also start in line
```
Just like the `//` in JavaScript
```javascript=
// this is a comment
console.log("Hello world") // can also start in line
```
---
### Commenting code
Longer comment blocks can use the `"""` syntax
```python=
"""
You can use three quotes in a row
for multiline comments
"""
```
Like in JavaScript, where `/* ... */` creates multiline comments
```javascript=
/*
longer comment
more commenting here
*/
```
---
### Number Data Types
We'll mostly interact with `int` and `float` types
- `int` (integers): counting numbers with no decimal points
- `float` (floating point numbers): numbers with decimal places.
- They may occasionally have rounding errors, just like JavaScript
- see [documentation on floating point arithmetic](https://docs.python.org/3/tutorial/floatingpoint.html)
- `complex`: complex numbers
---
| Operator | Meaning | Example |
|:--------:|:---------------- |:--------------------- |
| `+` | addition | `print(10+4) # 14` |
| `-` | subtraction | `print(10-4) # 6` |
| `*` | multiplication | `print(10*4) # 40` |
| `/` | division | `print(10/4) # 2.25` |
| `%` | modulo | `print(10%4) # 2` |
| `**` | exponent | `print(10**4) # 10000`|
| `//` | integer division | `print(10//4) # 2` |
---
### Number Operations
- Plus operator (`+`) can be used for both numeric addition and string concatenation
- But type conversion between strings and numbers won't happen automatically (unlike JavaScript)
```python=
print("hello " + "world") # "hello world"
print("hello " + 7) # TypeError
# explicitly convert types
print("hello" + str(7)) # "hello7"
```
---
## Exercises 1 (35 minutes)
- Hello, Eggs and Spam (5:00)
- Plus, Minus, More (5:00)
- Fun With Functions (5:00)
- Adding Two Numbers (1:00)
- Convert Minutes To Seconds (1:00)
- Livestock Legs (5:00)
- Return Next Number (1:00)
- Remainder Of Two Numbers (1:00)
- String To Integer (5:00)
- By The Power Of... (1:00)
---
## Lecture videos 2 (25 min)
Watch:
- Simple Formatted Strings (10:19)
- Duck Typing (7:26)
- Arithmetic With Strings (3:36)
---
### String Data Type
- Strings use single quotes (`'`) or double quotes (`"`)
- Using three quotes in a row (either `"""` or `'''`) will open a multiline string
```python=
my_long_string = '''
you can make
longer strings over multiple lines
individual quote characters ' " won't end the string
'''
```
---
### String Interpolation
String formatting with `%` operator
```python=
word = "hi"
num = 6
print("%s is a word. %i is an integer" % (word, num))
# prints "hi is a word. 6 is an integer"
```
---
### String Interpolation
String formatting with `.format()` method (better)
```python=
word = "hi"
num = 6
print("{stuff} and {number}".format(stuff=word, number=num))
# prints "hi and 6"
# positional
print("{1} is a value, so is {0}".format(word, num))
```
---
### String Interpolation
String formatting with `f` strings (best):
```python=
word = "hi"
num = 6
print(f"{word} and {num}")
```
Most similar to interpolated strings in JavaScript:
```javascript=
let word = "hi"
let num = 6
console.log(`${word} and ${num}`)
```
---
### String Arithmetic
```python=
a = "a"
b = "b"
an = "an"
print(b + an)
print(b + a*7)
print(b + an*2 + a)
print("$1" + ",000"*3)
```
---
### String indexing
- Use square brackets (`[]`)
- Index starts at 0 (like in JavaScript)
```python=
print("Spaghetti"[0]) # S
print("Spaghetti"[4]) # h
```
- Can use a negative index
```python=
print("Spaghetti"[-1])
print("Spaghetti"[-4])
```
---
### String indexing
Indexing with ranges: the start value is inclusive, the end value is skipped
```python=
# indexing with ranges
print("Spaghetti"[1:4]) # pag
print("Spaghetti"[4:-1]) # hett
print("Spaghetti"[4:4]) # (empty string)
print("Spaghetti"[:4]) # Spag
print("Spaghetti"[:-1]) # Spaghett
print("Spaghetti"[1:]) # paghetti
print("Spaghetti"[-4:]) # etti
```
---
### String indexing
Out of range values will through errors if you try to access the single value, but they are valid as part of a range.
```python=
print("Spaghetti"[15]) # IndexError: string index out of range
print("Spaghetti"[-15]) # IndexError: string index out of range
print("Spaghetti"[:15]) # Spaghetti
print("Spaghetti"[15:]) # (empty string)
print("Spaghetti"[-15:]) # Spaghetti
print("Spaghetti"[:-15]) # (empty string)
print("Spaghetti"[15:20]) # (empty string)
```
---
### String methods: `.index()`
Returns the first index where the substring is found
```python=
print("kiwi".index("k")) # 0
print("kiwi".index("m")) # ValueError: substring not found
```
---
### String methods: `.count()`
Returns the number of times the substring is found
```python=
print("kiwi".count("k")) # 1
print("kiwi".count("i")) # 2
print("kiwi".count("m")) # 0
```
---
### String methods: `.split()`
Returns a list (array) of substrings, split on the character (or substring) passed
- If no character is passed, a space is used to split
```python=
print("Hello World".split()) # ["Hello", "World"]
print("Hello World".split(" ")) # ["Hello", "World"]
print("i-am-a-dog".split("-")) # ["i", "am", "a", "dog"]
```
---
### String methods: `.join()`
Use a given string to join all the substrings from the list argument
- Works in reverse from what you may be used to with JavaScript
```python=
print(" ".join(["Hello", "World"])) # "Hello World"
# ["Hello", "World"].join(" ") JavaScript
print("-".join(["i", "am", "a", "dog"])) # "i-am-a-dog"
```
---
### String methods: `.upper()` & `.lower()`
Transform a string to the specified case
- these functions do not mutate the value of the string
```python=
a = 'Hello'
print(a) # 'Hello'
print(a.upper()) # 'HELLO'
print(a) # 'Hello'
```
---
### Duck Typing?
From the video - "better to ask forgiveness than permission"
- this is a pythonic principle---a fundamental part of control flow in python
- but it's not actually Duck Typing
- Duck Typing won't really come into play until we're creating our own classes
- We'll talk more on Thursday, once we've introduced classes
---
### Control flow with `try/except` blocks
Keywords:
- `try`: run this code until an exception occurs
- `except`: run this code when an exception occurs
- `else`: run this code only if no exception occurs
- `finally`: run this code no matter what
---
### Control flow with `try/except` blocks
```python=
num = 0
try:
print("Trying now...")
print(4/num)
except ZeroDivisionError:
print("oops i tried to divide by zero!")
finally:
print("this happens no matter what")
```
---
### Control flow with `try/except` blocks
Avoid using a bare `except`— you should specify the type of error in almost every case.
A "bare `except`" can be dangerous...
```python=
while True:
try:
num = int(input("say a number "))
print(num)
break
except ValueError:
print("try again")
```
---
## Exercises 2 (15 min)
- Fun With Strings (5:00)
- Burrrrrp (5:00)
- Concatenate Names (1:00)
---
## Lecture Videos 3 (12 min)
Watch
- Assignment Operators (9:17)
---
### Assignment operators
We can use assignment operators (like in JavaScript) to concisely update values
```python=
a = 2
a += 3
print(a) # 5
a *= 2
print(a) # 10
```
But no more `++` or `--`
```python=
a++ # SyntaxError: invalid syntax
```
---
## Lecture Videos 4 (30 minutes)
Watch:
- The Meaning of Truth (13:22)
- Identity vs. Equality Demo (10:50)
---
### Truthiness in Python
Falsey values in Python:
- 0 (for any number type)
- `0`, `0.0`, `0j`
- any empty collection
- `""`, `[]`, `set()`, `{}`, `range(0)`
- `False`
- `None`
Truthy values in Python:
- anything not listed above
---
### Logic Operators
We use the keywords `and`, `or`, and `not` in Python instead of `&&`, `||`, and `!`
```python=
print(True and False) # False
print(True or False) # True
print(True and not False) # True
```
---
### Logical operators
Parentheses can group our conditions, just like JavaScript
```python=
print(False and (True or True)) # False
print((False and True) or True) # True
```
---
### Short circuiting
If we can already determine the overall outcome of a conditional, Python won't bother evaluating the rest of the statement.
(JavaScript also has short-circuiting)
```python=
False and print("not printed") # does not print
False or print("printed #1") # prints "printed #1"
True and print("printed #2") # prints "printed #2"
True or print("not printed") # does not print
```
---
### While loops
While loops follow a very similar structure to JavaScript.
```python=
i = 0
while i < 5:
print(f"{i}. Hello, world.")
i += 1
print("You've printed 5 times. Goodbye.")
```
---
### Loop keywords: `continue` and `break`
- `continue`: goes to the next iteration of the loop
- `break`: exits out of the loop completely
```python=
i = 0
while True:
print(f"{i}. Hello, world.")
if i < 4:
i += 1
continue
print("You've printed 5 times. Goodbye.")
break
```
---
### Identity vs. Equality
- in JavaScript: `==` is bad, `===` is good
- in Python: `is` and `==` are both useful, just for different things
- Equality is not about typechecking, it's just about whether the values are the same
```python=
my_int = 4
my_float = 4.0
# check if the values are the same
print(my_int == my_float) # True
# check if the values are the same and check type
print(my_int == my_float and isinstance(my_int, float)) # False
```
---
### When to use `==` (equality):
- Most of the time!
- Whenever you are comparing two values to see if they are the same
- strings, numbers, lists, dictionaries, etc
```javascript=
// javascript version
console.log({ gorilla: "large" } === { gorilla: "large" })
// false
```
```python=
# python version
print({"gorilla": "large"} == {"gorilla": "large"})
# True
```
---
### When to use `is` (identity) [1/3]:
1. For checking if a value is not `None`
```python=
a = []
if a:
print("a is truthy")
else:
print("a is falsey") # prints "a is falsey"
if a is not None:
print("a is not None") # prints "a is not None"
else:
print("a is None")
```
---
### When to use `is` (identity) [2/3]:
2. For checking is `True` / `False`
```python=
a = 1
print(a == True) # don't do this
print(a is True)
```
---
### When to use `is` (identity) [3/3]:
3. For checking whether two objects are the same object
```python=
print([] == []) # True
print([] is []) # False
a = []
b = a
print(a is b) # True
b.append(5)
print(a) # [5]
```
---
### What is the "identity"
`id()` returns the “identity” of an object.
- Integer which is guaranteed to be unique and constant for this object during its lifetime (i.e. while the program is running)
```python=
print(id(None)) # 4315260920
print(id(None)) # 4315260920
a = None
print(id(a)) # 4315260920
```
---
## Practices 4 (40 min)
- Double That Penny (5:00)
- Numeric Equality (1:00)
- Using and (1:00)
- Split On Capitals (10:00)
- Count Characters In String (5:00)
- Factorial (5:00)
- Is Divisible By 5 (1:00)
- Is The Last Character N? (5:00)
- Same Number Of Characters? (1:00)
---
## Lecture Videos 5 (14 min)
Watch:
- Functions in Python (8:28)
- Functions Returning Functions (2:00)
---
### Python Functions
- We use the `def` keyword to define a function followed by:
- The name of the function
- The arguments that it accepts
- A new block identified as `:` and indent the next line
```python=
def is_even(num):
return num % 2 == 0
print(is_even(5)) # False
print(is_even(2)) # True
```
---
### Python Scoping
- Scoping is done at the function level
- In JS, we had block scopes
- In PY, our `if` statements do not create new scopes
```python=
def make_a_five():
y = 5
return y
if True:
x = 10
print(x) #10
# `x` was created in the global scope
print(y) # NameError: name 'y' is not defined
# `y` was created in the scope of the make_a_five function
```
---
### Lambda Functions
- For simple one-line functions, we can also use a lambda, which takes in:
- Arguments on left side of `:`
- Returns the value resulting from the right side of the `:`
```python=
is_even = lambda num: num % 2 == 0
print(is_even(8)) # True
```
---
### PEP-8 Style Guidlines
- The use case of lambdas is when you are going to use a function once without assigning it
- Assigning a lambda to a variable essentially duplicates the purpose of the def keyword, hence it is not pythonic
---
### Functions Returning Functions
```python=
def order_pizza(pizza_type):
order = f"I would like a {pizza_type} pizza"
print(pizza_type)
return lambda topping_type: order + f" with {topping_type}."
sausage_pizza = order_pizza("sausage")
# prints from line 3: "sausage"
print(sausage_pizza("bell pepper"))
# "I would like a sausage pizza with bell pepper."
```
---
### Summary Practices (50 minutes)
- Valid Hex Code (10:00)
- First Before Second (10:00)
- Sequence of Numbers (30:00)
### Summary Quizzes (20 minutes)
- Python Documentation Quiz (5:00)
- Arithmetic Operators (5:00)
- Strings? (5:00)
- Short Circuit (5:00)