Second half of the course!

• I’m so tired. All the time. 10 solid months of teaching
• today will be kinda relaxed and playful
• if you’re curious about anything at any time, ask! I know a good bit about python
• turning our attention to the server side
• this week: learning another new language, python
• then learning about server-side page generation
• and then all the stuff about client-server communication
• so let’s GOOOOOOOOOO

Python

• What is it?
• Dynamically-typed language
• Started in 1989 by Guido Van Rossum
• Slowly gained users in the 90s
• Became much more popular after 2.0 in 2000
• Community split for stupid reasons with 3.0 in 2008
• If I had to pick a mainstream dynamic language to work in, it’d be Python
• 2 vs 3
• 3.0 came out 11 years ago but there are still people using 2
• 3 was a backwards-incompatible release - py2 code cannot be run in py3
• but mostly, 3 was sweeping away a lot of cruft, dumb decisions, and inconsistencies from 2
• all the practical reasons to avoid 3 have long since disappeared
• the ideological reasons to avoid 3 are… misguided at best?
• basically, these people don’t understand text encoding.
• 3 is the version everyone should be using from now on. I think 2020 is the EOL for py2
• what’s frustrating is that most google searches still rank py2 results above py3
• e.g. try googling python functools
• if you see the blue/teal docs, you’re in python 2 land
• switch to the 3.7 docs!
• REPLs
• the JS console in your browser inspector is an example
• but when you install python, you can run it from a shell
• and you get a REPL - “read-eval-print loop”
• an interactive programming console
• every line/block you type is executed immediately
• use help(whatever) for help on a lot of things - modules, functions, classes…
• it’s super useful for trying things out quickly, testing assumptions
• or even just when you need a calculator

Syntax

• Unlike most other languages, in Python, whitespace is significant
• in C-like syntaxes, blocks of code are delimited by { curly braces }
• in Python, blocks of code are indicated by indentation
• INDENTATION IS NOT JUST FOR FUN
• if you’re good/consistent with your indentation in another language…
• then you won’t have much trouble adjusting. just leave out the braces.
• but in python, indentation means something, and it must be consistent.
• you can use tabs or spaces…
• but never both.
• NEVER MIX TABS AND SPACES AT THE BEGINNING OF A LINE.
• this is a cardinal sin in most code styles and a syntax error in python.
• python’s style guide says to use 4 spaces.
• but I hate spaces so I use tabs.
• if you use spaces, all indents must be the same size (e.g. 3, 6, 9, 12, 15, etc.)
• once you get past the indentation thing, the syntax is not very unusual.
• instead of open braces, you put colons at the ends of lines.
• instead of closing braces, you put… nothing.
• instead of empty braces, you put the pass keyword.
# Thanks, Todd Waits
import random

# no need to declare variables.
r = random.randint(0, 100)

while r < 85: # no parentheses.
if r > 70:
print(r, ":  so close!", sep="")    # what's that sep=""?
elif r > 45:                            # elif??
print(r, end="")
print(":  Getting there...")
else:
print("{}:  Still so far away!".format(r))

r = random.randint(0, 100)

print("WE GOT OUT!")

# a function with no code.
def emptyFunction():
pass # 'pass' is like empty braces {}

""" Multi-line comments are delimited by triple-quotes.
This is kind of weird, because we'll see that we can also use
triple-quotes for strings... """


Control structures

• Python has some control structures we all know and love
• if-else
• if-elif-else
• why can’t they just make it if-else if-else like every other language? idk.
• half my syntax errors are typing else if instead of elif.
• while
• with break and continue which work as you’d expect
• try-except-finally instead of try-catch-finally but it works the same
• and raise instead of throw
• return
• though you can return multiple values (more on that later)
• there are no switches
• there’s been discussions about it for years
• but basically hitting all the right tradeoffs is hard
• so you’ll see if-elif-elif-else or a dict of functions or virtual methods instead
• Python has some other ones you may be less familiar with
• its for-in loop is similar to JS’s for-of loop, or Java’s for(:) loop
• there is no C-style for(i = 0; i < 10; i++) loop
• you would write for i in range(10): for that
• there is yield which is like a return but for generators
• and there is with which.. is neat and doesn’t have an equivalent in many other languages

Variables and types

• local variables do not need to be declared
• and sadly they are not block-scoped; they are function-scoped like JS’s var
• this means you can declare a variable inside a block and it will be available after
• global variables are used in a very weird way.
• we’ll come back to those with functions.
• they’re kind of “un-pythonic” anyway.
• Python is dynamically typed, so the types are associated with values, not variables…
• but it is much more strongly typed than JS
• 1 == "1" is False
• oh yeah, python capitalizes its boolean values and I have no idea why.
• furthermore, "x = " + 10 does not do string concatenation…
• it throws an error!
• you would have to use "x = " + str(10) in that case
• but again, not pythonic
• basic types and values
• type(x) gives you the type of x…
• as a type object, not a string. (basically, the value’s “class”)
• NoneType (None)
• kinda like null
• bool (True, False)
• capitalized…
• bool() is a function too, to convert things to bools
• int and float
• again, int() and float() are conversion functions, will also parse strings
• unlike many languages, int has no (practical) range limits
• try 10 ** 10 ** 3 (** is the power operator)
• also unlike many languages, dividing ints gives you a float
• try 5 / 3
• now try 5 // 3
• this is the flooring division operator
• try -5 // 3
• wuh-oh.
• guess what: quotients/remainders are not unique and different languages give different results!
• str
• this is the string type; it’s unicode!
• str() is a conversion function; kinda like toString() in other languages
• it’s immutable
• can use "double quotes" or 'single quotes', just like JS
• can also use """triple quotes""" - syntactically distinguished by appearing in expression position
• len(s) gives you the length
• very common method: .format()
• try "{} {}".format("hello", "world")
• uses similar formatting syntax to .net, some other languages

