From 81fb6551e0e109aecd2aa33106a9c0333dddc88e Mon Sep 17 00:00:00 2001 From: waldek Date: Tue, 2 Nov 2021 10:33:03 +0100 Subject: [PATCH] adds libraries --- learning_python3.md | 260 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 5 deletions(-) diff --git a/learning_python3.md b/learning_python3.md index 856a45c..e504957 100644 --- a/learning_python3.md +++ b/learning_python3.md @@ -85,12 +85,16 @@ print("Hello World!") ``` Just for reference below are a few helloworld programs in different languages. -First `c#` then `c` and last but not least `javascript`. +First `c#` then `c` then `c++` and last but not least `javascript`. + +### c# ```c# Console.WriteLine("Hello World!"); ``` +### c + ```c #include @@ -100,6 +104,21 @@ int main() { } ``` +### c++ + +```c++ +// Your First C++ Program + +#include + +int main() { + std::cout << "Hello World!"; + return 0; +} +``` + +### javascript + ```javascript alert( 'Hello, world!' ); ``` @@ -375,6 +394,8 @@ True Your first challenge! I would like you to write a program that converts Celsius to Fahrenheit. +You should do this in a **new** python file. +I suggest you call it `c_to_f.py` or something that makes sense to you. The result of this program *could* be as follows. ```bash @@ -683,6 +704,8 @@ Think of some calculations such as the Celsius to Fahrenheit converter and creat # Coding challenge - Pretty Print Can you write me a function that decorates a name or message with a *pretty* character. +You should do this in a **new** python file. +I suggest you call it `pretty_frame.py` or something that makes sense to you. Kind of like the two examples below. ``` @@ -776,6 +799,8 @@ Also think about how you can *break* this program! That being said, we all die and we all live in a country with a life expectancy. The [Belgian](https://www.healthybelgium.be/en/health-status/life-expectancy-and-quality-of-life/life-expectancy) life expectancy for a man is about 80 years so if you know your birthday, which you should, you can calculate your theoretical death day. Plus, you can calculate the percentage of your life that remains. +You should do this in a **new** python file. +I suggest you call it `memento_mori.py` or something that makes sense to you.
Spoiler warning @@ -797,7 +822,7 @@ days_to_live = memento_mori - datetime.datetime.now().date() percentage = (days_to_live.days / life_expectancy_days) * 100 print("your theoretical death day is:", memento_mori) -print("that's", days_to_live.days, "left to live") +print("that's", days_to_live.days, "days left to live") print("which means you have {:.2f}% left to live...".format(percentage)) ``` @@ -808,17 +833,242 @@ Take your time to ask me about them, or use online documentation and keep some n # Writing your first library -TODO import pretty print and digital dice +Up until now have coded our own functions and usage of these functions. +We've seen there is no need to always write everything from scratch as we can *reuse* existing code by importing libraries and calling it's functions. +But what are those libraries actually? -## What are libraries? +Consider the following mini script. +It imports `datetime` and calls the `now` function to print the date and time. +A pretty basic clock. + +```python3 +import datetime + + +timestamp = datetime.datetime.now() +print("It is: {}".format(timestamp)) +``` + +When you put your cursor on the `now` part of the function call, you can press **CTRL-b** to go to the **declaration** of said function. +You can also right click on the `now` part and see all possible *actions* you can perform on this function. +This opens up a **second tab** in your editor window with a `datetime.py` file in it. +In this file your cursor should have jumped to the following code. + +```python3 + @classmethod + def now(cls, tz=None): + "Construct a datetime from time.time() and optional time zone info." + t = _time.time() + return cls.fromtimestamp(t, tz) +``` + +What does this look like? +It looks like python code no? +Well, it is! +Libraries are often *just* other python files we load into our program. +So if they are just python files we *should* be able to write our own libraries no? + +🏃 Try it +--- + +Import some libraries and go peak at some function declarations. +A big part of code writing is *navigating* a codebase written by other people. +Properly understanding how to navigate is essential! ## How do we write libraries? +Let's go back to our `pretty_print` function. +I have code along these lines. + +```python3 +def pretty_print(msg, decorator="#"): + line_len = len(msg) + (len(decorator) * 2) + 2 + print(decorator * line_len) + print("{} {} {}".format(decorator, msg, decorator)) + print(decorator * line_len) + +pretty_print("Wouter") +pretty_print("Python rules!") +pretty_print("Alice", "-") +``` + +I'll **create a new python file** and name it `helper_functions.py`. +In this file I rewrite (don't copy paste, you need the practice) my function. +As I'm rewriting my function I'll also need some test calls to my function. +Done! + +Now in a **second new python file** I'll name `my_program.py` I'll `import` the `helper_fucntions.py` file. +Note the syntax drops the `.py` extension! + +```python3 +import helper_functions + + +print("I'm a program") +helper_functions.pretty_print("hello world!") +``` + +If we now **run** the `my_program.py` file we get the following output. + +``` +########## +# Wouter # +########## +################# +# Python rules! # +################# +--------- +- Alice - +--------- +I'm a program +################ +# hello world! # +################ +``` + +OK, it *kind* of works, the function get's called from within the `my_program.py` file but the test calls from the `helper_functions.py` file are messing up my execution. +Luckily there is a way to tell python to only run certain code when a file should be seen as program and not a library. +Sounds complicated but it's logically very simple. + ## What is `__name__ == "__main__"`? +Remember on the first day when I showed you how python is self documenting via `print.__doc__`? +Well, there are [more](https://stackoverflow.com/questions/20340815/built-in-magic-variable-names-attributes) *magical attributes* than just the `__doc__` one! +There is one called `__name__` which is used for the exact purpose we're trying to achieve. +Go back to the `helper_functions.py` file and comment out the test calls and add the line that print's the `__name__` variable. + +```python3 +def pretty_print(msg, decorator="#"): + line_len = len(msg) + (len(decorator) * 2) + 2 + print(decorator * line_len) + print("{} {} {}".format(decorator, msg, decorator)) + print(decorator * line_len) + + +print("I'm a library") +print("my name is: {}".format(__name__)) +# pretty_print("Wouter") +# pretty_print("Python rules!") +# pretty_print("Alice", "-") +``` + +Do the same in the `my_program.py` file so it look similar to the code below. + +```python3 +import helper_functions + + +print("I'm a program") +print("my name is: {}".format(__name__)) +helper_functions.pretty_print("hello world!") +``` + +If you now run the `helper_functions.py` file you should get output similar to this. + +``` +I'm a library +my name is: __main__ +``` + +But when you run the `my_program.py` you should get something like this. + +``` +I'm a library +my name is: helper_functions +I'm a program +my name is: __main__ +################ +# hello world! # +################ +``` + +This shows that the `__name__` variable changes according to how a script is called and this behavior can be used to our advantage! +We can *evaluate* the value behind `__name__` and change execution accordingly. +Evaluating and changing execution screams **conditional logic** no? +So in the library we add the following. + +```python3 +def pretty_print(msg, decorator="#"): + line_len = len(msg) + (len(decorator) * 2) + 2 + print(decorator * line_len) + print("{} {} {}".format(decorator, msg, decorator)) + print(decorator * line_len) + + +if __name__ == "__main__": + pretty_print("Wouter") + pretty_print("Python rules!") + pretty_print("Alice", "-") +``` + +Only when the library is executed as a program, for example when we're testing out out functions, the condition is met to allow execution of our calls. +Problem sorted! +Executing our main program now gives the expected output. + +``` +I'm a program +my name is: __main__ +################ +# hello world! # +################ +``` + ## Anatomy of a program -TODO imports, functions, execution +While it's still very early in your coding career I *really* want to insist on good practices from the start as it will help you make sense of it all. +A well written script or program is divided into **three** sections. + +1. We collect external tools from libraries, either from the standard library or of our own making. +2. We write the specific tools we need for our program to run. +3. We call a combination of **external** and **specific** tools which constitutes our program logic. + +A mock-up program that follows these rules could look like this. +Notice how it's easy to read? + +```python3 +import random +import datetime + + +def first_function(): + pass + + +def second_function(): + pass + + +def third_function(): + pass + + +def fourth_function(): + pass + + +if __name__ == "__main__": + print("today it's: {}".format(datetime.datetime.now())) + choice = random.randint(0, 100) + if choice < 50: + first_function() + elif choice > 90: + second_function() + elif choice == 55: + third_function() + else: + fourth_function() +``` + +🏃 Try it +--- + +Go online and look for some scripts and programs that interest you. +See if you can assess whether the code follows the pattern I outlined. +There are a couple of things you should definitely read up on. + +* The [zen](https://www.python.org/dev/peps/pep-0020/) of python. +* What is [pythonic](https://stackoverflow.com/questions/25011078/what-does-pythonic-mean)? +* Coding [style](https://docs.python-guide.org/writing/style/) # While loop