DS2000 (Spring 2019, NCH) :: Lecture 1b

0. Administrivia

  1. Office hours for lecture/practicum changed, starting next week
  2. Due before Monday's lecture: first pre-class quiz (via Blackboard; feel free to use book/notes/Python)
  3. Due next Friday @ 9pm: first homework (submit via Blackboard)

1. Output

How can we tell Python to output to the screen a smiley face?

In [2]:
print(":)")
print(':)')
:)
:)

How about the number of states in the USA?

In [3]:
print(50)
50

How about the first 6 digits of $\pi$?

In [4]:
print(3.14159)
3.14159

So print is a function that takes as its argument a value to output (we will encounter many useful functions in this class!)

2. Data Types

Every value in Python has a type -- this matters because functions will be very picky about what kind of data they operate on!

We can tell the type of an element of data using the type function...

In [5]:
print(type(":)"))
<class 'str'>
In [6]:
print(type(50))
<class 'int'>
In [7]:
print(type(50.))
<class 'float'>
In [8]:
print(type(3.14159))
<class 'float'>
In [9]:
print(type("50"))
<class 'str'>
In [10]:
print(type("50.0"))
<class 'str'>

It's often useful to be able to convert between types...

In [11]:
print(len("50"))
# print(len(50)) # why doesn't this make sense?
2
In [12]:
print("50")
print(type("50"))
print(type(int("50")))
print(int("50"))
50
<class 'str'>
<class 'int'>
50
In [13]:
print("3.14159")
print(type("3.14159"))
print(type(float("3.14159")))
print(float("3.14159"))
3.14159
<class 'str'>
<class 'float'>
3.14159
In [14]:
print(3.14159)
print(type(3.14159))
print(type(int(3.14159)))
print(int(3.14159))
print(int(3.94159))
3.14159
<class 'float'>
<class 'int'>
3
3
In [15]:
print(3.14159)
print(type(3.14159))
print(type(str(3.14159)))
print(str(3.14159))
3.14159
<class 'float'>
<class 'str'>
3.14159

And here's one more type that we'll use a LOT in this class: a list, which is a sequence of values...

In [16]:
print([1, 2, 3])
print(len([1,2,3]))
print(type([1, 2, 3]))
[1, 2, 3]
3
<class 'list'>
In [17]:
print(["a", "b", "c"])
print(len(["a", "b", "c"]))
print(type(["a", "b", "c"]))
['a', 'b', 'c']
3
<class 'list'>

We can even have lists that contain lists - OMG!

In [18]:
print([1, "b", [3, 1, 4, 1, 5, 9]])
[1, 'b', [3, 1, 4, 1, 5, 9]]

Where do lists come from? We can create lists from other types via the list and split functions...

In [19]:
print(list("abc"))
['a', 'b', 'c']
In [20]:
# Challenge: how many digits are in the number 50?
print(len(list(str(50))))
print(len(str(50)))
2
2
In [21]:
print("programming is fun :)".split())
print("programming is fun :)".split(" "))
['programming', 'is', 'fun', ':)']
['programming', 'is', 'fun', ':)']

We can also join a list to re-form a string...

In [22]:
print(" ".join(['programming', 'is', 'fun', ':)']))
print("-".join(['I', "know", "a", "song", "that", "gets", "on", "everybody's", "nerves"]))
programming is fun :)
I-know-a-song-that-gets-on-everybody's-nerves

3. Operators

An operator is a special symbol or word that allows you to act upon values -- there are several in Python, but here are some basics...

