Session 2 : Setup & Python basics

In this session we will make sure that everyone can run Python on their devices and then do a quite fast-paced run-through over the code pieces below, to explain the basic Python (and programming) concepts.

As this might be a lot in a very short amount of time for people who are new not only to Python but to coding in general, please also take at the Python Bascis resources on our References page. Especially the w3schools Python Tutorial might be a good first starting point, if you are still puzzled about some of the concepts after our quick run-through.

There are three recordings in which I talk you through the following code snippets (and the setup initially, with some remarks about code editors):

Setup

If you already have Python set up and also have an editor/IDE you like to work with, then you are ready to go. If not, the easiest way to start ist to install Thonny, which is a beginner friendly IDE (itself written in Python).

Thonny was developed by the University of Tartu specifically for the context of teaching and learning Python. Thonny is not only an editor/IDE, it also brings a full Python 3 installation with it, as well as a version of pip - the package installer for Python. So with Thonny you have everything you need to get started, and we will use this as a reference tool throughout the course.

Python basics crash course I

Here’s the code we’ll run through and work in this session:

basic.py

'''
This is a multi-line comment at the beginning of this Python
script. Its aim is to introduce you to the most basic concepts
in Python. We'll walk through this live in the course. If you
look at this in advance and everything here makes perfect sense
to you, and you could recreate it yourself from scratch, feel
free to skip the first hour of our Setup & Python basics session.
'''

# also a comment, only a single line comment
# althought it is followed by just another one
# no machine code will be executed up to (down) here

# but now, let's define some variables
my_boolean = True
my_boolean = False  # well, now we've overwritten the content
my_boolean = 'Not a boolean at all, but a string now!'
my_boolean = True or False  # ahm ... what's that?

# let's check and print the content to the console
print(my_boolean)

print('How can we explain that?')
my_explanation = 'Well, True or False is always ' + str(my_boolean)
print(my_explanation)

# combine printing and evaluation
print('But True and False is always', True and False)

# Let's get some user input
print()  # do an empty line first
user_name = input('Hey! What\'s your name? ')
print(f'Hi {user_name}, nice to talk to you.\n')  # using a format string and adding an empty line at the end


# before we can do more awesome stuff we need some better ideas
# of what types we can use here
my_string1 = 'Well, we already know this one'
my_string2 = "Double-quotes are also fine"
my_string3 = ''
my_string4 = 'The last one was an empty string. Still a string!'

my_multiline_string = '''This string starts here,
but spans several lines.
Quite convenient.'''

my_tedious_multiline_string = 'This string starts here,\n'
my_tedious_multiline_string += 'but spans several lines.\n'
my_tedious_multiline_string += 'Quite inconvenient doing it this way.'

print(my_multiline_string)
print(my_tedious_multiline_string, '\n')

print('So' + 'yes,' + 'strings' + 'can' + 'be' + 'concatenated!')  # whats up with the spaces?

# ok, we got strings, what about numbers and calculations?
my_int = 42
my_float = 42.0000000000001
my_float2 = 42.0
print(f'The type of {my_int} is {type(my_int)}.')
print(f'The type of {my_float2} is {type(my_float2)}.')

# let's do some calculations
print(5 * (12-8) + -15)
print(98 + (59872 / (13*8)) * -51)
print(72 % 8)  # this is the modulo operation
print(73 % 8)  # it returns the remainder of a division

# we can even "multiply" strings
print('The essence is ' + 'bla' * 3)

# now, comparing things is a very boolean thing to do
print('2 == 2? ', 2 == 2)
print('2 == 3? ', 2 == 3)
print('2 < 3? ', 2 < 3)
print('2 <= 2? ', 2 <= 2)
print('42 > 0? ', 42 > 0)
print('"lala" == "lala"', "lala" == "lala")

# comparing can be fun, IF you can do something with it
user_guess = input(f'Hey {user_name}, give me a number: ')
if user_guess == '42':
    print('Awesome, it seems there is nothing else left to lear for you')

user_guess = input(f'Gimme another one: ')
if user_guess == '42':
    print('Sneaky you, you are really intent on being stuck here, are you?')
else:
    print('Sorry, your number is just wrong!')

user_guess = input(f'Only one more: ')
if user_guess == '42':
    print('This is getting boring: ')
