diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53752db --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +output diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..df9614c --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +SLIDES := output/Bytes\ and\ Strings.pdf \ + output/Exceptions\ and\ Context\ managers.pdf \ + output/Functions,\ Objects\ and\ Classes.pdf \ + output/int\ and\ float.pdf \ + output/The\ Language.pdf \ + output/Modules\ and\ Packages.pdf \ + output/Collections\ and\ Iterators.pdf \ + output/Decorators\ and\ advanced\ Functions.pdf \ + output/Comprehensions.pdf + +PANDOC_COMMAND := pandoc + +PANDOC_OPTIONS := -t beamer + +.PHONY: clean all + +all: $(SLIDES) + +clean: + rm -rf output + +output: + mkdir output + +output/%.pdf: slides/%.md img $(wildcard img/*) | output + $(PANDOC_COMMAND) $(PANDOC_OPTIONS) -o "$@" "$<" \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1626d92 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# Artemis Python Slides + +These are the slides intended to be used for teaching the [Python 3](https://www.python.org/) +programming language in conjunction with the [Artemis](https://artemis-app.inf.tu-dresden.de/) +exercises. + +## Building + +To build the slides with pandoc execute: + +```sh +make all +``` + +The resulting PDF files are located in the `output` directory. + +## Slides + +The slides dont have to be taught in a specific order, but the following one is recommended: + + 1. The Language + + 2. Bytes and Strings + + 3. Functions, Objects and Classes + + 4. int and float + + 5. Exceptions and Context managers + + 6. Modules and Packages + + 7. Collections and Iterators + + 8. Decorators and advanced Functions + + 9. Comprehensions + +## Artemis exercises + +Almost every slide has an accompanying exercise in the [iFSR Artemis Course](https://artemis-app.inf.tu-dresden.de/courses/6/exercises). + +It is recommended that the exercises are started after teaching Functions, Objects and Classes. diff --git a/img/classes.png b/img/classes.png new file mode 100644 index 0000000..fee2e39 Binary files /dev/null and b/img/classes.png differ diff --git a/img/error.png b/img/error.png new file mode 100644 index 0000000..dd1fb6a Binary files /dev/null and b/img/error.png differ diff --git a/img/lambda.png b/img/lambda.png new file mode 100644 index 0000000..d24383f Binary files /dev/null and b/img/lambda.png differ diff --git a/img/list.png b/img/list.png new file mode 100644 index 0000000..5958950 Binary files /dev/null and b/img/list.png differ diff --git a/img/numbers.png b/img/numbers.png new file mode 100644 index 0000000..0a2455a Binary files /dev/null and b/img/numbers.png differ diff --git a/img/pypi.png b/img/pypi.png new file mode 100644 index 0000000..4c9d5b3 Binary files /dev/null and b/img/pypi.png differ diff --git a/img/python.png b/img/python.png new file mode 100644 index 0000000..f78593c Binary files /dev/null and b/img/python.png differ diff --git a/img/sugar.jpg b/img/sugar.jpg new file mode 100644 index 0000000..ff90951 Binary files /dev/null and b/img/sugar.jpg differ diff --git a/img/unicode.png b/img/unicode.png new file mode 100644 index 0000000..eed214a Binary files /dev/null and b/img/unicode.png differ diff --git a/slides/Bytes and Strings.md b/slides/Bytes and Strings.md index d4f587e..067adea 100644 --- a/slides/Bytes and Strings.md +++ b/slides/Bytes and Strings.md @@ -1,5 +1,7 @@ # Bytes and Strings +![Unicode Logo](img/unicode.png "https://commons.wikimedia.org/wiki/File:New_Unicode_logo.svg"){ height=75% } + --- ## Strings @@ -12,7 +14,7 @@ - can be created by enclosing text in `'single'` or `"double"` quotes (literals) - - the length can be determined by `len(string)` + - the length can be determined by [`len(string)`](https://docs.python.org/3/library/functions.html#len) --- @@ -24,22 +26,31 @@ - always start with a backslash and can be disabled by writing `r"string"` -| Escape sequence | Result | -|-------------------|----------------------------------| -| \n | ASCII Linefeed | -| \t | ASCII Horizontal Tab | -| \\\\ | \\ | -| \\" | " (works with single quotes too) | +| Escape sequence | Result | +|---------------------|----------------------------------| +| \\n | ASCII Linefeed | +| \\t | ASCII Horizontal Tab | +| \\\\\\\\ | \\\\ | +| \\" | " (works with single quotes too) | --- -### Concatenation +### Operators - strings can be concatenated by adding them using `+` - doing so with [`str.join(strings)`](https://docs.python.org/3/library/stdtypes.html#str.join) is more efficient when concatenating many strings + - using `*` with a string and an integer repeats the string + + - `==` checks whether two strings are equal + + (`!=` checks the opposite) + + - do not use the `is` operator to perform value comparisions! + + ```python # both are equal to "Hello World!" "Hello" + " " + "World!" @@ -55,22 +66,29 @@ - writing `:` without specifying a value defaults to the start and end of the string - - [`str.partition(seperator)`](https://docs.python.org/3/library/stdtypes.html#str.partition) - splits the string into the part before the first seperator, the seperator and the part after the seperator - - - [`str.split(seperator)`](https://docs.python.org/3/library/stdtypes.html#str.split) - splits the string into a list of substrings at the seperator (opposite to `str.join`) - ```python - # retuns "Hello" + # returns "Hello" "Hello World!"[0:5] "Hello World!"[:5] # returns " " "Hello World!"[5] +``` +--- + +### Splitting + + - [`str.partition(seperator)`](https://docs.python.org/3/library/stdtypes.html#str.partition) + splits the string into the part before the first seperator, the seperator and the part after the seperator + + - [`str.split(seperator)`](https://docs.python.org/3/library/stdtypes.html#str.split) + splits the string into a list of substrings at the seperator (opposite to `str.join`) + +```python # returns ("Hello", " ", "World!") - before, seperator, after = "Hello World!".partition(" ") + before, seperator, after = \ + "Hello World!".partition(" ") # returns ("Hello World!", "", "") "Hello World!".partition("not found") @@ -78,7 +96,6 @@ # returns ["Hell", " W", "rld!"] "Hello World!".split("o") ``` - --- ### Formatting @@ -109,3 +126,10 @@ - literals are prefixed with `b` - can be transformed into strings using [`bytes.decode(encoding)`](https://docs.python.org/3/library/stdtypes.html#bytes.decode) + + - can be created from strings using [`str.encode(encoding)`](https://docs.python.org/3/library/stdtypes.html#str.encode) + +```python +b"Hello W\xc3\xb6rld!".decode("utf8") == "Hello Wörld!" +b"Hello W\xc3\xb6rld!" == "Hello Wörld!".encode("utf8") +``` \ No newline at end of file diff --git a/slides/Collections and Iterators.md b/slides/Collections and Iterators.md new file mode 100644 index 0000000..7090c31 --- /dev/null +++ b/slides/Collections and Iterators.md @@ -0,0 +1,280 @@ +# Collections and Iterators + +![Linked List](img/list.png "https://commons.wikimedia.org/wiki/File:Singly-linked-list.svg"){ height=75% } + +--- + +## Collections + + - are classes whose main purpose is to store other objects + + - inherit from a class in the [`collections.abc`](https://docs.python.org/3/library/collections.abc.html) module + + - have different strengths and weaknesses + +--- + +### Accessing specific Elements + + - collections may provide access to their elements via the index operator + + - it is written by enclosing an index value with square brackets + + - elements can be removed with the `del` operator + +```python + words = "Hello World from Python".split() + + print(words[0]) # prints Hello + print(words[1]) # prints World + + words[1] = "Test" + words # ['Hello', 'Test', 'from', 'Python'] + del words[1] + words # ['Hello', 'from', 'Python'] +``` + +--- + +### Slicing + + - some collections allow to access multiple elements at once + + - they support an extension of the index operator + + - same syntax as substrings (since strings are collections too) + +```python + words = "Hello World from Python".split() + + # returns ['Hello', 'World'] + words[0:2] + words[:2] + + # returns ['from', 'Python'] + words[2:] +``` + +--- + +### Checking for Elements + + - all collections support checking whether they contain an element + + - checking is done via the `in` operator + + - can be negated by writing `not in` + +```python + words = "Hello World from Python".split() + + "World" in words # True + 42 in words # False + 42 not in words # True +``` + +--- + +### Accessing all Elements + + - the number of elements can be accessed by calling [`len(collection)`](https://docs.python.org/3/library/functions.html#len) + + - a `for` loop iterates through all elements of a collection + +```python + words = "Hello World".split() + + # prints Hello and then World + for word in words: + print(word) +``` + +--- + +## Builtin Collections + + - Python already defines many collections + + - they are available per default + + - more specialised collections are available in the [`collections`](https://docs.python.org/3/library/collections.html) module + +--- + +### list + + - Sequence which contains objects in a certain order + + - can be created by calling [`list()`](https://docs.python.org/3/library/functions.html#func-list) or enclosing elements in square brackets + + - provides fast access to elements by integer index (starting from 0) + + - support efficient addition and removal of the last element + +```python + l = [1, 9, "Hello", []] + + l[0] # 1 + l[1] # 9 + len(l) # 4 + + l.append(42) # [2, 9, "Hello", [], 42] + l.pop() # 42 +``` + +--- + +### tuple + + - immutable (and hashable) Sequence + + - can be created by calling [`tuple()`](https://docs.python.org/3/library/functions.html#func-tuple) or enclosing elements in parenthesis + + - sometimes the parenthesis can be omitted + +```python + t = (1, 9, "Hello", []) + + t[0] # 1 + t[1] # 9 + len(t) # 4 +``` + +--- + +### dict + + - Mapping which contains objects associated to other hashable objects (keys) + + - provides fast access to the value of a key and checks whether a key exists + + - has no ordering ([not anymore](https://mail.python.org/pipermail/python-dev/2017-December/151283.html) since Python 3.7) + + - can be created by calling [`dict()`](https://docs.python.org/3/library/functions.html#func-dict) or enclosing key-value pairs in curly brackets + +```python + d = {"Hello": 42, "World": 24} + + d["Hello"] # 42 + "Hello" in d # True + 42 in d # False, checks for keys + 42 in d.values() # True + ("Hello", 42) in d.items() # True +``` + +--- + +### set + + - unordered collection of hashable objects + + - contains every element exactly once + + - provides efficient checks whether an object is present + + - can be created by calling [`set()`](https://docs.python.org/3/library/functions.html#func-set) or enclosing elements in curly brackets + +```python + s = {42, 24} + + 42 in s # True + 43 in s # False + + s.add(43) + s.remove(42) + 42 in s # False + 43 in s # True +``` + +--- + +### frozenset + + - immutable (and hashable) set + + - can be created by calling [`frozenset(set)`](https://docs.python.org/3/library/functions.html#func-frozenset) + + - can be used as dict keys or elements in other sets + +--- + +## Iterators + + - are an abstract sequence of values + + - provide a `__next__()` method which returns the next element of the sequence + + - the [`next(iterator)`](https://docs.python.org/3/library/functions.html#next) function gets the next element + + - `__next__()` raises [`StopIteration`](https://docs.python.org/3/library/exceptions.html#StopIteration) when there are no more elements + +**Sharing Iterators is dangerous since they contain state!** + +--- + +### Iterables + + - are objects which can provide an Iterator + + - provide a `__iter__()` method which returns an Iterator + + - Iterator can be created by calling [`iter(iterable)`](https://docs.python.org/3/library/functions.html#iter) + + - used by the `for` loop + +**Some Iterables can not be modified while an Iterator exists!** + +--- + +### Adapters + + - [`range(start, stop, step=1)`](https://docs.python.org/3/library/functions.html#func-range) creates a sequence of integers + + - [`zip(*iterables)`](https://docs.python.org/3/library/functions.html#zip) combines multiple Iterables into a single one + + - [`all(iterable)`](https://docs.python.org/3/library/functions.html#all) and [`any(iterable)`](https://docs.python.org/3/library/functions.html#any) + check whether all (or any) elements of an Iterable are `True` + + - the [`itertools`](https://docs.python.org/3/library/itertools.html) module provides more tools for Iterators + +**Collections are Iterables too!** + +--- + +### Examples + +```python + for i in [1, 2, 3]: + if i > 9: + break + else: # executed when no break was executed + print("no element bigger than 9") + + iterator = iter(range(0, 2)) + next(iterator) # 0 + next(iterator) # 1 + next(iterator) # raises StopIteration + + all([True, False, True]) # False + any([True, False, True]) # True +``` + +--- + +### Unpacking + + - Iterables can be unpacked into multiple variables + + - the last variable can be a list of all remaining elements + + - can be used in `for` loops and variable assignment + +```python + t = (1, 2, 3) + + x, y, z = t # x=1 y=2 z=3 + first, *rest = t # first=1 rest=[2, 3] + + for key, value in {"Hello": 42, "World": 24}.items(): + print(key, value) +``` diff --git a/slides/Comprehensions.md b/slides/Comprehensions.md new file mode 100644 index 0000000..7e253be --- /dev/null +++ b/slides/Comprehensions.md @@ -0,0 +1,97 @@ +# Comprehensions + +![Why sugar?](img/sugar.jpg "https://commons.wikimedia.org/wiki/File:W%C3%BCrfelzucker_--_2018_--_3582.jpg"){ height=75% } + +--- + +## Syntactic sugar + + - makes things easier to read or express + + - does not add more expressive power to the language + + - designed for use by humans + +--- + +## List Comprehensions + + - concise way to create lists + + - syntax is `[EXPRESSION for VARIABLE in ITERABLE]` + + - resulting list contains result of EXPRESSION for every element of ITERABLE + +```python + base = 2 + # [1, 2, 4, 8, 16] + powers = [base ** i for i in range(5)] +``` + +--- + +## Filtering + + - elements can be ignored by a filter + + - FILTER is an expression which evaluates to whether the element should be kept (`True` or `False`) + + - syntax is `[EXPRESSION for VARIABLE in ITERABLE if FILTER]` + +```python + # [0, 2, 4, 6, 8] + even = [x for x in range(10) if x % 2 == 0] +``` + +--- + +## Nesting + + - multiple iterables can be nested + + - equivalent to nested for loops + +**Big comprehensions have poor readability!** + +```python +combs = [(x, y) for x in [1,2,3] for y in [3,1,4]] +# equivalent +combs = [] +for x in [1,2,3]: + for y in [3,1,4]: + combs.append((x, y)) +``` + +--- + +## Dictionary Comprehensions + + - concise way to create dicts + + - syntax is `{KEY: VALUE for VARIABLE in ITERABLE}` + + - KEY and VALUE expressions generate dictionary key and value + +```python + names = ["Alan", "Charles", "Konrad"] + # {'Alan': 4, 'Charles': 7, 'Konrad': 6} + lengths = {i: len(i) for i in names} +``` + +--- + +## Generator Comprehensions + + - like list comprehensions, but result is an iterable + + - syntax is `(EXPRESSION for VARIABLE in ITERABLE)` + + - can only be iterated once (saves memory) + +```python + even = (x for x in range(10) if x % 2 == 0) + # [0, 2, 4, 6, 8], exhausts the iterable + list(even) + # parenthesis can be omitted in function call + list(x for x in range(10) if x % 2 == 0) +``` diff --git a/slides/Decorators and advanced Functions.md b/slides/Decorators and advanced Functions.md new file mode 100644 index 0000000..24abac8 --- /dev/null +++ b/slides/Decorators and advanced Functions.md @@ -0,0 +1,191 @@ +# Decorators and advanced Functions + +![Greek letter lambda](img/lambda.png "https://commons.wikimedia.org/wiki/File:Greek_lc_lamda_thin.svg"){ height=75% } + +--- + +## Functions are values + + - everything in Python is an object + + - Functions are no exception + + - allows for passing functions as parameters + +```python + def call_if(condition, callback): + if condition: + callback() + + def say_hello(): + print("Hello World!") + + call_if(True, say_hello) # Hello World! +``` + +--- + +## Anonymous Functions + + - functions can exist without being assigned a name + + - defined using `lambda arg1, ...: expression` + + - only supports expressions (excludes most control flow) + +```python + def call_if(condition, callback): + if condition: + callback() + + call_if(True, lambda: print("Hello World!")) +``` + +--- + +## Closures + + - functions keep read-only references to the scope in which they are defined + + - allows functions to access values not passed via parameters + +```python + def make_greeter(phrase): + def greeter(name): + print(f"{phrase} {name}!") + return greeter + + greeter = make_greeter("Hello") + greeter("World") # Hello World! +``` + +--- + +## Default parameters + + - function parameters can be assigned a default value + + - when the parameter is omitted the default value is used + + - default parameters can not be followed by parameters without defaults + +**Dont use mutable values as defaults!** + +```python + def make_greeter(phrase="Hello"): + def greeter(name): + print(f"{phrase} {name}!") + return greeter + + greeter = make_greeter() + greeter("World") # Hello World! +``` + +--- + +## Keyword arguments + + - function parameters are identified by position + + - the name of the parameter can be passed explicitly + + - named arguments can not be followed by positional arguments + +```python + def say_hello(phrase, name): + print(f"{phrase} {name}!") + + # all output Hello World! + say_hello("Hello", "World") + say_hello(name="World", phrase="Hello") + say_hello("Hello", name="World") +``` + +--- + +## Arbitrary Argument Lists + + - functions can accept arbitrary arguments + + - positional arguments which can not be assigned parameters are collected as `tuple` in argument prefixed by `*` + + - keyword arguments of the same type are collected as `dict` in argument prefixed by `**` + + - `*` parameter has to come before `**` parameter (and both can only exist once) + +```python + def test(*args, **kwargs): + print(args, kwargs) + + test() # () {} + test(1, 2, 3) # (1, 2, 3) {} + test(a=1, b=2) # () {'a': 1, 'b': 2} +``` + +--- + +## Unpacking Argument Lists + + - inverse to arbitrary argument lists + + - iterables can be unpacked using the `*` operator + + - dictionaries can be unpacked using the `**` operator + +```python + def greet_all(*names): + for name in names: + print(f"Hello {name}!") + + # prints Hello World! and Hello Python! + greet_all(*["World", "Python"]) +``` + +--- + +## Decorators + + - functions can be passed to other functions before being assigned a name + + - receiving function is marked behind `@` symbol + + - returned value is assigned the name + +```python + def print_start_end(function): + def wrapper(*args, **kwargs): + print("Start") + function(*args, **kwargs) + print("End") + return wrapper + + @print_start_end + def say_hello(): + print("Hello World!") + + # prints Start, Hello World! an End + say_hello() +``` + +--- + +## Generators + + - functions can produce Iterators using the `yield` statement + + - `yield` returns one value to the caller without exiting the function + + - when the next value is required the function continues + +```python + # already available per default + def map(function, iterable): + for value in iterable: + yield function(value) + + names = ["World", "Python"] + greetings = map(lambda name: f"Hello {name}!", names) + # prints Hello World! and Hello Python! + for greeting in greetings: + print(greeting) +``` diff --git a/slides/Exceptions and Context managers.md b/slides/Exceptions and Context managers.md new file mode 100644 index 0000000..0d99486 --- /dev/null +++ b/slides/Exceptions and Context managers.md @@ -0,0 +1,170 @@ +# Exceptions and Context managers + +![Oh no!](img/error.png "https://commons.wikimedia.org/wiki/File:Generic_error_message.png"){ height=75% } + +--- + +## Error handling + + - errors are a common occurrence + + - robust programs have to handle errors gracefully: + + - fatal errors should cause a controlled appplication shutdown + + - not all have to be fatal (a network timeout can be retried) + +--- + +## Return values + + - old method primarily used by languages like C + + - depends on failed functions returning special values like `None` on error + + - does not protect against the returned values being ignored + +```py +values = {} +if values.get(42) is None: + print("Value 42 does not exist!") +``` + +--- + +## Exceptions + + - alternative method which makes it impossible to ignore errors + + - uses instances of the [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception) class to represent errors + + - custom exceptions can be created by subclassing existing ones + + - multiple exceptions are already [defined](https://docs.python.org/3/library/exceptions.html) + +--- + +### Raising exceptions + + - to signal that an error occured use the `raise` statement + + - raising an exception exits the current function (like `return`) + + - when a function raises an exception it raises it in its caller when returning + +```py +def test(): + raise Exception("something went wrong!") + print("Wont be executed") + +test1() +print("Wont be executed") +``` + +--- + +### Handling exceptions + + - to catch a raised exception use the `try` statement with `except` + + - `except` prevents exceptions inheriting from a certain class from exiting the current function + + - multiple `except` are allowed and they can be empty to catch all exceptions (not recommended!) + +```py +try: + raise Exception("something went wrong!") + print("Wont be executed") +except Exception as error: + print(f"An error occured: {error}") +print("Will be executed") +``` + +--- + +#### Prevent exceptions from being handled accidentally + + - `except` handles all exceptions being raised in the `try` statement + + - some exceptions can be raised by multiple functions, which should not be in the `try` statement + + - `else` executes only when no exceptions where raised + +```py +try: + value = parse_value(string) +except Exception: + print("Parsing failed") +else: + process(value) +``` + +--- + +### Performing cleanup + + - sometimes code like closing files should be executed no matter what happens + + - the `try` statement supports this using `finally` + + - after executing `finally` the program continues undisturbed + +```py +try: + raise Exception("something went wrong!") + print("Wont be executed") +finally: + print("Will be executed") +print("Wont be executed") +``` + +--- + +### Nesting exceptions + + - when handling an exception other exceptions can be raised + + - when they are not handled they are propagated with the original exception in `__context__` + + - when the new exception was raised intentionally using `raise ... from ...` it is stored in `__cause__` + +```py +try: + try: + raise ValueError("something went wrong!") + print("Wont be executed") + except ValueError: + raise Exception("oops") + finally: + print("Will be executed") +except ValueError: + print("Wont be executed") +``` + +--- + +## Context Managers + + - objects support the `with` statement by having `__enter__` and `__exit__` methods + + - `__enter__` returns the value produced by the `with` statement + + - `__exit__` receives the exception class, its instance and traceback (information where it was raised) which may be `None` + + - is always executed when exiting the `with` statement + + - can handle the exception by returning `True` + +```py +class Example: + + def __enter__(self): + print("We enter the statement") + return self + + def __exit__(self, type, value, traceback): + print("We exit the statement") + +with Example() as example: + print("We are inside the statement") +``` diff --git a/slides/Functions, Objects and Classes.md b/slides/Functions, Objects and Classes.md index e7a5602..41ab86e 100644 --- a/slides/Functions, Objects and Classes.md +++ b/slides/Functions, Objects and Classes.md @@ -1,5 +1,7 @@ # Functions, Objects and Classes +![Class hierarchy](img/classes.png "Generated by plantuml"){ height=75% } + --- ## Programming paradigms @@ -61,19 +63,26 @@ - part of the program in which a certain variable is visible - - function and class definitions are a scope + - scripts, function and class definitions are a scope - inner scopes optain read only access to variables in their enclosing scope + - variables are always created in the current scope + - variable assignment can replace variables from the enclosing scope with variables from the current scope having the same name (shadowing) +--- + +#### Scope Example + ```python # global scope, visible to the whole script var = 12 - # the variables a and m are only visible to the code in mean_with_var - def mean_with_var(a): + # the variables a and m are only visible + # to the function 'test' + def test(a): m = (a + var) / 2 return m @@ -81,9 +90,9 @@ m = 6 # prints 9.0 - print(mean_with_var(m)) + print(test(m)) - # prints 6, the variable m was shadowed in mean_with_var + # prints 6, the variable m was shadowed in test print(m) ``` @@ -97,6 +106,19 @@ - create objects by being called +```python + class TestClass: + # attribute on every instance + number = 42 + + # the first parameter is the object + # this method is called on + def calculate(self, a): + # attribute access by writing object.attribute + return self.number + a + + instance = TestClass() +``` --- ### Objects @@ -107,8 +129,22 @@ - behave like a inner scope of their class definition + - class can be checked by calling + [`type(object)`](https://docs.python.org/3/library/functions.html#type) or + [`isinstance(object, class)`](https://docs.python.org/3/library/functions.html#isinstance) + - can be compared by identity with the `is` operator +```python + # create two different objects from the same class + x = TestClass() + y = TestClass() + + x is x # True + x is y # False + type(x) is TestClass # True + isinstance(x, TestClass) # True +``` --- ### Methods @@ -120,22 +156,7 @@ - since attributes and methods are in the scope of the instance they have to be accessed by writing `instance.attribute` or `instance.method` ---- - ```python - class TestClass: - # attribute on every instance - number = 42 - - # the first parameter is the object this method is called on - def calculate(self, a): - # attribute access by writing object.attribute - return self.number + a - - # create two different objects from the same class - x = TestClass() - y = TestClass() - # prints 43 print(x.calculate(1)) @@ -144,11 +165,14 @@ # prints 41 print(x.number) - # prints 42, attributes are not shared between instances - # since the class attribute is being shadowed by an object attribute + # prints 42, attributes are not shared + # between instances since the class attribute + # is being shadowed by an object attribute print(y.number) ``` +--- + ### Special Methods - some methods have special meaning to the interpreter @@ -166,14 +190,20 @@ self.a = a self.b = b - # used when the object has to be converted into a string + # used when converted into a string def __str__(self): return "Iam a string!" - # used when the object has to be presented, like for debugging + # used when presented, like for debugging def __repr__(self): return "Iam a representation!" - +``` + +--- + +#### Expecial Methods Example + +```python x = Example(1, 2) # prints 1 @@ -191,34 +221,57 @@ ### Inheritance - - establishes a "is a" relation between the instances of two classes + - establishes a "is a" relation between two classes - the subclass inherits the methods and attributes of the superclass + - superclasses are searched left to right + - access to shadowed attributes and methods of the superclass by calling [`super()`](https://docs.python.org/3/library/functions.html#super) + - inheritance hierarchy can be checked with + [`issubclass(subclass, superclass)`](https://docs.python.org/3/library/functions.html#issubclass) + +--- + +#### Inheritance Example + ```python class Human: def __init__(self, firstname, lastname): self.firstname = firstname self.lastname = lastname - - def __repr__(self): - return self.say_name() def __str__(self): return self.say_name() + def __repr__(self): + return self.say_name() + def say_name(self): return f"{self.firstname} {self.lastname}" - +``` + +--- + +#### Inheritance Example + +```python class Child(Human): - def __init__(self, firstname, lastname, father, mother): + def __init__(self, firstname, lastname, + father, mother): super().__init__(firstname, lastname) self.father = father self.mother = mother def __repr__(self): - return f"{self}, child of {self.father} and {self.mother}" + return f"{self}, child of {self.father}" \ + f" and {self.mother}" + + a = Human("Maria", "Musterfrau") + b = Child("Max", "Mustermann", + "Max Mustervater", "Maria Mustermutter") + + issubclass(Child, Human) # True ``` diff --git a/slides/Modules and Packages.md b/slides/Modules and Packages.md new file mode 100644 index 0000000..79f24f1 --- /dev/null +++ b/slides/Modules and Packages.md @@ -0,0 +1,146 @@ +# Modules and Packages + +![Python Package Index](img/pypi.png "https://pypi.org"){ height=75% } + +--- + +## Modularization + +Programs often contain large amounts of functions and classes + + - they can be grouped into cohesive sets + + - some of these can be reused in other programs + +*Python provides built-in modularization* + +--- + +## Modules + + - represent loaded scripts + + - have the same name as the script (without `.py`) + + - have the variables of the script as attributes + + - are reused after being loaded once + +--- + +### Why the boilerplate? + + - when loading a script it is executed from top to bottom + + - when not loading as a module the variable `__name__` is `"__main__"` + + - checking this variable prevents unwanted code execution + +--- + +## Importing Modules + + - `import module` loads a module and stores it in the variable `module` + + - the module search path is searched for a matching file with a `.py` extension + + - `from module import value` stores `module.value` in the variable `value` + +```py +# print the python implementation +import sys +print(sys.implementation.name) + +# alternative which does the same +from sys import implementation +print(implementation.name) +``` + +--- + +### Module search path + + - controls where modules are searched + + - stored in [`sys.path`](https://docs.python.org/3/library/sys.html#sys.path) + + - contains by default the directory of the started script + +--- + +## Packages + + - are directories containing a `__init__.py` + + - can be imported like modules (which loads `__init__.py`) + + - modules in them have the name `package.module` + + - contained modules can import from their enclosing package with `from . import module` + +**Prevent cyclic imports!** + +--- + +## Built-in Modules + + - Python already provides many modules (batteries included) + + - they are listed in the [documentation](https://docs.python.org/3/library) + +Some examples: + +| Module | Content | +|----------|------------------------------------| +| sys | Interfaces to the Python Runtime | +| os | Interfaces to the Operating system | +| re | Regular expressions | +| math | mathematical functions | +| datetime | Date and Time functions | +| random | Random number generator | + +--- + +## Installing modules + + - user contributed modules can be installed using [`pip`](https://packaging.python.org/en/latest/tutorials/installing-packages/#use-pip-for-installing) + + - `pip` can be installed by executing [this](https://bootstrap.pypa.io/get-pip.py) Python script + + - the [Python Package Index](https://pypi.org) lists available modules + + - per default they are installed in the global packages for the current user + +**Be careful when installing code from other people!** + +```sh +# install a module +python3 -m pip install "module" + +# list installed modules +python3 -m pip list + +# uninstall a module +python3 -m pip uninstall "module" +``` + +--- + +## Virtual environments + + - some enviroments disallow pip to install packages globally + + - multiple projects might require different version of the same package + + - the [`venv`](https://docs.python.org/3/library/venv.html) module allows to create independent environments + +```sh +# create environment in directory +python3 -m venv directory + +# activate environment (bash) +source directory/bin/activate + +# deactive environment +deactivate +``` \ No newline at end of file diff --git a/slides/The Language.md b/slides/The Language.md new file mode 100644 index 0000000..e9e9ac4 --- /dev/null +++ b/slides/The Language.md @@ -0,0 +1,147 @@ +# The Language + +![Python Logo](img/python.png "https://commons.wikimedia.org/wiki/File:Python_logo_01.svg"){ height=75% } + +--- + +## Basics + +*Python is an object oriented scripting language* + + - everything is an object + + - source code is executed directly + + (from top to bottom) + + - source code has the extension `.py` + +--- + +## Comments + +*Code Tells You How, Comments Tell You Why* + + - allow to add additional information + + - `#` marks a whole line as a comment + +```python +# this is a comment! +print("Hello World!") # this one too! +``` + +--- + +## Function calls + + - functions are code you can execute + + - they may take variables (arguments) + + - arguments can be passed as keywords + + - arguments are passed between '(' and ')' + +```python +print("Hello World!") +print("Your name is", input("Name: "), sep=": ") +``` + +--- + +## Variables + + - store objects as references + + - can be changed (not immutable) + + - dont have a type + + - only available after assignment + +```python +a = "Hello World!" +print(a) +a = "Bye World!" +print(a) +``` + +--- + +## Logic + + - conditions can be `True` or `False` + + - evaluate to instances of [`bool`](https://docs.python.org/3/library/stdtypes.html#boolean-type-bool) + +| Operator | Operation | +|----------|--------------| +| not | Negation | +| and | Conjunction | +| or | Disjunction | +| ^ | Exclusive or | + +```python + True and False # False + + True or False # True + + True ^ True # False +``` + +--- + +## Control Structures + + - control the order in which code is executed + + - blocks of code are indented by whitespace + + - whitespace indent of a block must be the same + +--- + +### Conditional Statement + + - executes code whether a condition is `True` or `False` + +```python + if True or False: # condition is True + print("Executed") + else: + print("not Executed") +``` + +--- + +### While Loop + + - executes code while a condition is `True` + + - can be terminated with a `break` + + - can be resumed with a `continue` + +```python + while True or False: # condition is True + print("Executed") + break + print("not Executed") + print("Executed") +``` + +--- + +### For Loop + + - iterates through an [`Iterator`](https://docs.python.org/3/glossary.html#term-iterator) + + - iterators are an abstract sequence of values + + - in every iteration the current value is available as a variable + +```python + for i in range(10): + print(i) +``` diff --git a/slides/int and float.md b/slides/int and float.md index 6409440..8d08b4c 100644 --- a/slides/int and float.md +++ b/slides/int and float.md @@ -1,5 +1,7 @@ # int and float +![Number sets](img/numbers.png "https://commons.wikimedia.org/wiki/File:NumberSetinC.svg"){ height=75% } + --- ## The numeric tower @@ -18,7 +20,7 @@ - can contain arbitrary large numbers unlike most other languages - - can be created by calling [`int(value)'](https://docs.python.org/3/library/functions.html#int) + - can be created by calling [`int(value)`](https://docs.python.org/3/library/functions.html#int) or using literals like `42` or `-9` --- @@ -29,7 +31,7 @@ - have limited accuracy making them not suitable for things like money (`0.1 + 0.1 + 0.1 != 0.3`) - - can be created by calling [`float(value)](https://docs.python.org/3/library/functions.html#float) + - can be created by calling [`float(value)`](https://docs.python.org/3/library/functions.html#float) or using literals like `42.6` or `426e-1` ---