day1-code

This commit is contained in:
Philip 2025-07-15 17:04:58 +02:00
parent 8abf830f57
commit 23f03e90d1
9 changed files with 692 additions and 0 deletions

66
src/T00_Intro.py Normal file
View File

@ -0,0 +1,66 @@
# git clone https://git.budem.de/philip/tennet_course.git
# Standardpython
# externe libraries
# pandas, geopandas, matplotlib, numpy, etc
a = 13
print(a, type(a))
s = "hello"
t = 'python'
print(s, t)
# unveränderlichen datentypen und veränderlichen Datentypen
# immutable und mutable
print(id(a))
b = a # erstellt immer eine NamensReferenz auf das Objekt auf der rechten seite
print(id(b))
print()
a += 1 # a = a + 1
print(id(a))
print(a)
print(id(b))
print(b)
# unveränderliche Objekte:
# * Zahlen: int, float, (complex)
# * Strings
# * tuple (unveränderliche Liste) (nur wenn unveränderliche elemente im tuple sind)
# * (frozenset)
# alles andere ist veränderlich
s = "Hello World"
s = s.upper()
print(s)
s = s.replace("WORLD", "PYTHON")
print(s)
# Listen sind veränderlich
l1 = [5, "python", 1.3]
l2 = l1 # erzeugt einen zweiten verweis auf die Liste [5, "python", 1.3]
l1.append(42)
print(l2)
# += besser append und extend nutzen
l1 += [6, 1, 9]
print(l1)
print(l2)
# + (erzeuge eine neue Liste)
print(id(l1))
l1 = l1 + [1]
print(id(l1))
print(l1)
print(l2)
# best practise: append und extend
l1.append(15)
l1 = [1, 2, 3]
l2 = [4, 5, 6]
l1.extend([5, 8])
print(l1)
l1.extend("python") # jedes element einzeln eingefügt
print(l1)
l1.extend(["python"])
print(l1)

138
src/T01_Funktionen.py Normal file
View File

@ -0,0 +1,138 @@
# float: float oder integer
DEFAULT_B = 13 # all_caps
SPEED_OF_SOUND = 343
def divide(a, b):
# nicht überprüfen ob b != 0 da dies ein fehler ist!
return a / b
# : typehint
def convert_dog_to_human_age(dogage: int) -> int:
"""
Konvertiert ein Hundealter in Menschenjahren.
:param dogage: (int) Hundealter in Jahren
:return (int): Entsprechendes alter in Menschenjahren
Ein Hund ist immer ganze Jahre alt. z.B. 1, 2, 3, 4
"""
# assert oder raise
assert dogage >= 0, "ALter muss immer positiv sein"
# assert isinstance(dogage, int), "Muss integer sein"
human_age = 0 # lokale variable
if dogage == 1:
human_age = 14
elif dogage == 2:
human_age = 22
elif dogage > 2:
human_age = 22 + (dogage - 2) * 5
return human_age
def substract_mean(lst: list[float]) -> None:
mean = sum(lst) / len(lst)
for i in range(len(lst)):
lst[i] -= mean
# diese Zeile steht immer bei fehlendem return am Ende
return None
def create_mean_free_list(lst):
res = []
mean = sum(lst) / len(lst)
for el in lst:
res.append(el - mean)
return res
# positionelle argumente, schlüsselwort-argumente
def foo(a, b=DEFAULT_B, verbose=0):
# f-string
# formatted-string
print(f"a={a}")
print(f"{b=}")
print(f"{verbose=}")
print(f"a/b = {a/b}")
# r-string
return a / b
def open_file(file_path: str):
print(f"Opening {file_path}")
def food(bag=None, debug=False):
# is und nicht ==
# is vergleicht id
if debug:
print("Debug message")
if bag is None:
bag = []
bag.append("Spam")
return bag
def calculate_time(dist):
# 1. in der Funktion nach SPEED_OF_SOUND
# 2. Global im file + imports (selten nutzen)
# 3. im eingebauten namensraum
return dist / SPEED_OF_SOUND
def calc_circle_area(radius):
return 3.14 * radius ** 2
def calc_rect_area(height, width):
return height * width
def calc_area(shape, *sides: tuple[float], **kwargs):
print(kwargs, type(kwargs))
if "verbose" in kwargs:
verbose = kwargs.pop("verbose") # entfernt schlüssel verbose und gibt den dazugehörigen wert zurück
print(verbose)
if shape.lower() == "circle":
return calc_circle_area(*sides, **kwargs)
elif shape.lower() == "rectangle":
return calc_rect_area(*sides, **kwargs) # args[0], args[1]
else:
raise ValueError(f"Shape {shape} is not yet supported, Circle, Rectangle")
def complete_function(pos_arg1, pos_argn, *args, kw1=True, kwn="N", **kwargs):
print(pos_arg1)
if __name__ == "__main__":
dst = 10
print("test")
t = "hello"
# Beispiele
print(__name__)
scooby_doo = 6
scooby_name = "Scooby doo"
scooby_doo_human = convert_dog_to_human_age(scooby_doo)
print(scooby_doo_human)
divide(5, 1)
numbers = [42, 14, 7, 11, 13, 39]
print(numbers, id(numbers))
res = numbers.copy()
substract_mean(res)
print(numbers)
numbers.insert(0, -1)
print(numbers)
foo(31, verbose=2)
foo(10, b=3)
foo(b=5, a=2) # nicht schreiben
datei = r"C:\neuer Ordner\neuesfile" # raw-string
open_file(datei)
res = food()
print(res)
res2 = food()
print(res2)
res3 = food()
print(res3)
print(res)
l1 = [101, 102, 103]
l2 = [101, 102, 103]
print(l1 == l2)
t = calculate_time(10)
print(t)
area = calc_area("rectangle", 5, 2)
print(area)
area = calc_area("circle", 4, verbose=True)
print(area)
rect = [6, 2]
ra = calc_rect_area(*rect)
print(ra)