elif user_name == 'jackie':
    print(f'Well {user_name}, whatever you say seems to be the right thing.')
else:
    print('Not it! Well, maybe another time')

# so here we actually compared strings, not really numbers (as in int)
# but as we already have 100 lines of code here, let's try it out before we continue with basic2.py

As a file: snippets/basic.py

basic2.py

# as we are getting into error handling now, let's define a DEMO var
DEMO = True

try:
    print(23 + '23')
except Exception as err:
    if DEMO:
        print("Ugh, there was an error. But never mind, we'll just continue")
    else:
        raise err

print(str(23) + '23')
print(23 + int(23))

# Ok, so type conversion is an important thing. Let's try that with our
# number guesser
guess = input('Hey user, gimme a number: ')
# You might get an error here, depending on your input
try:
    if int(guess) == 42:
        print('Correct!')
    else:
        print('Not it!')
except:
    print("Ugh, there was an error. But never mind, we'll just continue")

# Errors sometimes seem ugly and annoying,
# but really, don't be a snob, they can be your friends
# Turn off the DEMO mode and see what you get.
# Try to fix the code one way or another.

# Now which of the following produce an error?
try:
    print(12 + 12)
    print('12' + '12')
    print('12' + 12)
    print('12 + 12')
    print(2 * 5)
    print('2' * '5')
    print('2' * 5)
    print('2 * 5')
except:
    if DEMO:
        print("Ugh, there was an error. But never mind, we'll just continue")
    else:
        raise err

# we've already seen type conversion, here some more examples:
variable_1 = 12
variable_2 = '12'
str(variable_1)
int(variable_2)
float(variable_2)

# now we can actually check the user input more properly
guess = input('Hey user, gimme a number again: ')
try:
    guess = int(guess)
except:
    print("Come on, why can't you give me a number?")
else:
    if guess > 10000:
        print("That's quite a large number")
    else:
        print('Nothing special about this number')
# This does not handle ALL numbers. Can you fix it?

print('\nAnd now for something completely different!\n')
print('A side note on string formatting:')

name = 'jackie'
day = 'Thursday'

# simple string concatenation, as we already know it
formatted = 'Hello ' + name + ', what a ' + day + '!'
print(formatted)

# the old style - good to know but please don't use it
formatted = 'Hello %s, what a %s!' % (name, day)
print(formatted)

# the new style
formatted = 'Hello {}, what a {}!'.format(name, day)
print(formatted)

# f-strings : the best, since Python 3.6
formatted = f'Hello {name}, what a {day}!'
print(formatted)

# Still, everything is so boringly determined here. Let's add some randomness
# and use some standard library features
from random import randint
from datetime import datetime

number = randint(0, 5)
now = datetime.now()
weekday = now.weekday()

print('Today, right now, this moment is', now.strftime('%A, %Y-%m-%d %H:%M')) 
if abs(weekday - number) == 0:
    print('Wow! This is a perfect day!')
elif abs(weekday - number) <= 2:
    print('A day as every other.')
else:
    print('This day really sucks!')
  
# check out https://www.w3schools.com/python/python_datetime.asp
# for more things you can do with dates

# enough for now. try to get this script running. play around with it.
# in DEMO and outside DEMO mode. fix the errors. and then ready yourself
# for part 3

As a file: snippets/basic2.py

basic3.py

# before we venture into machine land, we really should talk about
# lists, dicts, loops and functions

item = True
my_list = ['contains', 5, 'different', 'items like', item]
my_tuple = ('contains', 4, 'immutable', 'things')
my_list_from_tuple = list(my_tuple) + ['now mutable!']  # lists can be concatenated too
print(my_list_from_tuple, len(my_list_from_tuple))
# let's correct the number of items then
my_list_from_tuple[1] = len(my_list_from_tuple)
print(my_list_from_tuple)

# lists are indexed starting with 0. and they can be sliced
print(my_list[2:4])
print(my_list[2:])
print(my_list[:3])
print(my_list[1:2])  # isn't this a bit silly, as we could just use my_list[1] then?
print(my_list[1])    # hm ... see the difference?

# lists can be extended
print('extending my_list')
my_list.append('something')
my_list.extend([1, 2, 3])
my_list.insert(2, '(number is actually incorrect)')
print(my_list)

