Python for Asshats

Chapter 2

This chapter introduces Python's fundamental built-in data structures. As with all great works, I recommend reading it once while sober, and once while tripping balls on LSD.

Digging up the Pre-Algebra trauma you buried in middle school

Programming deeply relies on structures called variables. Most people will remember this term from a mathematics class, and many respond to it with a slight shudder. Similarly to in math, they are a way of storing information as you manipulate it in your program. Variables in a lot of older programming languages are a clusterfuck of incomprehensible memory addresses and null pointers that make you want to move to the mountains, become a hermit, and never see a computer or another human soul ever again. This is why when the second coming of Christ, Guido van Rossum, created Python in 1991, he did away with all that. Creating and using a variable in Python is as simple as this:

Code:
x = 4  # write 4 to x
print(x)  # print the value of x
Output:
4

Variables can be given whatever name you see fit, as long as it includes only numbers, letters, and underscores. The name of the variable should describe what it represents, something along the lines of chapter_number or dicks_sucked. Spaces are not allowed. Absurdly long variable names, such as how_many_dicks_sucked_for_weed_today are allowed, but are generally considered bad practice, and get very annoying to type. For now, our variables represent nothing, so names such as x and y will be used for brevity.

There are a few words that Python reserves, which you cannot use as variable names:

True False class finally is return None continue for lambda try def from nonlocal while and del global not with as elif if or yield assert else import pass break except in raise

Each of these menacing keywords preforms an action, most of which I will explain later on. For now, keep in mind that they can't be used as names.

Whenever the interpeter encounters a valid name followed by an = sign, it writes the value after the equals sign into the variable. Every time it encounters the name of that variable again, it just replaces the variable's name with it's value. The following are equivalent:

Code:
x = 4  # write 4 to x
y = 5  # write 5 to y
print(x + y)  # print the value of x + y
Output:
9
Code:
print(4 + 5)  # print the value of 4 + 5
Output:
9

Being able to put a value in memory and then use it again is amazing, like keeping a little snack for later in your foreskin. However, this isn't very usefull, that's why we also have the ability to modify the variables as the program runs. Because the interpreter replaces variable's names with their current values, it is perfectly reasonable to use a variable's old value when assigning it a new one.

x = 4  # write 4 to x
print(x)  # print the value of x
x = x + 5  # read x, add 5 to it, and write the result to x
print(x)  # print the updated value of x
Output:
4
9

When the intrepter tries to assign a value to a variable that already has one, it just overrides what is already there. This allows you to chain operations ad nauseam.

Code:
x = 4  # write 4 to x
x = x + 5  # read x, add 5 to it, and write the result to x
x = x * 23 # read x, multiply by 23, and write the result to x
x = x / 3 # read x, divide by 3, and write the result to x
print(x)  # print the updated value of x
Output:
69.0

Nice.

Look at all the shit I can store

Programming has a lot of numbers, to be sure, but there are a lot of things that are notably not numbers.

For this reason, there are many types of data you can put into a variable. This chapter will list only the ones you will use most often.

Ints and Floats

These are your numbers. Your work so far has dealt almost entirely with integers, or ints. They are numbers without a decimal component. 1, 10, 420, what have you. When a number has decimals, like everyone's favorite 3.14159, it is considered a floating point number, or float. You can do all the standard arithmetic operations with numbers.

Code:
print(3 + 4)  # addition
print(3 - 4)  # subtraction
print(3 * 4)  # multiplication
print(3 / 4)  # division
print(3 ** 4)  # exponentiation (power)
Output:
7
-1
12
0.75
81

When evaluating multiple operations, the interpreter uses the order of operations you are all familiar with.

Code:
print(2 + 3 * 2)  # remember PEMDAS?
Output:
8

If part of the calculation needs to be done first, surround it with parentheses to keep things obedient.

Code:
print( (2 + 3) * 2)
Output:
10

You don't have to worry about mixing ints and floats; they're both numbers so they play nicely together. Any operation that includes a float will always return a float, so no information is lost.

Code:
print(2 + 4.9)  # the int is automatically converted to a float
Output:
6.9

Keep in mind that division of two ints returns a float because numbers tend not to divide cleanly.

Code:
print(3 / 4)  # the output is automatically converted to a float
Output:
0.75

Computers are lazy shits, so it will return a float regardless of whether or not the answer actually has a decimal component — a float ending in .0 is considered a float and not an integer, much to the dismay of many so many programmers.

Code:
print(6 / 3)  # still returns a float
Output:
2.0

Strings

Calling back to the majority of non-number things that I mentioned, strings are one of the most useful types of data in Python. They encode strings of text, and are indicated as any characters wrapped by quotes. You may use "double quotes" or 'single quotes' to create a string, they both work identically, the only important part is to be consistent. If you mix single and double quotes in a project, the Python Police will hunt you down and have you hanged. You can put a string into a variable just as you would with a number.

