Checks¶
Variablen und Ausdrücke¶
Erstellt in der Python-Shell einige Variablen. Was passiert, wenn ihr Leerzeichen, Bindestriche oder andere Zeichen in den Variablennamen einfügt?
>>> x = 3 >>> var fünf = 5 File "<stdin>", line 1 var fünf = 5 ^^^^ SyntaxError: invalid syntax >>> var_fünf = 5
Ändern sich die Ergebnisse, wenn ihr Klammern verwendet, um Zahlen auf verschiedene Weise zu gruppieren?
>>> 2 + 3 * 4 - 5 / 6 13.166666666666666 >>> (2 + 3) * 4 - 5 / 6 19.166666666666668 >>> 2 + (3 * 4) - 5 / 6 13.166666666666666 >>> 2 + 3 * (4 - 5) / 6 1.5
Welche der folgenden Variablen- und Funktionsnamen sind eurer Meinung nach kein guter Python-Stil, und warum?
var*
❌ enthält ein unzulässiges Zeichen (
*
)varname
✅ ok, aber mit Unterstich einfacher lesbar
func_name()
✅
varName
❌ Gemischte Groß- und Kleinschreibung
VARNAME
❌ Nur Großbuchstaben, schlecht lesbar
very_very_long_var_name
✅ ok, aber sehr lang und daher nur zu empfehlen, wenn zwischen vielen sehr ähnlichen Variablen unterschieden werden soll
Zahlen¶
Erstellt einige Zahlenvariablen (Ganzzahlen, Gleitkommazahlen und komplexe Zahlen). Experimentiert ein wenig damit, was passiert, wenn ihr Operationen mit ihnen durchführt, auch Typ-übergreifend.
>>> x = 3 >>> import math >>> pi = math.pi >>> pi 3.141592653589793 >>> c = 3j4 File "<stdin>", line 1 c = 3j4 ^ SyntaxError: invalid imaginary literal >>> c = 3 +4j >>> c (3+4j) >>> x * c (9+12j) >>> x + c (6+4j)
Komplexe Zahlen¶
Ladet das Modul
math
und probiert einige der Funktionen aus. Ladet dann auch das Modulcmath
und macht dasselbe.>>> from math import sqrt >>> sqrt(3) 1.7320508075688772 >>> from cmath import sqrt >>> sqrt(3) (1.7320508075688772+0j)
Wie könnt ihr die Funktionen des
math
-Moduls wiederherstellen?>>> from math import sqrt >>> sqrt(3) 1.7320508075688772
Boolesche Werte¶
Entscheidet, ob die folgenden Aussagen wahr oder falsch sind:
1
→ True0
→ False-1
→ True[0]
→ True (Liste mit einem Item)1 and 0
→ False1 > 0 or []
→ True
Listen¶
Was gibt
len()
für jeden der folgenden Fälle zurück:>>> len([3]) 1 >>> len([]) 0 >>> len([[1, [2, 3], 4], "5 6"]) 2
Wie würdet ihr mit
len()
und Slices die zweite Hälfte einer Liste ermitteln, wenn ihr nicht wisst, wie groß sie ist?>>> l = [[1, [2, 3], 4], "5 6"] >>> l[len(l) // 2 :] ['5 6']
Wie könntet ihr die letzten zwei Einträge einer Liste an den Anfang verschieben, ohne die Reihenfolge der beiden zu ändern?
>>> l[-2:] + l[:2] ['5 6', 7, [1, [2, 3], 4], '5 6']
Welcher der folgenden Fälle löst eine Exception aus?
min(["1", "2", "3"])
max([1, 2, "3"])
[1,2,3].count("1")
max([1, 2, "3"])
, da Strings und Ganzzahlen nicht verglichen werden können; daher ist es unmöglich, einen Maximalwert zu erhalten.Wenn ihr eine Liste
l
habt, wie könnt ihr daraus einen bestimmten Werti
entfernen?>>> if i in l: ... l.remove(i) ...
Bemerkung
Mit diesem Code wird nur das erste Vorkommen von
i
entfernt. Um alle Vorkommen voni
aus der Liste zu entfernen, könnte die Liste z.B. in den Set-Typ umgewandelt werden:>>> l = set(l) >>> if i in l: ... l.remove(i) ... >>> l = list(l)
Dies ändert jedoch auch die Reihenfolge der Elemente.
Wenn ihr eine verschachtelte Liste
ll
habt, wie könnt ihr eine Kopienll
dieser Liste erhalten, in der ihr die Elemente ändern könnt, ohne den Inhalt vonll
zu verändern?>>> import copy >>> nll = copy.deepcopy(ll)
Stellt sicher, dass das Objekt
my_collection
eine Liste ist, bevor ihr versucht, daran Daten anzuhängen.>>> my_collection = [] >>> if isinstance(my_collection, list): ... print(f"my_collection is a list") ... my_collection is a list
Welche anderen Optionen könntet ihr neben der expliziten Überprüfung des Typs haben?
Tupel¶
Erläutert, warum die folgenden Operationen nicht auf das Tuple
t
angewendet werden können:t.append(1)
t[2] = 2
del t[3]
Alle Operation versuchen, das Tuple
t
zu ändern. Tuples können jedoch nicht verändert werden.Wie könnt ihr die Elemente eines Tuple sortieren?
>>> sorted(t)
Sets¶
Wieviele Elemente hat ein Set, wenn es aus der folgenden Liste
[4, 2, 3, 2, 1]
gebildet wird?Vier unterschiedliche Elemente.
Dictionaries¶
Angenommen, ihr habt die beiden Dictionaries
x = {"a":1, "b":2, "c":3, "d":4}
undy = {"a":5, "e":6, "f":7}
. Was wäre der Inhalt vonx
, nachdem die folgenden Codeschnipsel ausgeführt wurden?>>> del x["b"] >>> z = x.setdefault("e", 8) >>> x.update(y)
>>> x = {"a": 1, "b": 2, "c": 3, "d": 4} >>> y = {"a": 5, "e": 6, "f": 7} >>> del x["b"] >>> z = x.setdefault("e", 8) >>> x.update(y) >>> x {'a': 5, 'c': 3, 'd': 4, 'e': 6, 'f': 7}
Welcher der folgenden Ausdrücke kann ein Schlüssel eines Dictionary sein:
1
;"Veit"
;("Veit", [1])
;[("Veit", [1])]
;["Veit"]
;("Veit", "Tim", "Monique")
>>> d = {} >>> d[1] = None >>> d["Veit"] = None >>> d[("Veit", [1])] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> d[["Veit"]] = None Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> d[("Veit", "Tim", "Monique")] = None
Ihr könnt ein Dictionary verwenden, und das wie ein Tabelle einer Tabellenkalkulation verwenden, indem ihr Tupel als Schlüssel Zeilen- und Spaltenwerte verwendet. Schreibt Beispielcode, um Werte hinzuzufügen und wieder abzufragen.
>>> sheet = {} >>> sheet[("A", 0)] = 1 >>> sheet[("A", 1)] = 2 >>> sheet[("B", 0)] = 3 >>> sheet[("B", 1)] = 4 >>> print(sheet[("A", 1)]) 2
Wie könnt ihr alle Dubletten aus einer Liste entfernen ohne die Reihenfolge der Elemente in der Liste zu ändern?
Hierfür können die Schlüssel eines Dictionaries verwendet werden:
>>> list(dict.fromkeys(l))
Zeichenketten¶
Könnt ihr z.B. eine Zeichenkette mit einer ganzen Zahl addieren oder multiplizieren, oder mit einer Gleitkommazahl oder einer komplexen Zahl?
>>> x = 3 >>> c = 3 + 4j >>> snake = "🐍" >>> x + snake Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'int' and 'str' >>> x * snake '🐍🐍🐍' >>> c + snake Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'complex' and 'str' >>> c * snake Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't multiply sequence by non-int of type 'complex'
Operatoren und Funktionen¶
Welche der folgenden Zeichenketten können nicht in Zahlen umgewandelt werden und warum?
>>> int("1e2") Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: '1e2' >>> int(1e+2) 100 >>> int("1+2") Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: '1+2' >>> int("+2") 2
string¶
Wie könnt ihr eine Überschrift wie
variables and expressions
so abändern, dass sie statt Leerzeichen Bindestriche enthält und so besser als Dateinamen verwendet werden kann?>>> ve = "variables and expressions" >>> "-".join(ve.split()) 'variables-and-expressions'
Wenn ihr überprüfen wollt, ob eine Zeile mit
.. note::
beginnt, welche Methode würdet ihr verwenden? Gibt es auch noch andere Möglichkeiten?>>> x.startswith(".. note::") True >>> x[:9] == ".. note::" True
Angenommen, ihr habt eine Zeichenkette mit Ausrufezeichen, Anführungszeichen und Zeilenumbruch. Wie können diese aus der Zeichenkette entfernt werden?
>>> hipy = "„Hello Pythonistas!“\n" >>> hipy.strip("„“!\n") 'Hello Pythonistas'
Wie könnt ihr alle Leerräume und Satzzeichen aus einer Zeichenfolge in einen Bindestrich (
-
) ändern?>>> from string import punctuation, whitespace >>> chars = punctuation + whitespace >>> subs = str.maketrans(chars, len(chars) * "-") >>> hipy = "Hello Pythonistas!\n" >>> hipy.translate(subs) 'Hello-Pythonistas--'
re¶
Welchen regulären Ausdruck würdet ihr verwenden, um Zeichenfolgen zu finden, die die Zahlen zwischen -3 und +3 darstellen?
r"-?[0-3]"
oderr"-{0,1}[0-3]"
?
ist ein Quantifizierer für ein oder kein Vorkommen.
Welchen regulären Ausdruck würdet ihr verwenden, um Hexadezimalwerte zu finden?
r"0[xX][0-9a-fA-F]+"
entspricht einem Ausdruck, der mit
0
beginnt, gefolgt von einem kleinen oder großenx
, gefolgt von einem oder mehreren Zeichen in den Bereichen0-9
,a-f
oderA-F
.
input()¶
Wie könnt ihr mit der
input()
-Funktion String- und Integer-Werte erhalten?>>> year_birth = input("Geburtsjahr: ") Geburtsjahr: 1964 >>> type(year_birth) <class 'str'> >>> year_birth = int(input("Geburtsjahr: ")) Geburtsjahr: 1964 >>> type(year_birth) <class 'int'>
Wie wirkt es sich aus, wenn ihr
int()
nicht verwendet um den Aufruf voninput()
für Integer-Eingaben zu verwenden?>>> import datetime >>> current = datetime.datetime.now() >>> year = current.year >>> year_birth = input("Geburtsjahr? ") Geburtsjahr? 1964 >>> age = year - year_birth Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for -: 'int' and 'str'
Könnt ihr den Code so abändern, dass er eine Fließkommazahl akzeptiert?
>>> import datetime >>> current = datetime.datetime.now() >>> year = current.year >>> year_birth = float(input("Geburtsjahr: ")) Geburtsjahr: 1964 >>> type(year_birth) <class 'float'>
Was passiert, wenn ihr einen falschen Werttyp eingebt?
>>> import datetime >>> current = datetime.datetime.now() >>> year = current.year >>> year_birth = int(input("Geburtsjahr: ")) Geburtsjahr: Schaltjahr Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: 'Schaltjahr'
Schreibt den Code, um für drei User jeweils nach Namen und Alter zu fragen. Nachdem die Werte eingegeben wurden, fragt nach einem der Namen und gebt das zugehörige Alter aus.
>>> personal_data = {} >>> for i in range(3): ... name = input("Name? ") ... age = int(input("Age? ")) ... personal_data[name] = age ... Name? Veit Age? 60 Name? Tim Age? 35 Name? Monique Age? 37 >>> who = input("Who? ") Who? Veit >>> print(personal_data[who]) 60
Schleifen¶
Entfernt aus der Liste
x = [ -2, -1, 0, 1, 2, 3]
, alle negativen Zahlen.>>> x = [-2, -1, 0, 1, 2, 3] >>> pos = [] >>> for i in x: ... if i >= 0: ... pos.append(i) ... >>> pos [0, 1, 2, 3]
Welche List-Comprehension würdet ihr verwenden, um zum selben Ergebnis zu kommen?
>>> x = [-2, -1, 0, 1, 2, 3] >>> pos = [i for i in x if i >= 0] >>> pos [0, 1, 2, 3]
Wie würdet ihr die Gesamtzahl der negativen Zahlen in der Liste
[-[1, 0, 1], [-1, 1, 3], [-2, 0, 2]]
zählen?>>> x = [[-1, 0, 1], [-1, 1, 3], [-2, 0, 2]] >>> neg = 0 >>> for row in x: ... for col in row: ... if col < 0: ... neg += 1 ... >>> neg 3
Erstellt einen Generator, der nur ungerade Zahlen von 1 bis 10 liefert.
Tipp
Eine Zahl ist ungerade, wenn bei der Division durch 2 ein Rest übrig bleibt; also wenn
% 2
wahr ist.>>> x = (x for x in range(10) if x % 2) >>> for i in x: ... print(i) ... 1 3 5 7 9
Schreibt ein Dict mit den Kantenlängen und Volumen von Würfeln.
>>> {x: x**3 for x in range(1, 5)} {1: 1, 2: 8, 3: 27, 4: 64}
Exceptions¶
Schreibt Code, der zwei Zahlen erhält und die erste Zahl durch die zweite dividiert. Prüft, ob der
ZeroDivisionError
auftritt, wenn die zweite Zahl0
ist, und fangt diese ab.>>> x = int(input("Please enter an integer: ")) Please enter an integer: 7 >>> y = int(input("Please enter an integer: ")) Please enter an integer: 6 >>> try: ... z = x / y ... except ZeroDivisionError as e: ... print("It cannot be divided by 0!") ... >>> z 1.1666666666666667 >>> y = int(input("Please enter an integer: ")) Please enter an integer: 0 >>> try: ... print("It cannot be divided by 0!") ... except ZeroDivisionError as e: ... print("It cannot be divided by 0!") ... It cannot be divided by 0!
Wenn
MyError
vonException
erbt, was ist dann der Unterschied zwischenexcept Exception as e
undexcept MyError as e
?Die erste fängt jede Ausnahme ab, die von
Exception
erbt, während die zweite nurMyError
-Ausnahmen abfängt.Schreibt ein einfaches Programm, das eine Zahl erhält und dann die Anweisung
assert()
verwendet, um eineException
auszulösen, wenn die Zahl0
ist.>>> x = int(input("Please enter an integer that is not zero: ")) Please enter an integer that is not zero: 0 >>> assert x != 0, "The integer must not be zero." Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: The integer must not be zero.
Schreibt eine benutzerdefinierte Ausnahme
Outliers
, die eineException
auslöst, wenn die Variablex
größer oder kleiner als3
ist?>>> class Outliers(Exception): ... pass ... >>> x = -4 >>> if abs(x) > 3: ... raise Outliers(f"The value {x} is an outlier") ... Traceback (most recent call last): File "<stdin>", line 2, in <module> Outliers: The value -4 is an outlier
Handelt es sich bei der Überprüfung, ob ein Objekt eine Liste ist (Check: Listen) um eine Programmierung im Stil von LBYL oder EAFP?
Das ist LBYL-Programmierung. Erst wenn ihr
append()
einemtry... except
-Block packt undTypeError
-Exceptions abfangt, wird es etwas mehr EAFP.
Parameter¶
Schreibt eine Funktion, die eine beliebige Anzahl von unbenannten Argumenten annehmen und deren Werte in umgekehrter Reihenfolge ausgeben kann?
>> def my_func(*params): ... for i in reversed(params): ... print(i) ... >>> my_func(1, 2, 3, 4) 4 3 2 1
Variablen¶
Angenommen,
x = 1
,func()
setze die lokale Variablex
auf2
undgfunc()
die globale Variablex
auf3
, welchen Wert nimmtx
an, nachdemfunc()
undgfunc()
durchlaufen wurden?>>> x = 1 >>> def func(): ... x = 2 ... >>> def gfunc(): ... global x ... x = 3 ... >>> func() >>> x 1 >>> gfunc() >>> x 3
Module¶
Wenn ihr ein Modul
my_math
erstellt habt, das eine Funktiondivide()
enthält, welche Möglichkeiten gibt es, diese Funktion zu importieren und dann zu verwenden? Was sind die Vor- und Nachteile der einzelnen Möglichkeiten?>>> import my_math >>> my_math.divide(..., ...)
>>> from my_math import divide >>> divide(..., ...)
Die erste Lösung wird oft bevorzugt, da es keinen Konflikt zwischen den Bezeichnern in
my_math
und dem importierenden Namespace geben wird. Diese Lösung ist jedoch ein wenig aufwändiger.Eine Variable
min
ist im Modulscope.py
enthalten. In welchem der folgenden Kontexte kannmin
verwendet werden?Mit dem Modul selbst
Innerhalb der Funktion
scope()
des ModulsInnerhalb eines Skripts, das das Modul
scope.py
importiert hat
und 2., aber nicht 3.
Packt die Funktionen, die ihr am Ende von Dekoratoren erstellt habt, als eigenständiges Modul. Dabei soll die Funktionen zunächst lediglich von einem anderen Skript aus vollständig nutzbar sein.
example_mod.py¶from functools import wraps def my_decorator(f): @wraps(f) def wrapper(*args, **kwargs): """Wrapper docstring""" print("Call decorated function") return f(*args, **kwargs) return wrapper @my_decorator def example(): """Example docstring""" print("Call example function")
my_script.py¶from example_mod import example print(example.__name__) print(example.__doc__)
Macht euer Modul ausführbar.
--- /home/docs/checkouts/readthedocs.org/user_builds/python-basics-tutorial-de/checkouts/latest/docs/appendix/example_mod.py +++ /home/docs/checkouts/readthedocs.org/user_builds/python-basics-tutorial-de/checkouts/latest/docs/appendix/example_mod2.py @@ -15,3 +15,8 @@ def example(): """Example docstring""" print("Call example function") + + +if __name__ == "__main__": + print(example.__name__) + print(example.__doc__)
Schreibt eure Version des
wc
-Dienstprogramms so um, dass es sowohl die Unterscheidung zwischen Bytes und Zeichen als auch die Möglichkeit, aus Dateien und von der Standardeingabe zu lesen, implementiert.--- /home/docs/checkouts/readthedocs.org/user_builds/python-basics-tutorial-de/checkouts/latest/docs/modules/wcargv.py +++ /home/docs/checkouts/readthedocs.org/user_builds/python-basics-tutorial-de/checkouts/latest/docs/modules/wcargv_stdin.py @@ -1,27 +1,50 @@ -"""wc module. Contains function: words_occur()""" +"""Reads a file or stdin and returns the number of lines, words and characters – +similar to the UNIX wc utility.""" import sys -def words_occur(): - """words_occur() - count the occurrences of words in a file.""" - # Prompt user for the name of the file to use. - file_name = sys.argv.pop() - # Open the file, read it and store its words in a list. - with open(file_name, "r") as f: - word_list = f.read().split() - # Count the number of occurrences of each word in the file. - occurs_dict = {} - for word in word_list: - # increment the occurrences count for this word - occurs_dict[word] = occurs_dict.get(word, 0) + 1 - # Print out the results. - print( - f"File {file_name} has {len(word_list)} words, " - f"{len(occurs_dict)} are unique:" - ) - print(occurs_dict) +def main(): + """Count the occurrences of lines, words and characters in a file or + stdin.""" + # initialize counts + line_count = 0 + word_count = 0 + char_count = 0 + filename = None + option = None + if len(sys.argv) > 1: + params = sys.argv[1:] + if params[0].startswith("-"): + # If there are several parameters, the first one is taken as an option + option = params.pop(0).lower().strip() + if params: + filename = params[0] + file_mode = "r" + if option == "-c": + file_mode = "rb" + if filename: + infile = open(filename, file_mode) + else: + infile = sys.stdin + with infile: + for line in infile: + line_count += 1 + char_count += len(line) + words = line.split() + word_count += len(words) + if option in ("-c", "-m"): + print(f"{filename} has {char_count} characters.") + elif option == "-w": + print(f"{filename} has {word_count} words.") + elif option == "-l": + print(f"{filename} has {line_count} lines.") + else: + # print the answers using the format() method + print( + f"{filename} has {line_count} lines, {word_count} words and {char_count} characters." + ) if __name__ == "__main__": - words_occur() + main()
Klassen¶
Schreibt eine
Triangle
-Klasse, die auch die Fläche berechnen kann.class Triangle: def __init__(self, width, height): self.width = width self.height = height def area(self): return 0.5 * self.width * self.height
Methoden¶
Schreibt eine Klassenmethode, die ähnlich wie
circumferences()
ist, aber die Gesamtfläche aller Kreise zurückgibt.def area(self): return self.diameter**2 / 4 * self.__class__.pi @classmethod def areas(cls): """Class method to sum all areas.""" careasum = 0 for c in cls.circles: careasum = careasum + c.area() return careasum
Klassen und Vererbung¶
Schreibt den Code für eine
Triangle
-Klasse um, sodass sie vonForm
erbt.>>> class Form: ... def __init__(self, x=0, y=0): ... self.x = x ... self.y = y ... >>> class Triangle(Form): ... def __init__(self, width=1, height=1, x=0, y=0): ... super().__init__(x, y) ... self.length = length ... self.height = height ...
Wie würdet ihr den Code schreiben, um eine Methode
area()
für die KlasseTriangle
hinzuzufügen? Sollte die Methodearea()
in die BasisklasseForm
verschoben und anCircle
,Square
undTriangle
vererbt werden? Welche Probleme würde diese Änderung verursachen?Es ist sinnvoll, die
area()
-Methode in eineTriangle
-Klasse zu packen; aber sie inForm
zu packen, wäre nicht sehr hilfreich, weil verschiedene Typen vonForm
ihre eigenen Berechnungen der Fläche haben. Jede abgeleitete Form würde ohnehin die Basismethodearea()
überschreiben.
Datentypen als Objekte¶
Was wäre der Unterschied zwischen der Verwendung von
type()
undisinstance()
in Check: Listen?Mit
type()
würdet ihr nur Listen erhalten, nicht aber Instanzen von Listen.
Private Variablen und Methoden¶
Ändert den Code der Klasse
Triangle
, um die Dimensionsvariablen privat zu machen. Welche Einschränkung wird diese Änderung für die Verwendung der Klasse mit sich bringen?>>> class Triangle: ... def __init__(self, x, y): ... self.__x = x ... self.__y = y ...
Die Dimensionsvariablen sind außerhalb der Klasse nicht mehr über
.x
und.y
verfügbar.Aktualisiert die Dimensionen der Klasse
Triangle
, damit sie Eigenschaften mit Getter- und Setter-Methoden sind, die keine negativen Größen zulassen.>>> class Triangle: ... def __init__(self, x, y): ... self.__x = x ... self.__y = y ... @property ... def x(self): ... return self.__x ... @x.setter ... def x(self, new_x): ... if new_x >= 0: ... self.__x = new_x ... @property ... def y(self): ... return self.__y ... @y.setter ... def y(self, new_y): ... if new_y >= 0: ... self.__y = new_y ... >>> t1 = Triangle(-2, 2) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 6, in __init__ ValueError: The number must be greater or equal to zero. >>> t1 = Triangle(2, 2) >>> t1.x = -2 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 13, in x ValueError: The number must be greater or equal to zero. >>> t1.x = 3 >>> t1.x 3
Verteilungspaket erstellen¶
Wenn ihr ein Paket für eine Aufgabenverwaltung erstellen wollt, das die Aufgaben in eine Datenbank schreibt und über ein Python-API und eine Befehlszeilenschnittstelle (CLI bereitstellt, wie würdet ihr die Dateien strukturieren?
Das Paket führt drei Arten von Aktionen durch:
Zugriffe auf die Datenbank
Bereitstellen einer Python-API
Bereitstellen einer Befehlszeilenschnittstelle
├── README.rst ├── pyproject.toml └── src └── items ├── __init__.py ├── api.py ├── cli.py └── db.py
Überlegt euch, wie ihr die oben genannten Aufgaben erledigen wollt. Welche Bibliotheken und Module fallen euch ein, die diese Aufgabe erfüllen könnten? Skizziert den Code für die Module der Python-API, der Befehlszeilenschnittstelle und der Datenbankanbindung.
Ich würde in
src/items/db.py
eineDB
-Klasse für die Kommunikation mit der Datenbank erstellen, im folgenden Beispiel zu tinydb:import tinydb class DB: def __init__(self, db_path, db_file_prefix): self._db = tinydb.TinyDB( db_path / f"{db_file_prefix}.json", create_dirs=True ) def create(self, item: dict): """Create an item Returns: id: The items id. """ return id def read(self, id: int): """Reads an item. Args: id (int): The item id of an item. Returns: item: The item object.""" return item def update(self, id: int, mods): """Update an item in the database. Args: id (int): The item id of an item. mods (Item): The modifications to be made to this item. """ self._db.update(changes, doc_ids=[id]) def delete(self, id: int): """Deletes an item in the database. Args: id (int): The item id of an item. """ self._db.remove(doc_ids=[id]) def close(self): """Closes the database connection.""" self._db.close()
Dann würde ich in
src/items/api
dataclass()
verwenden, um eineItem
-Klasse zu erstellen:from dataclasses import dataclass, field @dataclass class Item: summary: str = None owner: str = None state: str = "todo" id: int = field(default=None, compare=False) class ItemsException(Exception): pass class ItemsDB: def __init__(self, db_path): self._db_path = db_path self._db = DB(db_path, ".items_db") def add_item(self, item: Item): return def get_item(self, item: Item): return def update_item(self, item: Item): return def delete_item(self, item: Item): return def close(self): self._db.close() def path(self): return self._db_path
In
src/items/__init__.py
werden dannItemsException
Item
undItemsDB
bereitgestellt:from .api import ItemsException, Item, ItemsDB
Siehe auch
Ein vollständiges Beispiel findet ihr in github.com/veit/items.
Dateien¶
Verwendet die Funktionen des
os
-Moduls, um einen Pfad zu einer Datei namensexample.log
zu nehmen und einen neuen Dateipfad im selben Verzeichnis für eine Datei namensexample.log1
zu erstellen.>>> import os >>> path = os.path.abspath("example.log") >>> print(path) /Users/veit/python-basics-tutorial-de/example.log >>> new_path = f"{path}2" >>> print(new_path) /Users/veit/python-basics-tutorial-de/example.log2
Welche Bedeutung hat das Hinzufügen von
b
als Parameter vonopen()
?Dadurch wird die Datei im Binärmodus geöffnet, d.h. es werden Bytes und keine Zeichen gelesen und geschrieben.
Öffnet eine Datei
my_file.txt
und fügt zusätzlichen Text am Ende der Datei ein. Welchen Befehl würdet ihr verwenden, ummy_file.txt
zu öffnen? Welchen Befehl würdet ihr verwenden, um die Datei erneut zu öffnen und von Anfang an zu lesen?>>> with open("my_file", "a") as f: ... f.write("Hi, Pythonistas!\n") ... 17 >>> with open("my_file") as f: ... print(f.readlines()) ... ['Hi, Pythonistas!\n', 'Hi, Pythonistas!\n']
Welche Anwendungsfälle könnt ihr euch vorstellen, in denen das
struct
-Modul für das Lesen oder Schreiben von Binärdaten nützlich wäre?beim Lesen und Schreiben einer Binärdatei
beim Lesen von einer externen Schnittstelle, wobei die Daten genau so gespeichert werden sollen, wie sie übermittelt wurden
Warum könnte pickle für die folgenden Anwendungsfälle geeignet sein oder auch nicht:
Speichern einiger Zustandsvariablen von einem Durchlauf zum nächsten ✅
Aufbewahren von Auswertungsergebnissen ❌, da Pickle abhängig von der jeweiligen Python-Version sind
Speichern von Benutzernamen und Passwörtern ❌, da Pickle nicht sicher sind
Speichern eines großen Wörterbuchs mit englischen Begriffen ❌, da der gesamte Pickle in den Speicher geladen werden müsste
Wenn ihr euch die Manpage für das wc-Dienstprogramm anseht, seht ihr zwei Befehlszeilenoptionen:
-c
zählt die Bytes in der Datei
-m
zählt die Zeichen, die im Falle einiger Unicode-Zeichen zwei oder mehr Bytes lang sein können
Außerdem sollte unser Modul, wenn eine Datei angegeben wird, aus dieser Datei lesen und sie verarbeiten, aber wenn keine Datei angegeben wird, sollte es aus
stdin
lesen und verarbeiten.Siehe auch
Wenn ein Kontext-Manager in einem Skript verwendet wird, das mehrere Dateien liest und/oder schreibt, welche der folgenden Ansätze wäre eurer Meinung nach am besten?
Legt das gesamte Skript in einen Block, der von einer
with
-Anweisung verwaltet wird.Verwendet eine
with
-Anweisung für alle Lesevorgänge und eine weitere für alle Schreibvorgänge.Verwendet jedes Mal eine
with
-Anweisung, wenn ihr eine Datei lest oder schreibt, d.h. für jede Zeile.Verwendet für jede Datei, die ihr lest oder schreibt, eine
with
-Anweisung.
Wahrscheinlich ist 4. der beste Ansatz, da ein Teil der Aufgabe des Kontextmanagers beim Dateizugriff darin besteht, sicherzustellen, dass eine Datei geschlossen ist.
Archiviert
*.txt
-Dateien aus dem aktuellen Verzeichnis im Verzeichnisarchive
als*.zip
-Dateien mit dem aktuellen Datum als Dateiname.Welche Module benötigt ihr hierfür?
Schreibt eine mögliche Lösung.
1>>> import datetime 2>>> import pathlib 3>>> import zipfile 4>>> file_pattern = "*.txt" 5>>> archive_path = "archive" 6>>> today = f"{datetime.date.today():%Y-%m-%d}" 7>>> cur_path = pathlib.Path(".") 8>>> paths = cur_path.glob(file_pattern) 9>>> zip_path = cur_path.joinpath(archive_path, today + ".zip") 10>>> zip_file = zipfile.ZipFile(str(zip_path), "w") 11>>> for path in paths: 12... zip_file.write(str(path)) 13... path.unlink() 14...
- Zeile 9
erstellt den Pfad zur ZIP-Datei im Archivverzeichnis.
- Zeile 10
öffnet das neue ZIP-Dateiobjekt zum Schreiben;
str()
wird benötigt, um einen Pfad in eine Zeichenkette umzuwandeln.- Zeile 12
schreibt die aktuelle Datei in die Zip-Datei.
- Zeile 13
entfernt die aktuelle Datei aus dem Arbeitsverzeichnis.