Merge branch 'master' of ssh://86thumbs.net:3022/waldek/python_course_doc
This commit is contained in:
commit
5b32090a1d
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,56 @@
|
|||
import random
|
||||
import string
|
||||
|
||||
|
||||
def load_file(filename):
|
||||
"""
|
||||
We load a file and make a list out of it. Note that the same function is
|
||||
used for both files (both adjectives and subjects). Functions should be
|
||||
made as generic as possible.
|
||||
|
||||
There IS a problem you can fix, some logins will have spaces in them. Try
|
||||
to remove them in this function!
|
||||
"""
|
||||
words = []
|
||||
with open(filename, "r") as fp:
|
||||
lines = fp.readlines()
|
||||
for line in lines:
|
||||
words.append(line.strip()) # what does strip() do, what does append() do? remember CTRL+Q!
|
||||
return words
|
||||
|
||||
|
||||
def generate_username():
|
||||
"""
|
||||
We'll generate a random pair of adjectives and subjects from two wordlists.
|
||||
You NEED to have both files in you python project for this to work! Note
|
||||
the capitalize method call to make it all prettier...
|
||||
"""
|
||||
adjectives = load_file("./adjectives.txt")
|
||||
subjects = load_file("./subjects.txt")
|
||||
adjective = random.choice(adjectives)
|
||||
subject = random.choice(subjects)
|
||||
username = adjective.capitalize() + subject.capitalize()
|
||||
return username
|
||||
|
||||
|
||||
def generate_password(length=10, complictated=True):
|
||||
"""
|
||||
We generate a password with default settings. You can overide these by
|
||||
changing the arguments in the function call.
|
||||
"""
|
||||
password = ""
|
||||
if complictated:
|
||||
chars = string.ascii_letters + string.digits + string.punctuation
|
||||
else:
|
||||
chars = string.ascii_letters
|
||||
for i in range(0, length):
|
||||
password += random.choice(chars)
|
||||
return password
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# let's do some testing!
|
||||
username_test = generate_username()
|
||||
print(username_test)
|
||||
password_test = generate_password()
|
||||
print(password_test)
|
|
@ -0,0 +1,61 @@
|
|||
import login_generator
|
||||
|
||||
|
||||
def prompt():
|
||||
"""
|
||||
We prompt but you KNOW how this works!
|
||||
"""
|
||||
response = ""
|
||||
while not response.isdigit():
|
||||
response = input("how many login pairs would you like to create?")
|
||||
return int(response)
|
||||
|
||||
|
||||
def how_long():
|
||||
"""
|
||||
And again... (we could combine both prompts, but how?)
|
||||
"""
|
||||
response = ""
|
||||
while not response.isdigit():
|
||||
response = input("how long should the password be?")
|
||||
return int(response)
|
||||
|
||||
|
||||
def complex_or_not():
|
||||
response = ""
|
||||
while response.lower() not in ["y", "n"]:
|
||||
response = input("you want complex passwords? (y/n)")
|
||||
if response.lower() == "y":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def create_login(length, complicated):
|
||||
"""
|
||||
We use our library to generate the username and password. The double return
|
||||
might look confusing but just look at the for loop in the generate_logins
|
||||
functions and you'll see how it unpacks...
|
||||
"""
|
||||
username = login_generator.generate_username()
|
||||
password = login_generator.generate_password(length, complicated)
|
||||
return username, password
|
||||
|
||||
|
||||
def generate_logins(number, length, complicated):
|
||||
"""
|
||||
Easy no? But what does the i do? Do we really need it's value?
|
||||
"""
|
||||
for i in range(0, number):
|
||||
username, password = create_login(length, complicated)
|
||||
print("username {}: {}".format(i, username))
|
||||
print("password {}: {}".format(i, password))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Here we go!
|
||||
number_of_logins = prompt()
|
||||
complicted = complex_or_not()
|
||||
length = how_long()
|
||||
generate_logins(number_of_logins, length, complicted)
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
Aardvark
|
||||
African elephant
|
||||
Albatross
|
||||
Alley cat
|
||||
Alligator
|
||||
Amphibian
|
||||
Ant
|
||||
Anteater
|
||||
Antelope
|
||||
Ape
|
||||
Armadillo
|
||||
Asian elephant
|
||||
Baboon
|
||||
Badger
|
||||
Bat
|
||||
Bear
|
||||
Beaver
|
||||
Beetle
|
||||
Billy goat
|
||||
Bison
|
||||
Boar
|
||||
Bobcat
|
||||
Bovine
|
||||
Bronco
|
||||
Buck
|
||||
Buffalo
|
||||
Bug
|
||||
Bull
|
||||
Bunny
|
||||
BunnyCalf
|
||||
Camel
|
||||
Canary
|
||||
Canine
|
||||
Caribou
|
||||
Cat
|
||||
Caterpillar
|
||||
Centipede
|
||||
Chanticleer
|
||||
Cheetah
|
||||
Chick
|
||||
Chimpanzee
|
||||
Chinchilla
|
||||
Chipmunk
|
||||
Clam
|
||||
Cockatiel
|
||||
Colt
|
||||
Condor
|
||||
Cougar
|
||||
Cow
|
||||
Coyote
|
||||
Crab
|
||||
Crane
|
||||
Creature
|
||||
Crocodile
|
||||
Crow
|
||||
Cub
|
||||
Cur
|
||||
Cygnet
|
||||
Deer
|
||||
Dingo
|
||||
Dodo
|
||||
Doe
|
||||
Dog
|
||||
Dolphin
|
||||
Donkey
|
||||
Dove
|
||||
Drake
|
||||
Duck
|
||||
Eagle
|
||||
Egret
|
||||
Elephant
|
||||
Elk
|
||||
Emu
|
||||
Ewe
|
||||
Falcon
|
||||
Fawn
|
||||
Feline
|
||||
Ferret
|
||||
Flamingo
|
||||
Flee
|
||||
Flies
|
||||
Foal
|
||||
Fowl
|
||||
Fox
|
||||
Frog
|
||||
Gander
|
||||
Gazelle
|
||||
Gelding
|
||||
Gerbil
|
||||
Gibbon
|
||||
Giraffe
|
||||
Goat
|
||||
Goose
|
||||
Gopher
|
||||
Gorilla
|
||||
Grizzly bear
|
||||
Guinea pig
|
||||
Hamster
|
||||
Hare
|
||||
Hawk
|
||||
Hedgehog
|
||||
Heifer
|
||||
Hippopotamus
|
||||
Horse
|
||||
Hound
|
||||
Hummingbird
|
||||
Hyena
|
||||
Ibis
|
||||
Iguana
|
||||
Jackal
|
||||
Jackrabbit
|
||||
Jaguar
|
||||
Javalina
|
||||
Jellyfish
|
||||
Jenny
|
||||
Joey
|
||||
Kangaroo
|
||||
Kid
|
||||
Kitten
|
||||
Kiwi
|
||||
Koala
|
||||
Komodo dragon
|
||||
Krill
|
||||
Lamb
|
||||
Lemming
|
||||
Lemur
|
||||
Leopard
|
||||
Lion
|
||||
Lioness
|
||||
Llama
|
||||
Lobster
|
||||
Lynx
|
||||
Macaw
|
||||
Manatee
|
||||
Marmoset
|
||||
Marmot
|
||||
Mink
|
||||
Minnow
|
||||
Mite
|
||||
Mockingbird
|
||||
Mole
|
||||
Mongoose
|
||||
Mongrel
|
||||
Monkey
|
||||
Moose
|
||||
Mouse
|
||||
Mule
|
||||
Mustang
|
||||
Mutt
|
||||
Nag
|
||||
Narwhale
|
||||
Newt
|
||||
Ocelot
|
||||
Octopus
|
||||
Opossum
|
||||
Orangutan
|
||||
Orca
|
||||
Osprey
|
||||
Ostrich
|
||||
Otter
|
||||
Owl
|
||||
Ox
|
||||
Pachyderm
|
||||
Panda
|
||||
Panther
|
||||
Parakeet
|
||||
Parrot
|
||||
Peacock
|
||||
Pelican
|
||||
Penguin
|
||||
Pheasant
|
||||
Pig
|
||||
Pigeon
|
||||
Piglet
|
||||
Platypus
|
||||
Pony
|
||||
Pooch
|
||||
Porcupine
|
||||
Porpoise
|
||||
Primate
|
||||
Puppy
|
||||
Pussycat
|
||||
Rabbit
|
||||
Raccoon
|
||||
Ram
|
||||
Rat
|
||||
Reptiles
|
||||
Rhinoceros
|
||||
Robin
|
||||
Rooster
|
||||
Salamander
|
||||
Sea lion
|
||||
Seagull
|
||||
Seal
|
||||
Sheep
|
||||
Sidewinder
|
||||
Skunk
|
||||
Sloth
|
||||
Snail
|
||||
Snake
|
||||
Songbird
|
||||
Sow
|
||||
Spider
|
||||
Squid
|
||||
Squirrel
|
||||
Stallion
|
||||
Steer
|
||||
Stork
|
||||
Stork
|
||||
Swan
|
||||
Tadpole
|
||||
Tapir
|
||||
Terrapin
|
||||
Thoroughbred
|
||||
Tiger
|
||||
Toad
|
||||
Tortoise
|
||||
Toucan
|
||||
Turkey
|
||||
Uakari
|
||||
Unicorn
|
||||
Vixen
|
||||
Vole
|
||||
Vulture
|
||||
Wallaby
|
||||
Walrus
|
||||
Warthog
|
||||
Wasp
|
||||
Weasel
|
||||
Whale
|
||||
Wildebeast
|
||||
Wolf
|
||||
Wombat
|
||||
Woodpecker
|
||||
Worm
|
||||
X-ray fish
|
||||
Yak
|
||||
Zebra
|
||||
|
|
@ -1072,67 +1072,815 @@ There are a couple of things you should definitely read up on.
|
|||
|
||||
# While loop
|
||||
|
||||
TODO guess the number exercise
|
||||
We started our python journey with fully linear code.
|
||||
Next we saw functions which are first **defined** and called afterwards.
|
||||
Now we'll have a look at **loops**.
|
||||
In python there are **two** types of loops, a **while** and a **for** loop.
|
||||
We'll start with the while loop which I see as a loop in *time*.
|
||||
The for loop is a loop in *space* but we'll get to that one later.
|
||||
|
||||
The concept of a while loop is pretty simple.
|
||||
Code **within** the loop will be executed as long as a **condition** is met.
|
||||
Consider the code below.
|
||||
|
||||
```python3
|
||||
import time
|
||||
|
||||
counter = 0
|
||||
print("before the loop, counter: {}".format(counter))
|
||||
|
||||
while counter <= 10:
|
||||
print("inside the loop, counter: {}".format(counter))
|
||||
counter += 1
|
||||
time.sleep(1)
|
||||
|
||||
print("after the loop, counter: {}".format(counter))
|
||||
```
|
||||
|
||||
Two *extra* things might look new to you here.
|
||||
First the `import time` and `time.sleep(1)`, can you tell me what it does?
|
||||
Next the `counter += 1` which is called [incrementing](https://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python).
|
||||
You'll find this feature in most languages.
|
||||
You can think of it's syntax as *counter equals itself plus 1*.
|
||||
The *1* can be any number you want though!
|
||||
|
||||
When learning the `while` [keyword](https://docs.python.org/3/reference/compound_stmts.html#the-while-statement) there is a *second* keyword you should learn.
|
||||
It comes in very handy when constructing [infinite loops](https://en.wikipedia.org/wiki/Infinite_loop).
|
||||
Consider the following code.
|
||||
|
||||
```python3
|
||||
import time
|
||||
|
||||
counter = 0
|
||||
print("before the loop, counter: {}".format(counter))
|
||||
|
||||
while True:
|
||||
print("inside the loop, counter: {}".format(counter))
|
||||
counter += 1
|
||||
time.sleep(1)
|
||||
|
||||
print("after the loop, counter: {}".format(counter))
|
||||
```
|
||||
|
||||
The `while True` condition is *always* `True` so the loop will **never** exit!
|
||||
This is what we call an infinite loop.
|
||||
The `break` keyword was added to the language so we can *break out* of a loop.
|
||||
The logic is as follows.
|
||||
|
||||
```python3
|
||||
import time
|
||||
|
||||
counter = 0
|
||||
print("before the loop, counter: {}".format(counter))
|
||||
|
||||
while True:
|
||||
print("inside the loop, counter: {}".format(counter))
|
||||
counter += 1
|
||||
if counter >= 10:
|
||||
print("I'll break now!")
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
print("after the loop, counter: {}".format(counter))
|
||||
```
|
||||
|
||||
Infinite loops are a cornerstone of modern programming.
|
||||
While they might look scary, don't overthink it, you'll get used to them very quickly.
|
||||
|
||||
⛑ **When testing out an infinite loop it's sometimes handy to insert a `time.sleep` in it to slow down the execution a bit so you can wrap your head around what's happening.**
|
||||
|
||||
🏃 Try it
|
||||
---
|
||||
|
||||
Go back to the Celsius to Farenheit converter and add a while loop to ensure the user put's in only numbers.
|
||||
|
||||
|
||||
# Coding challenge - Guess the number
|
||||
|
||||
Now that you know how to repeat code execution we can create our first game!
|
||||
Everybody knows the *guess the number* game.
|
||||
The computer chooses a *random* number and the user has to *guess* which number it is.
|
||||
At each try the computer will till you if the user's number is bigger or smaller *than* the one the computer has in mind.
|
||||
The flow of the game could be as follows.
|
||||
|
||||
```
|
||||
I have a number in mind...
|
||||
What's your guess? 50
|
||||
my number is bigger
|
||||
What's your guess? 80
|
||||
my number is smaller
|
||||
What's your guess? blabla
|
||||
that's not a number! try again...
|
||||
What's your guess? 76
|
||||
yes, that's right! you win!
|
||||
bye bye...
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Spoiler warning</summary>
|
||||
|
||||
```python3
|
||||
import random
|
||||
|
||||
|
||||
def ask_for_number():
|
||||
result = input("What's your guess? ")
|
||||
if result.isdigit():
|
||||
number = int(result)
|
||||
return number
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
number_to_guess = random.randint(0, 100)
|
||||
print("I have a number in mind...")
|
||||
while True:
|
||||
user_number = ask_for_number()
|
||||
if user_number is None:
|
||||
print("that's not a number! try again...")
|
||||
continue
|
||||
elif number_to_guess == user_number:
|
||||
print("yes, that's right! you win!")
|
||||
break
|
||||
elif number_to_guess > user_number:
|
||||
print("my number is bigger")
|
||||
elif number_to_guess < user_number:
|
||||
print("my number is smaller")
|
||||
print("bye bye...")
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
🏃 Try it
|
||||
---
|
||||
|
||||
My *solution* is very basic.
|
||||
Think of some ways to improve on it.
|
||||
Can you limit the number of tries?
|
||||
Can you add a feature to let the user play a *second* game after he/she wins or loses?
|
||||
Coming up with challenges is on of the most *challenging* aspect op learning how to program.
|
||||
Your thought process will send you of into unknown territory and will force you to expand you knowledge.
|
||||
We'll get back to this thought process later, but if you feel like an extra challenge go for it!
|
||||
|
||||
# Lists
|
||||
|
||||
The different built-in objects we've seen until now, such as `str` and `int` are simple [text](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) and [numeric](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex) types.
|
||||
There are other classes of objects that server different purposes.
|
||||
One of these *groups* is called [sequence types](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range).
|
||||
|
||||
A list in python is pretty much exactly what you think it is.
|
||||
It is an *object* that groups together *other* objects.
|
||||
Sounds complicated?
|
||||
Have a look at the following.
|
||||
|
||||
```python3
|
||||
my_numbers = [1, 2, 44, 60, 70]
|
||||
print(my_numbers)
|
||||
```
|
||||
|
||||
Easy right?
|
||||
Compared to [other languages](https://www.cplusplus.com/reference/list/list/) lists in python are *very* flexible.
|
||||
They can contain objects of different types, and their length can be changed at any time.
|
||||
Programmers coming from other languages often find this flexibility of python a bug but you should see it as a feature.
|
||||
|
||||
```python3
|
||||
favorite_number = 7
|
||||
name = "wouter"
|
||||
date = [1986, 10, 7]
|
||||
values = [1, date, favorite_number, "hello world", name]
|
||||
|
||||
print(values)
|
||||
```
|
||||
|
||||
The code above is just an illustration of the flexibility of lists.
|
||||
|
||||
## Creating lists
|
||||
|
||||
## Picking elements
|
||||
Creating lists can be done in two ways, either by using the **square brackets** `[]` or by calling `list`.
|
||||
When calling `list` it takes **one argument**, which python will iterate over.
|
||||
For example:
|
||||
|
||||
## Slicing lists
|
||||
```python3
|
||||
>>> first_list = ["hello", "world", "!"]
|
||||
>>> first_list
|
||||
['hello', 'world', '!']
|
||||
>>> second_list = list("hello world !")
|
||||
>>> second_list
|
||||
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', ' ', '!']
|
||||
>>>
|
||||
```
|
||||
|
||||
## List methods
|
||||
|
||||
As a `list` is a different type of object, it has different methods you can invoke on it.
|
||||
When using tab complete in the python shell we get the following.
|
||||
|
||||
```python3
|
||||
>>> second_list.
|
||||
second_list.append( second_list.count( second_list.insert( second_list.reverse(
|
||||
second_list.clear( second_list.extend( second_list.pop( second_list.sort(
|
||||
second_list.copy( second_list.index( second_list.remove(
|
||||
>>> second_list.
|
||||
```
|
||||
|
||||
One of the most used methods is `append`.
|
||||
It is used to add an element to the end of the list.
|
||||
The second most used method is the `pop` one.
|
||||
Read the shell code below and you'll understand immediately what they do.
|
||||
|
||||
```python3
|
||||
>>> first_list
|
||||
['hello', 'world', '!']
|
||||
>>> first_list.append("coucou")
|
||||
>>> first_list
|
||||
['hello', 'world', '!', 'coucou']
|
||||
>>> first_list.pop()
|
||||
'coucou'
|
||||
>>> first_list
|
||||
['hello', 'world', '!']
|
||||
>>>
|
||||
```
|
||||
|
||||
🏃 Try it
|
||||
---
|
||||
|
||||
Look at all the methods you can invoke on a list and try them out.
|
||||
Remember to read the documentation!
|
||||
|
||||
## Picking elements and slicing lists
|
||||
|
||||
We can pick elements from the list of slice the list as we please.
|
||||
A code block speaks more than words.
|
||||
|
||||
```python3
|
||||
>>> long_list
|
||||
['I', 'am', 'a', 'very', 'long', 'list', 'of', 'words', 'that', 'make', 'little', 'actual', 'sense']
|
||||
>>> long_list[7]
|
||||
'words'
|
||||
>>> long_list[7:9]
|
||||
['words', 'that']
|
||||
>>> long_list[7:]
|
||||
['words', 'that', 'make', 'little', 'actual', 'sense']
|
||||
>>> long_list[:7]
|
||||
['I', 'am', 'a', 'very', 'long', 'list', 'of']
|
||||
>>> long_list[-1]
|
||||
'sense'
|
||||
>>> long_list[0]
|
||||
'I'
|
||||
>>>
|
||||
```
|
||||
|
||||
⛑ **In programming we start counting at 0 because 0 and nothing are not the same thing.**
|
||||
|
||||
🏃 Try it
|
||||
---
|
||||
|
||||
Slice and dice away!
|
||||
A handy method of the `str` class is `split` which will cut up a string into separate elements.
|
||||
The result will be a `list` on which you can use `list` methods.
|
||||
|
||||
# For loop
|
||||
|
||||
TODO say hello to my friends exercise
|
||||
TODO simple ROT13 cryptography with multiple libs
|
||||
I mentioned the for loop, which is a loop in space, when we saw the `while` loop.
|
||||
The [keyword](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement) in question is, surprise surprise, `for`!
|
||||
I see it as a loop in space because it will run *for each element in a sequence* which in my mind is something of substance.
|
||||
Your logical mileage may vary but as long as you understand the following code block we're good.
|
||||
|
||||
```python3
|
||||
import time
|
||||
|
||||
friends = ["max", "mike", "alice", "steve", "rosa", "hans"]
|
||||
|
||||
print("The door opens and in walk my {} friends!".format(len(friends)))
|
||||
|
||||
for friend in friends:
|
||||
print("Hello {}!".format(friend.capitalize()))
|
||||
time.sleep(1)
|
||||
|
||||
print("{} closes the door behind him...".format(friend.capitalize()))
|
||||
```
|
||||
|
||||
# Coding challenge - Cheerleader chant
|
||||
|
||||
TODO nested for loop exercise
|
||||
Can you make me a program that outputs this type of cheerleader chant?
|
||||
You can make it *prettier* by importing your `pretty_print` function, plus you can add some `time.sleep` in it to make it more *musical*.
|
||||
|
||||
```
|
||||
Give me an m
|
||||
M
|
||||
Give me an a
|
||||
A
|
||||
Give me an x
|
||||
X
|
||||
Gooooooooo, MAX!
|
||||
Give me an m
|
||||
M
|
||||
Give me an i
|
||||
I
|
||||
Give me an k
|
||||
K
|
||||
Give me an e
|
||||
E
|
||||
Gooooooooo, MIKE!
|
||||
Give me an c
|
||||
C
|
||||
Give me an a
|
||||
A
|
||||
Give me an m
|
||||
M
|
||||
Give me an i
|
||||
I
|
||||
Give me an l
|
||||
L
|
||||
Give me an l
|
||||
L
|
||||
Give me an e
|
||||
E
|
||||
Gooooooooo, CAMILLE!
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Spoiler warning</summary>
|
||||
|
||||
```python3
|
||||
friends = ["max", "mike", "camille"]
|
||||
|
||||
|
||||
for friend in friends:
|
||||
for letter in friend:
|
||||
print("Give me an {}".format(letter))
|
||||
print("{}".format(letter.upper()))
|
||||
print("Gooooooooo, {}!".format(friend.upper()))
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
# Coding challenge - ROT13
|
||||
|
||||
ROT13 is one of the oldest cryptographic cyphers know to mankind.
|
||||
It dates back to the Roman empire and is also known as a [Caesar cypher](https://en.wikipedia.org/wiki/Caesar_cipher).
|
||||
The algorithm is pretty simple, you just shift a letter 13 places in the alphabet so `a` becomes `n` or `x` becomes `k`.
|
||||
Have a look at [this](https://rot13.com/) website to see the cypher in action.
|
||||
Now, can you make a program that encrypts a phrase with ROT13?
|
||||
Something along these lines:
|
||||
|
||||
```python3
|
||||
What's your secret? hello world!
|
||||
encoded secret: uryyb jbeyq!
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Spoiler warning</summary>
|
||||
|
||||
```python3
|
||||
import string
|
||||
|
||||
|
||||
def encode_rot(msg, rot=13):
|
||||
msg = msg.lower()
|
||||
letters = list(string.ascii_lowercase)
|
||||
coded_msg = []
|
||||
for letter in msg:
|
||||
if letter not in letters:
|
||||
coded_msg.append(letter)
|
||||
else:
|
||||
idx = letters.index(letter) + rot
|
||||
coded_letter = letters[idx % len(letters)]
|
||||
coded_msg.append(coded_letter)
|
||||
coded_msg = "".join(coded_msg)
|
||||
return coded_msg
|
||||
|
||||
|
||||
def decode_rot(msg, rot=13):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
clear_message = input("What's your secret? ")
|
||||
encoded_message = encode_rot(clear_message)
|
||||
print("encoded secret: {}".format(encoded_message))
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
🏃 Try it
|
||||
---
|
||||
|
||||
To make things more interesting you can add a decode function.
|
||||
Plus you could add a prompt that asks how big the shift should be (ROT13, ROT16, ...).
|
||||
|
||||
# List comprehension
|
||||
|
||||
This is a bit of an advanced topic but I'm putting it here to show you a very unique and powerful feature of python.
|
||||
It's an *in-line* combination of `list`, `for` and conditional logic which allows us to make lists of lists which obey certain conditions.
|
||||
You can [learn](https://12ft.io/proxy?q=https%3A%2F%2Frealpython.com%2Flist-comprehension-python%2F) about it online.
|
||||
|
||||
```python3
|
||||
mixed_list = ["one", "2", "three", "4", "5", "six6", "se7en", "8"]
|
||||
|
||||
digits = [d for d in mixed_list if d.isdigit()]
|
||||
|
||||
print(digits)
|
||||
```
|
||||
|
||||
The code above can be recreated **without** list comprehension as well, it will just be *a lot* longer.
|
||||
|
||||
```python3
|
||||
mixed_list = ["one", "2", "three", "4", "5", "six6", "se7en", "8"]
|
||||
|
||||
digits = []
|
||||
for d in mixed_list:
|
||||
if d.isdigit():
|
||||
digits.append(d)
|
||||
|
||||
print(digits)
|
||||
```
|
||||
|
||||
As the `d` in the list comprehension is **always** a digit, we can convert it to an integer on the spot!
|
||||
|
||||
```python3
|
||||
mixed_list = ["one", "2", "three", "4", "5", "six6", "se7en", "8"]
|
||||
|
||||
digits = [int(d) for d in mixed_list if d.isdigit()]
|
||||
|
||||
print(digits)
|
||||
```
|
||||
|
||||
# Handling files
|
||||
|
||||
When we `import` a library python will read and execute the file in question.
|
||||
We can also just *read* a simple text file and *use* the data that's in the file.
|
||||
There are two ways of reading a file, one more *pythonic* and one more linear.
|
||||
I'll outline both and you can use whichever seems more logical to you.
|
||||
|
||||
## Reading from a file
|
||||
|
||||
### In-line way
|
||||
|
||||
The builtin function `open` is what's new here.
|
||||
It takes two arguments, one is the [path](https://en.wikipedia.org/wiki/Path_(computing)) and the other is a *mode*.
|
||||
The most used modes are **read** or **write**, and this as either **text** or **binary**.
|
||||
Have a look at the documentation to discover more modes.
|
||||
|
||||
```python3
|
||||
fp = open("./examples/data.txt", "r")
|
||||
data = fp.readlines()
|
||||
print("file contains: {}".format(data))
|
||||
fp.close()
|
||||
```
|
||||
|
||||
### Pythonic way
|
||||
|
||||
The *exact* same thing can be done in a more pythonic way as follows.
|
||||
The beauty of the `with` syntax is that the `close` function call is implied by the indentation.
|
||||
I personally prefer this way of reading and writing files but you do you!
|
||||
|
||||
```python3
|
||||
file_to_open = "./examples/data.txt"
|
||||
|
||||
with open(file_to_open, "r") as fp:
|
||||
data = fp.readlines()
|
||||
print("file contains: {}".format(data))
|
||||
|
||||
print("{} has {} lines".format(file_to_open, len(data)))
|
||||
```
|
||||
|
||||
## Writing to a file
|
||||
|
||||
## csv, JSON and yaml
|
||||
Writing to a file can also be done in two ways, a pythonic and *less* pythonic way.
|
||||
As I prefer the pythonic way I'll only showcase that one but you'll be able to easily adapt the code yourself.
|
||||
The only difference is the **mode** we use to `open` the file.
|
||||
|
||||
## pickle
|
||||
```python3
|
||||
first_name = input("what's your first name? ")
|
||||
last_name = input("what's your last name? ")
|
||||
birthday = input("what's your date of birth? ")
|
||||
|
||||
data = [first_name, last_name, birthday]
|
||||
|
||||
file_to_open = "./examples/test.tmp"
|
||||
|
||||
with open(file_to_open, "w") as fp:
|
||||
for element in data:
|
||||
fp.write("{}\n".format(element))
|
||||
print("done!")
|
||||
```
|
||||
|
||||
There is also a way to write a batch of lines to a file in one go.
|
||||
This is done as follows.
|
||||
But, you'll notice there is no **newline** added after each element.
|
||||
|
||||
```python3
|
||||
data = ["wouter", "gordts", "1986"]
|
||||
|
||||
file_to_open = "./examples/test.tmp"
|
||||
|
||||
with open(file_to_open, "w") as fp:
|
||||
fp.writelines(data)
|
||||
```
|
||||
|
||||
# Coding challenge - Login generator
|
||||
|
||||
TODO write a login generator as a library with a cli as program
|
||||
BONUS argparse, save to file, read from file
|
||||
Can you write me a program that creates random, but easy to remember, usernames?
|
||||
Plus, for each username also a *not-so-easy-to-remember* password?
|
||||
Maybe with a bit of flexibility?
|
||||
For example variable password length?
|
||||
|
||||
This is an exercise you can take pretty far if you plan it out properly.
|
||||
I would advise you to write the **generator** functions as a library.
|
||||
Then import those functions into the program where you implement the user facing logic.
|
||||
By doing so you can reuse your code for multiple interfaces (CLI, TUI, [argparse](https://docs.python.org/3/howto/argparse.html)).
|
||||
If you want to you can also **save** your logins to a file!
|
||||
|
||||
An example of the output I expect:
|
||||
|
||||
```
|
||||
how many login pairs would you like to create?3
|
||||
you want complex passwords? (y/n)y
|
||||
how long should the password be?32
|
||||
username 0: EarnestCrocodile
|
||||
password 0: :sdGV&[FDYZZ|RXUpZeo`J&t@*Z>^fEW
|
||||
username 1: AbstractedDragon
|
||||
password 1: 32hz5&C@<o\OMa9tnET(lk(3wF%d?$Dy
|
||||
username 2: MeekStallion
|
||||
password 2: +;^di8a":AD;_b4^w$Fj'RVkI`CoG,LX
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Spoiler warning</summary>
|
||||
|
||||
This spoiler warning is in multiple steps.
|
||||
If you're unsure how to generate the *random-yet-easy-to-remember* have a look at [this file](./assets/subjects.txt) and [this file](./assets/adjectives.txt).
|
||||
|
||||
**Stop here and try it out!**
|
||||
|
||||
If you're unsure how to tackle the *library part* of this exercise, have a look at [this file](./assets/login_generator.py).
|
||||
Don't just copy this code, read it and recreate it yourself!
|
||||
|
||||
**Stop here and try it out!**
|
||||
|
||||
Once the library is done you can code the *interface*.
|
||||
For some inspiration for a simple question/response system you can have a look [here](./assets/pwd_cli.py).
|
||||
|
||||
</details>
|
||||
|
||||
# Dictionaries as data containers
|
||||
|
||||
TODO adapt the login generator to output a dict
|
||||
Of the *built-in* types we first say `str`, `int` and `float`.
|
||||
Next we saw *sequence* types such as `list` and `tupple`.
|
||||
Now we'll dive into a **mapping type** called `dict`.
|
||||
I advise you to have a look at the [reference pages](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict) when in doubt.
|
||||
|
||||
# Creating our own classes
|
||||
A dictionary is *kind* of like a list but it has **two** objects per **element**.
|
||||
We call them **key** and **value**.
|
||||
There are a couple of rules you need to be aware of though.
|
||||
|
||||
## Class examples
|
||||
1. In a `dict` the keys have to be **unique**.
|
||||
2. A dictionary is **unordered** meaning the *first* element is not garanteed to remain the first over the lifespan of the dictionary.
|
||||
3. The keys used must be **hashable**.
|
||||
|
||||
Let's visualize a legal dictionary!
|
||||
It's declared with **curly brackets** as follows `{}`.
|
||||
|
||||
```python3
|
||||
my_data = {"key": "value", "name": "wouter", "age": 35}
|
||||
|
||||
same_data_different_layout = {
|
||||
"key": "value",
|
||||
"name": "wouter",
|
||||
"age": 35,
|
||||
}
|
||||
```
|
||||
|
||||
Let's have a look at the **methods** we can invoke on a `dict`.
|
||||
|
||||
```python3
|
||||
>>> my_data = {"key": "value", "name": "wouter", "age": 35,}
|
||||
>>> my_data.
|
||||
my_data.clear( my_data.get( my_data.pop( my_data.update(
|
||||
my_data.copy( my_data.items( my_data.popitem( my_data.values(
|
||||
my_data.fromkeys( my_data.keys( my_data.setdefault(
|
||||
>>> my_data.keys()
|
||||
dict_keys(['key', 'name', 'age'])
|
||||
>>> my_data.values()
|
||||
dict_values(['value', 'wouter', 35])
|
||||
>>> my_data.items()
|
||||
dict_items([('key', 'value'), ('name', 'wouter'), ('age', 35)])
|
||||
>>> for key, value in my_data.items():
|
||||
... print("key is {}".format(key))
|
||||
... print("value is {}".format(value))
|
||||
...
|
||||
key is key
|
||||
value is value
|
||||
key is name
|
||||
value is wouter
|
||||
key is age
|
||||
value is 35
|
||||
>>>
|
||||
```
|
||||
|
||||
We can reference specific **values** corresponding to specific **keys** as follows.
|
||||
|
||||
```pythons
|
||||
>>> my_data["name"]
|
||||
'wouter'
|
||||
>>> my_data["age"]
|
||||
35
|
||||
>>>
|
||||
```
|
||||
|
||||
We can use dictionaries as data containers and put them in a list to group together similar data elements.
|
||||
The code below should explain it quite nicely.
|
||||
|
||||
```python3
|
||||
login_ovh = {"username": "EarnestCrocodile", "password": ":sdGV&[FDYZZ|RXUpZeo`J&t@*Z>^fEW"}
|
||||
login_mailbox = {"username": "AbstractedDragon", "password": "32hz5&C@<o\OMa9tnET(lk(3wF%d?$Dy"}
|
||||
login_gitea = {"username": "MeekStallion", "password": "+;^di8af:AD;_b4^w$Fj'RVkI`CoG,LX"}
|
||||
|
||||
my_login_list = [login_ovh, login_mailbox, login_gitea]
|
||||
|
||||
for login in my_login_list:
|
||||
print("login {}".format(my_login_list.index(login)))
|
||||
for key in login.keys():
|
||||
print("\t{}: {}".format(key, login[key]))
|
||||
```
|
||||
|
||||
# Coding challenge - Task manager
|
||||
|
||||
Can you create me a *task manager* please?
|
||||
I made one that is run from the command line with different arguments to modify it's behaviour.
|
||||
If this looks too challenging I can tell you that the *full code* is 64 lines long, including empty lines!
|
||||
Those of you who already tried out [argparse](https://realpython.com/command-line-interfaces-python-argparse/) in the previous challenges will probably understand what's going on here.
|
||||
Those who did not I urge you to have a look at the link above and don't hesitate to ask for help!
|
||||
|
||||
```bash
|
||||
➜ python_course_doc git:(master) ✗ python3 test.py --help
|
||||
usage: test.py [-h] [--file FILE] {add,delete,show} ...
|
||||
|
||||
positional arguments:
|
||||
{add,delete,show}
|
||||
add adds a todo item to you todo list
|
||||
delete deletes an item from your todo list
|
||||
show show all your tasks
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--file FILE, -f FILE path to your todo file
|
||||
➜ python_course_doc git:(master) ✗ python3 test.py show
|
||||
ID: 0 --- buy milk
|
||||
ID: 1 --- clean house
|
||||
ID: 2 --- test my code
|
||||
➜ python_course_doc git:(master) ✗ python3 test.py add write some documentation
|
||||
➜ python_course_doc git:(master) ✗ python3 test.py show
|
||||
ID: 0 --- buy milk
|
||||
ID: 1 --- clean house
|
||||
ID: 2 --- test my code
|
||||
ID: 3 --- write some documentation
|
||||
➜ python_course_doc git:(master) ✗ python3 test.py delete 2
|
||||
➜ python_course_doc git:(master) ✗ python3 test.py show
|
||||
ID: 0 --- buy milk
|
||||
ID: 1 --- clean house
|
||||
ID: 2 --- write some documentation
|
||||
➜ python_course_doc git:(master) ✗
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Spoiler warning</summary>
|
||||
|
||||
```python3
|
||||
import argparse
|
||||
import pathlib
|
||||
|
||||
|
||||
def read_taskfile(taskfile_path):
|
||||
tasks = []
|
||||
if not pathlib.Path(taskfile_path).exists():
|
||||
return tasks
|
||||
with open(taskfile_path, "r") as fp:
|
||||
lines = fp.readlines()
|
||||
for line in lines:
|
||||
task = line.strip()
|
||||
tasks.append(task)
|
||||
return tasks
|
||||
|
||||
|
||||
def write_taskfile(taskfile_path, tasks):
|
||||
with open(taskfile_path, "w") as fp:
|
||||
for task in tasks:
|
||||
fp.write("{}\n".format(task))
|
||||
|
||||
|
||||
def show_tasks(tasks):
|
||||
counter = 0
|
||||
for task in tasks:
|
||||
print("ID: {} --- {}".format(counter, task))
|
||||
counter += 1
|
||||
|
||||
|
||||
def add_task(tasks, task):
|
||||
tasks.append(task)
|
||||
return tasks
|
||||
|
||||
|
||||
def delete_task(tasks, task_id):
|
||||
tasks.pop(task_id)
|
||||
return tasks
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--file", "-f", default="./todo.tasks", help="path to your todo file")
|
||||
subparser = parser.add_subparsers()
|
||||
add = subparser.add_parser("add", help="adds a todo item to you todo list")
|
||||
add.add_argument("task", nargs="*")
|
||||
delete = subparser.add_parser("delete", help="deletes an item from your todo list")
|
||||
delete.add_argument("idx", type=int, nargs="*")
|
||||
show = subparser.add_parser("show", help="show all your tasks")
|
||||
show.add_argument("show", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
taskfile = args.file
|
||||
tasks = read_taskfile(taskfile)
|
||||
|
||||
if "task" in args:
|
||||
tasks = add_task(tasks, " ".join(args.task))
|
||||
write_taskfile(taskfile, tasks)
|
||||
elif "idx" in args:
|
||||
for idx in args.idx:
|
||||
tasks = delete_task(tasks, idx)
|
||||
write_taskfile(taskfile, tasks)
|
||||
elif args.show:
|
||||
show_tasks(tasks)
|
||||
```
|
||||
</details>
|
||||
|
||||
# Text based databases
|
||||
|
||||
The todo list example from before is handy but quite *limited* as a database.
|
||||
As is it only holds one form or information and that is the *actual task*.
|
||||
What if we want to add urgency or mark tasks complete (instead of deleting)?
|
||||
This can be done by grouping data together.
|
||||
We already saw a dictionaries which are good mapping structures but how can we save them to disk?
|
||||
A hacky way would be to write a python file containing the `dict` and `import` it when we need it.
|
||||
But there are better ways.
|
||||
|
||||
|
||||
# Now for some useful scripting
|
||||
|
||||
With everything we have learned up until now you can start doing some interesting and useful things.
|
||||
Have a look at [these exercises](https://gitea.86thumbs.net/waldek/linux_course_doc/src/branch/master/modules/qualifying/exercise_python.md).
|
||||
You can try them out at your own pace.
|
||||
I can give some hints or pointers if needed, either in class or individually.
|
||||
Don't hesitate to ask for help!
|
||||
|
||||
# Creating our own objects
|
||||
|
||||
## First some *abstract* examples
|
||||
|
||||
TODO simple animal or vehicle exercise
|
||||
TODO task manager
|
||||
|
||||
## Class inheritance
|
||||
|
||||
TODO shapes and surfaces
|
||||
TODO superhero game
|
||||
|
||||
## Improve the login generator
|
||||
## Now some *practical* improvements
|
||||
|
||||
### Improve the login generator
|
||||
|
||||
TODO convert the login generator to a class
|
||||
|
||||
### Improve the task manager
|
||||
|
||||
TODO convert the task manager to a class
|
||||
|
||||
# Infinite programs
|
||||
|
||||
* insist on the nature of scripts we did up until now
|
||||
|
||||
## Logic breakdown of a simple game
|
||||
|
||||
TODO hangman exercise
|
||||
```
|
||||
***********************
|
||||
* welcome to hangman! *
|
||||
***********************
|
||||
|
||||
guess the hidden word below
|
||||
---------------------------
|
||||
word: *****
|
||||
guess a letter: a
|
||||
word: a****
|
||||
guess a letter: l
|
||||
word: a**l*
|
||||
guess a letter: p
|
||||
word: appl*
|
||||
guess a letter: e
|
||||
word: apple
|
||||
*****************
|
||||
* you found it! *
|
||||
*****************
|
||||
do you want to play a new game? (Y/N)
|
||||
```
|
||||
|
||||
## Trivial pursuit multiple choice game
|
||||
|
||||
|
|
Loading…
Reference in New Issue