Code:
name = "dean kamen"  # write a string to name
print(name)  # print the value of name
Output:
dean kamen

Amazing. If you recall our first program, you may have noticed that words hello world were wrapped in quotes, indicating that the text inside is a string.

Look how much you've grown!
print("hello world")

This is critical to actually being able to output the text. If you recall, print outputs the value of whatever you put between the parentheses. If you try to run it without the quotes, it very quickly shits itself.

Code:
print(hello world)
Oh, fuck!

This happens because when the interpreter sees a series of letters and numbers, it assumes that is the name of a variable. It continues reading the line, sees a space, which is not valid in variable names, stops to yell at you and exits. Even without the space, it would still result in an unsightly error.

Code:
print(helloworld)
Output:
Traceback (most recent call last):
  File "/home/timgor/test.py", line 1, in <module>
    print(helloworld)
NameError: name 'helloworld' is not defined

This time, what the interpeter saw was a valid variable name, so it went to search for it in memory. You hadn't created a variable with the name helloworld, so it stops to yell at you and exits. This is a prime example of a computer doing exactly what you tell it to do and never what you fucking want it to. The important takeaway from this is that text always needs to be wrapped in quotes so the interpeter knows what to do with it.

Strings, or strs, have a limited set of operations you can preform on them, just like ints and floats. The main one is concatenation, indicated by a +. It simply combines strings into one by laying them end to end.

Code:
a = "wolf"
b = "girls"
c = a + b  # concatenate a and b
print(c)
Output:
wolfgirls

Awoo! Remember that concatenation does not add a space character, so you have to include that yourself if you want spaces between strings.

Code:
print("wolfgirls" + "are" + "cute")  # no spaces after words
print("wolfgirls " + "are " + "cute")  # note the spaces inside the strings
Output:
wolfgirlsarecute
wolfgirls are cute

Concatenation only works between strings, so be wary of that.

Code:
print("stroing" + 1)
Output:
Traceback (most recent call last):
  File "/home/timgor/test.py", line 1, in 
    print("stroing" + 1)
TypeError: must be str, not int

It is also important to recall that Python is interpreted line by line, so when the interpreter sees a newline in a string, it considers that the end of that line of code. Because the line of code ends before the quote is closed, it shits itself, yells at you, and exits.