72
src/T02_Datentypen.py Normal file
View File

@ -0,0 +1,72 @@
from copy import deepcopy
# Listen
l = ["python", 42,18, 4, 2, 19]
print(l[0])
print(l[2:4]) # inklusive:exklusive
print(len(l))
for i in range(len(l)):
print(i, l[i])
l2 = [[1, 2, 3], [10, 11, 12]]
print(l2)
print(l2[0])
print(l2[0][1])
# kopien von veschachtelten strukturen
l_copy = l2.copy()
l_copy[0][0] = 10
print(l2)
# was ist eine Liste
# sammlung an verweise
l2 = [[1, 2, 3], [10, 11, 12]]
print(l2)
print(l2[0])
print(l2[0][1])
# kopien von veschachtelten strukturen
l_copy = deepcopy(l2)
l_copy[0][0] = 10
print(l2)
# python ist objektorientiert aufgebaut
# Dictionaries (ungeordnete Datenstruktur)
prices = {"bananas": 2.19, "oranges": 3.39, "ice-cream": 2.79, 0:"zero"}
print(prices["oranges"])
print(len(prices))
print(prices)
print(prices[0])
# hinzufügen von schlüsselwertpaaren
prices["ice-tea"] = 0.99
print(prices)
prices["bananas"] = 2.49 # update den wert
print(prices["bananas"])
print(prices)
prices.pop(0)
print(prices)
# über ein dictionary iterieren
for product in prices: # über die schlüssel
print(f"{product:10s} {prices[product]:7.2f}")
print()
for product, price in prices.items():
print(f"{product:10s} {price:7.2f}")
reduced_price = price * 0.9
product_names = ["bananas", "oranges", "ice-cream", "ice_tea"]
# gibt es ein element in einer Liste bzw. einen Schlüssel in einem dictionary
# in bei listen ist eine for-schleife (lineare Laufzeit)
if "coffee" in product_names:
print("Coffee available")
else:
print("Coffee not available")
# in bei dict: konstante Zeit
if "coffee" in prices: # überprüft nur schlüssel
print("Coffee available")
else:
print("Coffee not available")
# oder set (merkt sich nicht die reihenfolge des einfügens)
# schlüssel im dictionary:
# 1. unveränderlich
# 2. hashable