Lists

• python calls arrays “lists” and idk why.
• similar to JS’s - mutable length, any mix of types
• but you get out of bounds exceptions - IndexError (thank god)
• len(a) - length
• a.append(value) - appends the value
• a.remove(value) - finds and removes value
• a.pop() - removes and returns last value
• a.pop(n) - removes and returns nth value
• a.sort() - sorts a correctly unlike JS
• a.reverse() - gosh
• you can use + to concatenate lists
• you can use * to multiply them (????)
• try [0] * 10
• this is how you get a new list of a given length
• you can use them in for-in loops
• for val in [1, 2, 3, 4, 5]:
• indexing[n] can take positive or negative numbers
• negative numbers count from the end
• so a[-1] means the last item
• and a[-len(a)] means the first
• you can slice lists
• this is super super useful and powerful
• slicing always gives you a new list object
• a[2:5] gives you indexes 2, 3, 4 of the original array
• lower bound inclusive, upper bound exclusive
• a[:5] gives you the first 5 items
• a[2:] gives you items from 2 until the end
• a[-5:] gives you the last 5 items
• a[0 : 6 : 2] gives you every other item starting at 0 and ending at 6
• so you’d get 0, 2, and 4 in this case
• honestly I don’t use this “stride” version often, if ever…
• you can also slice strings with the same behaviors
• and many other list-like things!

Sets

• a lot of beginning tutorials don’t cover these but I think they’re super useful and I use them a lot
• you make them with {1, 2, 3} or with the set() constructor
• test membership with in
• s = {1, 2, 3, 4, 5}
• 3 in s gives True
• s.add(value) and s.remove(value)
• do what you expect
• can use len() and for-in on them
• really cool operations:
• | (union)
• & (intersection)
• - (difference: a - b gives set of things in a but not b)
• ^ (symmetric difference: a ^ b gives set of things unique to each set)

Dicts

• python’s map/hash type is called dict
• also uses curly braces, but with key-value pairs inside:
• d = {"x": 10, "y": 20}
• unlike JS, you can’t write d.x here… have to write d['x']
• cause these are not “objects” like in JS; they’re just maps.
• can set/add new things by indexing
• d[None] = 10
• can remove things with the weird del syntax
• del d['x']
• throws KeyError if the key doesn’t exist
• can test for key membership with in
• 'x' in d
• 'y' in d
• get keys/values with d.keys() and d.values()
• these are not lists but can be iterated
• you can get a list with e.g. list(d.keys())
• can iterate with for-in
• for k in d: gives you the keys
• but often you want the keys and the values
• for k, v in d.items(): does that.

Tuples

• like an immutable list/array
• python has some other immutable collections, like frozenset
• written as a list of items in parens, like (1, 2, 3)
• if you have 0 items, it’s ()
• and if you have 1 item, it’s (1,) - note the comma
• just like a list, you can use len and [] and use for-in
• but you can’t change the length or the items
• tuples are often used to return multiple values from functions
• they can be used transparently like return 1, 2, 3
• and then transparently again as x, y, z = func()
• this is called “unpacking” the tuple
• but you can get the tuple if you assign to one variable: t = func()
• however…
• tuples are not great for readability.
• you have to remember which index means what
• if you have more than 2 or 3 things in a tuple, a class might be a better choice
• or, you can use collections.namedtuple:
# from X import Y means "import the X module, and grab the Y name out of it"
# so I don't have to write collections.namedtuple, I can just write namedtuple
from collections import namedtuple

# like making a "Point" class with 2 fields, but way less typing, and it acts like a tuple
Point = namedtuple('Point', ['x', 'y'])

p = Point(10, 20) # uses class-like construction syntax
x, y = p          # can unpack it like a real tuple
print(p[0], p.x)  # can access fields by name or by index - same thing here

• I like these. really useful for tiny objects that just pack together some values.

Functions

• the def keyword defines functions: def func(x, y):
• not really anything weird about it
• you can call functions with positional arguments: func(10, 20)
• and you can use named arguments: func(y=20, x=10)
• this is so, so useful for code readability.
• many functions use named arguments for optional parameters
• for instance, print() has sep and end
• sep is what is printed between values - by default, a space
• end is what is printed after the values - by default, a newline
• so you can use print("hello ", end="") to print without a newline
• one really weird thing is how globals are accessed…
• to read global variables, you just use them.
• to write global variables, you must use this bizarre syntax.
counter = 0

def printCounter():
# can *read* counter just fine
print("counter is", counter)

def incCounter():
# ??!??!??!
# this doesn't make a global variable. this says
# "within this function, treat counter as a global."
global counter
# now when we access it, it won't make a local.
counter += 1