Code:
print("To be, or gluten free, that is the question:
Whether 'tis nobler in the mind to suffer")
Get fucked!

You also run into problems if you want to have quotation marks in your string. When reading a string, the interpreter reads until it runs into an end quote. If your string includes a quote, it thinks the string is over, but there's still more string, so it shits itself, yells at you, and exits.

Code:
print("I'm not perfect. Okay? I don't "use air quotes correctly."")
Ah, shit!

This becomes a very big issue, considering text written by humans often contains things like newlines and quotes. This is where escape sequences come in. This is a set of a few sequences that start with a backslash \ and act as a special character. The important ones are these:

Sequence Character
\n New line
\t Tab
\' Single quote
\" Double quote
\\ Backslash

Because backslashes are used to start escape sequences, \\ is the escape sequence for a literal backslash. How delightfully meta!

Code:
print("To be, or gluten free, that is the question:\nWhether 'tis nobler in the mind to suffer")
print("I'm not perfect. Okay? I don't \"use air quotes correctly.\"")
Output:
To be, or gluten free, that is the question:
Whether 'tis nobler in the mind to suffer
I'm not perfect. Okay? I don't "use air quotes correctly."

This chapter has drawn on for a while, so feel free to take a cocaine break to keep your energy up if you need to, we still have a few more data types to cover.

Booleans

Booleans, or bools, are the simplest type of data in Python. They can equal one of two values, True and False (capitalization is necessary). Keep in mind that these are not the strings "True" and "False", there are no quotes here, these are some of those keywords I mentioned. There are 3 operations that can be done with booleans: and, or, and not.

not bool takes whatever you give it and negates it. True becomes False and False becomes True.

Code:
a = True
b = False
print(not a)
print(not b)
Output:
False
True

bool and bool equals true only if both the inputs are true.

print(True and True)
print(False and True)
print(True and False)
print(False and False)
Output:
True
False
False
False

bool or bool equals true if any inputs are true.

Code:
print(True or True)
print(False or True)
print(True or False)
print(False or False)
Output:
True
True
True
False

As with arithmetic, you can use parentheses to specify which order to preform boolean operations in.

x = (a or b) and (not (a and b))

Booleans are, in this state, pretty neat, but frankly, completely fucking useless. Storing True and False values is only useful when you know what is true or false. This is where the comparison operators come in. When the intrepreter reads a comparison operator, it compares the values to its left and right, and evaluates that to a boolean.

Operator Meaning
== Equal to
!= Not equal to
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equal to

The behaviors of these operators should be obvious from their names and any experience you may have had learning mathematics. Since the interpeter evaluates a comparison to a boolean, you can use the same logical operators that I explained earlier.

Code:
x = 10
print(x > 15 or x == 10)
Output:
True

I recommend that you try running that code using a few different integer values of x to see how the comparisons interact.

You can also mix types of numbers when comparing, a comparison between an int and a float such as 1.0 == 1 is True just as you'd expect.

The most common operator is equals, value == value. It simply tells you if the two values are equal. A common mistake among programmers of any experience level is accidentally using the assignment operator, which is a single equals sign =. If you remember above, this is what we use to store a value into a variable. Confusing the two is a mistake you will make a lot, and you will never fully grow out of it. It's the worst, I know. Just be wary of it.

Code:
a = 10
b = 10
c = 9
print(a == b)  # 10 does equal 10
print(a == c)  # 10 does not equal 9
Output:
True
False

Equals is so useful because it can be used to compare any data type, not just numbers. As long as the values are equal, it evaluates to True. Here are examples using the two non-numeric types we've learned:

Code:
print("things" == "things")
print("stuff" == "things")
print(False == False)
print(True == False)
Output:
True
False
True
False

Yuh.

A lot of beginners forget that strings are case sensitive, so "string of things" does not equal "String Of Things".

Lists

A very interesting type in Python is the list, as each list can hold many things. They are defined by putting all your values between brackets and seperating them with commas, in the form [value,value,value,...]. Lists are populated with any data types, so you can create a list of numbers like so:

favorite_nums = [420, 69, -1, 42, 7800]

Or a list of strings, like this:

favorite_words = ["some", "body", "once", "told", "me"]

Though it's generally advised against, you can mix types in a list:

favorite_shit = [83, "owo wuts this", False]  # try not to do!

You can even put other lists inside of lists:

favorite_lists = [[1,2,3], [2,3,4], [6,6,6]]

When you have a list, you can either print the whole list, or individually access the creamy values inside using access operators, list[index]. When the interpeter sees you access a value in the list, it treats it just like any variable. You can use it, modify it, print it, and any changes can be seen on the list itself.

Code:
favorite_nums = [420, 69, -1, 42, 7800]
print(favorite_nums)
print(favorite_nums[2])  # print value at position 2
favorite_nums[2] = 21  # modify value at position 2
print(favorite_nums)
Output:
[420, 69, -1, 42, 7800]
-1
[420, 69, 21, 42, 7800]

You may have noticed that, even though that code accessed element 2, it changed -1 to 21, which was the third element of the list. This results from some unintuitive conventions in programming, so let me clear things up: lists in Python and the vast majority of programming languages start counting at 0, so the first element has index [0], the second has index [1], and so on. You probably think that's pretty fucking stupid, but believe me, it makes sense. In ways that will become increasingly more evident in following chapters, this makes lists significantly less cumbersome to deal with. For now, just remember it as a minor inconvinence.

Python list indexes are just integers, so feel free to treat them as such.

Code:
# definitely foreshadowing
fibb = [1, 1, 2, 3, 5, 8]
i = 0
print(fibb[i])
i = i + 1
print(fibb[i])
i = i + 1
print(fibb[i])
i = i + 1
print(fibb[i])
i = i + 1
print(fibb[i])
i = i + 1
print(fibb[i])
Output:
1
1
2
3
5
8

Because i is an integer, we can increment it by 1, and print the ith value again.

Another wonderfully zany feauture of Python lists is the ability to slice them. Instead of specifying a single index, list[index], you specify two, list[start:stop]. If one index returns an item, what would a range?

Code:
fibb = [1, 1, 2, 3, 5, 8]
print(fibb[2:5])  # print slice
Output:
[2, 3, 5]

Holy fucking shit. You get the range of values. Slicing a lists gives you a sub-list of all the values between the two indexes. This sublist includes the value at the start index, but stops right before the ending index, this bit of jank is once again something you will be thankful for later on.

You can even write to slices, just as you can with variables and single list values. You can use lists longer or shorter than the slice, the length of the list will be adjusted dynamically.

Code:
fibb = [1, 1, 2, 3, 5, 8]
fibb[2:5] = [6,9]
print(fibb)
Output:
[1, 1, 6, 9, 8]

After wading through 20-odd pages of my bullshit, you know have five (5) whole data types at your disposal! The next chapter will hopefully a bit shorter, and cover some miscilaneous things like conversion between types.