81
src/T03_Klassen.py Normal file
View File

@ -0,0 +1,81 @@
# PascalCase
class Robot:
# alle funktionen mit unterstrichen links und rechts müssen exakt so heißen
def __init__(self, name):
print(f"Creating a new robot named {name}")
# sollten immer alle attribute initialisiert werden
self.name = name
def say_hi(self):
print(f"Hello, I'm a robot called {self.name}")
r1 = Robot("Bender") # führt die init-funktion aus
print(r1.name)
r1.say_hi() # r1 -> Robot -> Robot.say_hi(r1)
Robot.say_hi(r1) # wird so nie geschrieben
# Attribute können zu jeder Zeit geändert werden
r1.name = "Calculon"
r1.say_hi()
# 2 eigene Klassen schreiben
# Circle und Rectangle
# radius
# Rectangle hat die Attribute: height, width
# beide Klassen haben die Funktionen:
# calc_area() # kreis: pi*radius**2 3.14
# calc_perimeter() # 2 * pi * radius
import math
class Circle:
def __init__(self, radius):
self.radius = radius
self.area = 0
def calc_area(self):
self.area = 3.14 * self.radius ** 2 # ^,|,& -> binäre operatoren
return self.area
def calc_perimeter(self):
return 2 * 3.14 * self.radius
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def calc_area(self):
area = self.width * self.height
return area
def calc_perimeter(self):
perimeter = 2 * (self.width + self.height)
return perimeter
if __name__ == "__main__":
print("-"*100)
c1 = Circle(2)
c2 = Circle(3.2)
print(c1.radius)
area = c1.calc_area() # Circle.calc_area(c1)
print(area)
perimeter = c1.calc_perimeter()
print(perimeter)
print(c1.calc_area() > c2.calc_area())
print(c1.radius, c1.area)
c1.radius += 1 # daran denken die fläche zu berechnen
print(c1.radius, c1.area)
r1 = Rectangle(3, 9)
print(r1.width)
print(r1.calc_area(), r1.calc_perimeter())
# inkorrekte Zustände
r1.width -= 12
print(r1.calc_area(), r1.calc_perimeter())
# rectangle ohne oop
r = [4, 2] # h, w oder w,h?
r = {"height": 4, "width": 2}

99
src/T04_Klassen_privat.py Normal file
View File

@ -0,0 +1,99 @@
# PascalCase
class Robot:
# alle funktionen mit unterstrichen links und rechts müssen exakt so heißen
def __init__(self, name):
print(f"Creating a new robot named {name}")
# __ führt dazu das ein Attribut privat ist
# bedeutet, es kann nur innerhalb der Klasse genutzt werden
self.__name = name
self.set_name(name)
def get_name(self):
return self.__name
def set_name(self, name):
if len(name) < 6:
raise ValueError("RObot name has to have at least 6 characters")
self.__name = name
def say_hi(self):
print(f"Hello, I'm a robot called {self.__name}")
r1 = Robot("Bender") # führt die init-funktion aus
print(r1.__dict__)
r1.build_year = 2996
print(r1.__dict__)
print(r1.__dict__)
print(r1.get_name())
r1.say_hi() # r1 -> Robot -> Robot.say_hi(r1)
Robot.say_hi(r1) # wird so nie geschrieben
# Attribute können zu jeder Zeit geändert werden (nicht private)
r1.__name = "Calculon"
r1.say_hi()
# 2 eigene Klassen schreiben
# Circle und Rectangle
# radius
# Rectangle hat die Attribute: height, width
# beide Klassen haben die Funktionen:
# calc_area() # kreis: pi*radius**2 3.14
# calc_perimeter() # 2 * pi * radius
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
self.set_radius(radius)
self.__area = 0
self.__area_computed = False
def get_radius(self):
return self.__radius
def set_radius(self, radius):
assert radius > 0, (f"Radius {radius}, was smaller 0")
self.__radius = radius
self.__area_computed = False
# area berechnen
def get_area(self):
if self.__area_computed:
return self.__area
print("Calculting the area")
self.__area = 3.14 * self.__radius ** 2 # ^,|,& -> binäre operatoren
self.__area_computed = True
return self.__area
def calc_perimeter(self):
return 2 * 3.14 * self.__radius
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def calc_area(self):
area = self.width * self.height
return area
def calc_perimeter(self):
perimeter = 2 * (self.width + self.height)
return perimeter
if __name__ == "__main__":
print("-"*100)
c1 = Circle(2)
area = c1.get_area() # Circle.calc_area(c1)
print(area)
print()
print(c1.get_area())
c1.set_radius(5)
print(c1.get_area())
# schönen weg mit properties
c1.set_radius(c1.get_radius() + 1)
c1.radius += 3 # fehleranfällig
# beides verbinden -> properties
# als dataclasses!