In [23]:
print(1 + 2)
3
In [24]:
print(125 * 0.8)
100.0
In [25]:
print(50 / 7)
7.142857142857143
In [26]:
# integer division: 50 divide 7 is 7 remainder 1
print(50 // 7)
print(50 % 7)
7
1
In [27]:
print(17 ** 2)
print(17 * 17)
289
289

They don't only apply to numbers!

In [28]:
print("a" + "b")
ab
In [29]:
print("hi" * 7)
hihihihihihihi
In [30]:
print([1, 2, 3] * 3)
[1, 2, 3, 1, 2, 3, 1, 2, 3]
In [31]:
print(["howdy", "how"] + ["are", "you?"])
['howdy', 'how', 'are', 'you?']

We can access values inside lists and strings via the [] operator -- it's important to note that computer scientists, for good reason, start counting at 0...

In [32]:
print([1, 2, 3][0])
print([1, 2, 3][1])
print([1, 2, 3][2])
1
2
3
In [33]:
print([1, "abc", [3, 1, 4, 1, 5, 9]][0])
print([1, "abc", [3, 1, 4, 1, 5, 9]][1])
print([1, "abc", [3, 1, 4, 1, 5, 9]][1][0])
print([1, "abc", [3, 1, 4, 1, 5, 9]][1][1])
print([1, "abc", [3, 1, 4, 1, 5, 9]][1][2])
print([1, "abc", [3, 1, 4, 1, 5, 9]][2])
print([1, "abc", [3, 1, 4, 1, 5, 9]][2][0])
1
abc
a
b
c
[3, 1, 4, 1, 5, 9]
3

You can string together many operators... which introduces the question of operator precedence (like PEMDAS)!

Python has such an ordering (https://docs.python.org/3/reference/expressions.html#operator-precedence) and parenthases can be used for clarity or to overwrite such ordering.

In [34]:
print(125 * 0 + 0.8)
0.8
In [35]:
print(125 * (0 + 0.8))
100.0

An expression is a combination of values, variables, operators, and calls to functions. Expressions need to be evaluated. If you ask Python to print an expression, the interpreter evaluates the expression and displays the result.

In [36]:
# Challenge: produce a string that has as many !'s as there are strings in a list
print(len(["life", "liberty", "pursuit of happiness"]) * "!")
!!!

4. Variables

It can be quite useful to have a place to store information, such as when we want to reference it in multiple places...

In [37]:
print(", ".join(["life", "liberty", "pursuit of happiness"]) + len(["life", "liberty", "pursuit of happiness"]) * "!")
life, liberty, pursuit of happiness!!!

A variable provides you the ability store a value and then change it later -- think of it as a named container.

The following is an assingment: take the expression on the right, evaluate it, and store it in the variable on the left...

In [38]:
words = ["life", "liberty", "pursuit of happiness"]

And now we can write the previous expression much more succinctly: referencing a variable's name tells Python to retrieve its current value...

In [39]:
print(", ".join(words) + len(words) * "!")
life, liberty, pursuit of happiness!!!

And we are free to change the contents of the variable at any time...

In [40]:
words = ["a", "b", "c", "d"]
print(", ".join(words) + len(words) * "!")
a, b, c, d!!!!

Now we are starting to see the power of programming -- we can write instructions that don't depend on precisely the data we encounter!

Let's look at one more common use of variables...

In [41]:
counter = 0
print(counter)
0
In [42]:
counter = counter + 1
print(counter)
1

Follow the statement closely: the right-hand side said to get the current value of counter (0), add 1 (totaling 1), and store that result back into counter -- this pattern lets us count occurrences (e.g., how many tickets are sold), we'll come back to this later :)

FYI: A similar pattern is seen when creating/adding to a list (though the append function is used instead of an operator)...

In [43]:
mylist = [] # empty list
print(mylist)
mylist.append("first element") # similar to, but more efficient than: mylist = mylist + ['first element']
print(mylist)
mylist.append(2)
print(mylist)
[]
['first element']
['first element', 2]

5. Input

One of the most common uses of variables it to store input supplied by a user, such as via the input function...

In [44]:
user_name = input("Please enter your name: ")
print(user_name)
print(len(user_name))
Please enter your name: Nate
Nate
4

Importantly, the result of the input function is always a string... so consider figuring out months from years

In [45]:
num_years = input("Please enter number of years: ")
print(num_years * 12)
print(int(num_years) * 12)
Please enter number of years: 4
444444444444
48

6. Formatted Strings

Notice that in the prior examples we weren't being very nice to our user -- they had to guess what the number meant, as opposed to us making readable outputs.

Formatted strings allows us to provide a template and fill in values in particular parts of our string where we need to...

In the "template", a {} indicates a place to fill in a value...

In [46]:
out = "Your name, {}, has {} letter(s).".format(user_name, len(user_name))
print(out)
Your name, Nate, has 4 letter(s).
In [47]:
print("{} year(s) = {} months".format(num_years, int(num_years)*12))
4 year(s) = 48 months

There are many additional options that can go between the {}'s, here are a couple common ones:

In [48]:
big_num = 525600
print("{} (minutes in a year) is so much easier to read with group separation {:,d}".format(big_num, big_num))

print()

really_big_num = 6.02214076e23
print("How many moles in a guacamole? Avocado's number! ({:,d})".format(int(really_big_num)))
525600 (minutes in a year) is so much easier to read with group separation 525,600

How many moles in a guacamole? Avocado's number! (602,214,075,999,999,987,023,872)
In [49]:
small_num = 3.14159
print("{} rounded to two places is {:.2f}".format(small_num, small_num))
print("{} rounded to one place is {:.1f}".format(small_num, small_num))
print("{} rounded to zero places is {:.0f}".format(small_num, small_num))

print()

really_small_num = 6.626068e-34
print("What's the key to amazing abs? Constant planks! ({:.38f})".format(really_small_num))
print("What's the key to amazing abs? Constant planks! ({:.3g})".format(really_small_num))
3.14159 rounded to two places is 3.14
3.14159 rounded to one place is 3.1
3.14159 rounded to zero places is 3

What's the key to amazing abs? Constant planks! (0.00000000000000000000000000000000066261)
What's the key to amazing abs? Constant planks! (6.63e-34)

7. Putting It All Together

In [50]:
# Let's help the poor Americans understand distances :)

km_to_miles = 0.621371
decimal_places = 2

num_kms = float(input("Enter kilometers: "))

template = "{} km = {:.{}f} miles (rounded to {} decimal places)"
print(template.format(num_kms, num_kms*km_to_miles, decimal_places, decimal_places))
Enter kilometers: 5
5.0 km = 3.11 miles (rounded to 2 decimal places)