# and we can update single or multiple items
print('updating my_list')
my_list[1] = len(my_list)  # we've already seen this above
my_list[2:5] = ['(now correct)', 'very different', 'items']
my_list[7:] = [42, 10]  # this replaces part of the list with another (shorter) list
print(my_list)

# and we can also specifically delete items
print('deleting from my_list')
my_list.remove(10)
popped_item = my_list.pop(4)
print(f'popped_item: {popped_item} ; the list now looks like: {my_list}')
del my_list[1]
print(my_list)
my_list.clear()
print(my_list)
#del my_list
print(my_list)  # well, this should throw an error, becaus the list is gone now
# so remove the last line, before you move on to explore dictionaries
# and take a look at those many other aweseom list methods:
# https://www.w3schools.com/python/python_lists_methods.asp


my_dict = {'name': 'jackie', 'xp': 42, 'zombie': True}  # after such a speed run, what did you expect?
print(my_dict)
print(my_dict['name'])

# dicts contain key:value pairs. the values can also be dicts
my_dict = {
    'name': 'jackie',
    'data': {
        'xp': 42,
        'zombie': True,  # machine braaaaaains!
    },
}
print(my_dict)
print(my_dict['data'])
print(type(my_dict['data']))
print(my_dict['data']['zombie'])
print(my_dict.get('name'))  # a different way to access 
print(my_dict.get('something'))  # because my_dict['something'] would through an error

print('\nsome more ways to access dict keys and values:')
print(my_dict.values())
print(my_dict.keys())
print(my_dict.items())

print('\nadding and changing dict items')
my_dict['name'] = 'mafalda'
my_dict['data']['zombie'] = False
my_dict['a_new_key'] = 'a new value'  # adding something is easy as that
print(my_dict)
# but we can update (change/add) several key-value-pairs at once too
my_dict.update({'name': None, 'data': 'useless', 'hidden_gem': True})
print(my_dict)

print('\ndeleting works similar to lists')
popped_item = my_dict.pop('a_new_key')
print(f'popped_item: {popped_item} ; the dict now looks like: {my_dict}')
del my_dict['hidden_gem']
print(my_dict)
my_dict.clear()
print(my_dict)
#del my_dict
print(my_dict)
# well, this is same as with lists, same as with everything actually.
# if you delete it, it's gone. so fix this before you continue.
# also check out all of those dictionary methods:
# https://www.w3schools.com/python/python_dictionaries_methods.asp

print('\nOk, now, finally it is time to do some looping')
print("We'll loop through lists and dicts just for the fun of it")

my_list = ['contains', 5, 'different', 'items', True, 0.0, 1.234, False, None, {}, [], '']
for item in my_list:
    print('We now can do stuff with', item)
    if type(item) == str:
        print(f'This item is a string and of {len(item)} length.\n')
    elif type(item) == int:
        print('This item is an int:', item, '\n')
    else:
        output = 'This item appears to be something else.'
        if item:
            output += ' It looks like to be a truthy one.'
        else:
            output += ' Totally falsy of course.'
        print(output + '\n')
# here our loop ends

print('Looping through dicts works quite similarly')
my_dict = {'name': 'jackie', 'xp': 42, 'zombie': True, 'data': {'some': 'thing'}}
for key in my_dict:
    print('Currently at key', key, 'which has the value', my_dict[key])
# but sometimes it is more convenient to get the key and value as separate variables in the loop
for key, value in my_dict.items():
    print(f'In this loop we can access {key} and directly get {value}.')
    if type(value) == dict:
        print('A dict in a dict?!? Are you nuts? I wont look at this any further.')
    else:
        print('Boring')

# and because those loops actually work with all iterables we can also do this
for n in range(23):
    print(n)
else:
    print('imagine all the possibilities!')  # whait, what?!?
    # yep, that's a thing too, you can use an else after a for loop
    # look it up: https://www.w3schools.com/python/python_for_loops.asp


print('''

You've made it to the end!
I think this is enough for today.
Get some fresh air.
Take a deep breath.
Think about happy things.
Try not to become a robot until next Thursday.
Then we collect the missing pieces to become ... ah, create universal discrete state machines.
''')
from time import sleep
sleep(4)
print('\n\nOh...')
sleep(3)
print('by the way,')
sleep(3)
print('did you know this?\n')
sleep(2)
import this

As a file: snippets/basic3.py