View File

@ -0,0 +1,52 @@
class Circle:
def __init__(self, radius):
# keine normale Attributzuweisung
# versteckter Aufruf einer Funktion
self.radius = radius
@property
def radius(self):
print("Getting the radius")
return self.__radius
@radius.setter
def radius(self, radius):
print("Setting a new radius")
assert radius > 0, "Radius has to be positive"
self.__radius = radius
@property
def diameter(self):
return 2 * self.radius
@diameter.setter
def diameter(self, d):
self.radius = d / 2
@property
def area(self):
# keine teuren/langsamen operationen geschehen
return self.calc_area()
def calc_area(self):
area = 3.14 * self.radius ** 2
return area
def calc_perimeter(self):
return 3.14 * self.diameter
# muss str zurück geben
def __repr__(self):
return f"Circle(radius={self.radius})"
if __name__ == "__main__":
c1 = Circle(2)
print(c1.radius)
c1.radius += 0.5
print(c1.diameter)
c1.diameter -= 1
print(c1) # -> entweder __str__ oder __repr__ definierens
c2 = Circle(2)
print(c1 == c2)
# beides verbinden -> properties
# als dataclasses!

View File

@ -0,0 +1,46 @@
from dataclasses import dataclass, field
@dataclass
class Circle:
__radius: field(init=True)
@property
def radius(self):
return self.__radius
@radius.setter
def radius(self, r):
assert r > 0, "Error radius < 0"
self.__radius = r
def __post_init__(self):
self.radius = self.__radius
print("Checking all attributes")
print(f"Checking {self.radius=}")
# def __init__(self, radius):
# self.__radius = radius
# self.__post_init__()
@dataclass(frozen=True)
class Rectangle:
width: float
height: float
# automatisch ein __init__
# automatisch ein __repr__
# automatisch ein __eq__
if __name__ == "__main__":
c1 = Circle(2)
print(c1.radius)
c1.radius += 0.5
print(c1.radius)
print(c1)
# beides verbinden -> properties
r1 = Rectangle(2, 5)
print(r1.width, r1.height)
r1 = Rectangle(r1.width + 2, r1.height)
d = {r1: "Ein rechteck"}
d[c1] = "Ein Kreis" # __hash__
# als dataclasses!

113
src/T07_pandas.py Normal file
View File

@ -0,0 +1,113 @@
import pandas as pd
# standardbibliothek
# Zwei Datenstrukturen
# Series (eine spalte)
# Dem Dataframe
cities = {"Stadt": ["London", "Berlin", "Madrid", "Rom",
"Paris", "Wien", "Bukarest", "Hamburg",
"Budapest", "Warsaw", "Barcelona",
"München", "Mailand"],
"Population": [8615246, 3562166, 3165235, 2874038,
2273305, 1805681, 1803425, 1760433,
1754000, 1740119, 1602386, 1493900,
1350680],
"Land": ["England", "Deutschland", "Spanien", "Italien",
"Frankreich", "Österreich", "Romanien",
"Deutschland", "Ungarn", "Polen", "Spanien",
"Deutschland", "Italien"]}
# erstellung des dataframes
cities_df = pd.DataFrame(cities)
# einfügen von neuen Spalten
areas = [1572, 892, 604, 1285, 105,415, 228, 755, 525, 517, 101, 310, 182]
# cities_df["Flaeche"] = areas # spalte an
print(cities_df)
# insert (position wo die spalte eingefügt wird, name, werte [skalar oder anzahl zeilen]
# insert(position, name, werte)
cities_df.insert(2, "Flaeche", areas) # wenn keine spalte namens flaeche existiert
# cities_df["Flaeche"] = -1 # keine überprüfung ob spalte existiert statt
print(cities_df)
print("-"*100)
# Setzen unseren eigenen Index
df2 = cities_df.set_index("Stadt", inplace=False) # standardwert
print(df2)
print(cities_df)
cities_df.set_index("Stadt", inplace=True)
print(cities_df)
print("\n", "*"*100)
# Selektion in Pandas
# spalten selektieren
print(cities_df["Population"])
print("-" * 100)
# Selektion von Zeilen
# nach index
print(cities_df.loc["Paris"])
# nach numerischen index
print()
print(cities_df.iloc[7])
print()
# slicing
# slicing bei loc benötigt eine der 2 Bedingungen
# * index muss einzigartig sein
# * sortiert sein
print(cities_df.loc["Rom":"Warsaw"]) # inklusiv:inklusiv
# ändern den index auf land
# 1) Index zurücksetzen
cities_df.reset_index(inplace=True)
cities_df.set_index("Land", inplace=True)
print(cities_df)
print(cities_df.loc["England":"Polen"])
cities_df.sort_index(inplace=True)
print("-"*100)
print(cities_df)
print(cities_df.loc["Deutschland":"Italien"])
print("-"*100)
print(cities_df.loc["Italien"])
print("-"*100)
print(cities_df.iloc[0:5])
cities_df = pd.DataFrame(cities)
cities_df["Flaeche"] = areas
print(cities_df)
cities_df.sort_values(by="Stadt", inplace=True)
print(cities_df)
print(cities_df.loc[4])
print(cities_df.iloc[4])
print("-"* 100)
print(cities_df)
# Selektion nach Information in Spalte
# boolsche Selektionsmaske
print(cities_df[cities_df["Population"] > 2e6])
print(cities_df[cities_df["Population"] > 2_000_000])
# Maske selbst
print(cities_df["Population"] > 2_000_000)
print()
print("-" * 100)
print(cities_df[
(cities_df["Population"] > 2_000_000) &
(cities_df["Flaeche"] > 1_000)
]) # 0000000000001 & 1000010000010001
# spalten mit strings (contains unterstützt regulären ausdrücke)
print(cities_df[cities_df["Land"].str.contains("[E|e]n")])
print(cities_df[cities_df["Land"] == "Spanien"])
print()
print("-" * 100)
spanische_staedte = cities_df[cities_df["Land"] == "Spanien"]
spanien_info = spanische_staedte[["Population", "Flaeche"]]
print(spanien_info.sum())
# & und
# | oder
# ^ exklusive_oder (1 + 1 == 0)
stadt_de_esp = cities_df[(cities_df["Land"] == "Spanien") | (cities_df["Land"] == "Deutschland")]
info = stadt_de_esp[["Population", "Flaeche"]]
print(info)
print(info.sum())

25
src/T08_WorldCities.py Normal file
View File

@ -0,0 +1,25 @@
import pandas
import pandas as pd
world_cities = pd.read_excel("../data/worldcities.xlsx")
print(world_cities)
print(world_cities.columns)
print(f"{world_cities['city']}")
# conda install openpyxl
# 1) Wie viele Einwohner haben alle Deutschen Städte?
# XYZ
# 2) Wie viele Einwohner leben auf der nördlichen/Südlichen Halbkugel
# 3) Welche Städte sind nördlich von Berlin und größer (Einwohner) als Berlin?
# New-York
# Istanbul
# Rom
# funktion
# -> raise
# -> assert
val = world_cities[(world_cities["city"] == "Berlin") & (world_cities["country"] == "Germany")]["population"].iloc[0]
print(type(val))