Erste Schritte mit Python

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
funcoder
User
Beiträge: 3
Registriert: Mittwoch 11. Dezember 2013, 15:52

Hallo,

ich möchte gerne mich mit Python befassen und versuche die ersten Schritte zu gehen. Eine Menge Doku hab ich nun hinter mir, aber ich würde gerne gleich mit einen Praxisbeispiel weitermachen und wende mich daher gleich mal an Euch.

Ich würde gerne folgendes realisieren:
- eine DB mit mehreren Tabellen (Präfix name_jahr+kw)
- eine Liste mit Jahreszahlen+KW erstellen

In der BASH gehe ich wie folgt vor:

Code: Alles auswählen

#!/bin/bash
mysql database -e 'show tables' | grep -o '[0-9].*' | sort | uniq
Schwups, eine kurze List mit z.B.: 201311-201342 wäre jetzt erstellt.

Wie würde ich, bzw. Ihr bei Python vorgehen?

Einen DB-Zugriff bekomme ich hin, damit auch eine Liste der Tabellen:

Code: Alles auswählen

#!/usr/bin/python

import MySQLdb

connection = MySQLdb.connect(
    host = 'localhost',
    user = 'root',
    passwd = '')

cursor = connection.cursor()

cursor.execute("USE database")

cursor.execute("SHOW TABLES")

for (table_name,) in cursor:
    print(table_name)
Aber wie gehe ich nun das Filtern und Sortieren dieser Liste an? Bzw. fange ich hier schon falsch an?

BG
BlackJack

@funcoder: Der eigentliche Fehler liegt vor all den Abfragen: Tabellennamen die Daten enthalten. Wer kommt den auf so einen furchtbaren Datenbankentwurf. :shock:

Ansonsten arbeite doch einfach mal ein Grundlagentutorial zu Python durch. Du brauchst das wissen was dort über Grunddatentypen wie Zeichenketten, Listen, Mengen und so weiter vermittelt wird. Reguläre Ausdrücke stellt das `re`-Modul bereit, man käme aber auch mit „slicing”-Syntax und einer Methode auf Zeichenketten aus, weil man ja weiss wie viele Zeichen die gesuchte Ziffernfolge lang ist und das sie am Ende steht.

Die Klammern bei der ``print``-Anweisung gehören da übrigens nicht hin. Das kann sehr verwirrend werden, denn ``print a, b`` bedeutet etwas anderes als ``print(a, b)`` in Python 2.
funcoder
User
Beiträge: 3
Registriert: Mittwoch 11. Dezember 2013, 15:52

Danke für die Antwort.

Mir geht es jetzt nicht darum das Problem der Datenbankabfrage zu lösen - das ist nur ein simples Beispiel. Es könnte sich ja genauso gut um eine List mit Dateien(-namen) handeln, oder eine Datei mit Inhalt. Worauf ich hinaus will ist folgendes:
- wie löse ich in Python Aufgaben wie "grep", "sort" oder "uniq"?

In den Tutorials lese ich ständig "hier IF-Abfrage", "Schleifen", etc... aber das hilft mir bei der "normalen" Arbeit jetzt wenig. Bis jetzt löse ich alles mit der BASH und wollte mich jetzt weiterentwickeln und stehe vor so simplen Aufgaben wie "filtere einfach alle doppelten Einträge aus der Summe raus". Hier benötige ich einen Denkanstoß
Zuletzt geändert von funcoder am Donnerstag 12. Dezember 2013, 10:36, insgesamt 1-mal geändert.
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

funcoder hat geschrieben:Hier benötige ich einen Denkanstoß
Den hast Du ja bekommen: Grunddatentypen, Slicing, Methoden auf Zeichenketten, 're'-Modul
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
BlackJack

@funcoder: Du wirst Dir über die Schritte klar werden müssen die innerhalb der Shellprogramme gemacht werden und das sind unter anderem Schleifen und ``if``-Abfragen. Du willst die ja nachprogrammieren.

Beispiel ``grep``: Das geht in einer Schleife über die einzelnen Zeilen, wendet auf jede den regulären Ausdruck an und falls er matcht wird die Zeile ins Ergebnis aufgenommen. Mit ``-o`` nur der Teil der gematcht hat. Da musst Du Dich mit Python nun mit Dateiobjekten beschäftigen, denn dort kommen die Zeilen her, und mit dem `re`-Modul, denn das stellt in Python Objekte und Funktionen für reguläre Ausdrücke zur Verfügung, und entweder mit der ``for``-Schleife und der ``if``-Anweisung, oder „list comprehension”, oder Generatorausdrücken, oder der `filter()`-Funktion, oder `itertools.ifilter()`. Und vielleicht mit ``lambda``-Ausdrücken.

Für das konkrete gegebene Problem kämen aber auch statt dem `re`-Modul Operationen auf Zeichenketten in Frage.

Der Denkanstoss ist erst einmal die Grundlagen zu lernen, also all die Grunddatentypen und was man damit machen kann. Aus diesem Werkzeugkasten wählt man dann ja aus was man zum lösen eines Problems verwendet. Und gezielt nur das zu lernen was man für ein konkretes Problem benötigt, funktioniert nicht weil man ja wenn man nichts aus dem Werkzeugkasten kennt, nicht weiss was das ist was man gezielt lernen müsste.

Doppelte Objekte kann man auf mehrere Arten aussortieren, die sich in ihren Eigenschaften unterscheiden.

Das einfachste wäre schlicht der `set()`-Datentyp. In diesem Containerdatentyp gibt es aber keine Ordnung auf den enthaltenen Elementen. Man bekommt die also nicht in einer garantierten Reihenfolge wieder aus dem Container-Objekt heraus. Da müsste man das sortieren also vielleicht als Schritt danach machen.

Wenn die Reihenfolge der Eingabe beibehalten werden soll gibt es auch mindestens zwei Möglichkeiten. Wenn die Eingabedaten nach gleichen Objekten gruppiert sind, kann man `itertools.groupby()` verwenden um eine Lösung zu schreiben. Falls das nicht garantiert ist, könnte man sich in einem `set()` merken welche Werte man schon gesehen hat und nur die ins Ergebnis aufnehmen die noch nicht vorkamen.

Einen Bash-Einzeiler in einer allgemeinen Programmiersprache umzusetzen macht vielleicht mehr Arbeit als Du Dir das vorgestellt hast. Du musst ja zumindest die Untermenge an Funktionalität nachprogrammieren die Du von den Programmen in der Shell verwendest. ``grep``, ``sort``, und ``uniq`` sind in C geschrieben und mehr als ein paar Zeilen lang. Das geht in Python zwar deutlich kompakter, einfacher, und sicherer als in C, aber man muss trotzdem das ausprogrammieren was *in* diesen Programmen steckt.

Dafür bekommt man gegenüber der Shell eine deutlich einheitlichere Syntax, einen Haufen Datentypen, Klassen, eine umfangreiche Standardbibliothek, und viele Module von Drittanbietern. Ja nach dem was man mit den Jahreszahlen und Kalenderwochen machen möchte, kann man zum Beispiel beide Informationen aus der Zeichenkette trennen und in Zahlen umwandeln und die dann als Tupel zusammenfassen. Oder mit dem `datetime`-Modul in Datumsobjekte umwandeln und weiterverarbeiten.
funcoder
User
Beiträge: 3
Registriert: Mittwoch 11. Dezember 2013, 15:52

@BlackJack: ahhh, prima. Das hilft mir schon etwas weiter. Ich muss also alles nachbauen und sozusagen selber erstellen - bin wohl etwas verwöhnt von der BASH und die entsprechend umfangreiche Auswahl der Tools. Ich hatte irgendwie erwartet das es für solche "Probleme" evtl. vorgefertigte Wege/Routinen gibt - evtl. etwas sehr naiv von mir.
Aus diesem Werkzeugkasten wählt man dann ja aus was man zum lösen eines Problems verwendet
Genau hier liegt wohl mein Problem. Ich habe eigentlich keine Probleme die ich nicht mit der BASH ganz simpel erschlagen könnte, also deswegen dieses "ich-baue-etwas-nach-was-ich-schon-habe-in-bash". Sprich es fehlen die sinnvollen Aufgaben um sich weiterzuentwickeln und die Motivation aufrecht zu erhalten. Die Aufgaben aus irgendwelchen Tutorials (baue mit if-Abfragen ein Zahlenratespiel...) bringen mich so erst einmal nicht weiter.

BG
BlackJack

@funcoder: Ein Ziel ist für die Motivation in der Tat nicht unwichtig.

Die Motivation von der Shell zu einer allgemeineren Programmiersprache zu wechseln kommt ja meistens dann, wenn man etwas haben möchte was in Bash gar nicht oder nur sehr umständlich oder instabil lösbar ist. Also ist das Nachbauen von einfachen Shell-Skripten vielleicht nicht das richtige.

Es gibt sogar Module die das einfacher machen, aber wirklich gewonnen hat man dabei ja auch nichts gegenüber einem Shell-Skript das man schon hat.

Wenn ein Python-Programmierer das Ausgangsproblem umsetzen sollte, käme da vielleicht so etwas bei heraus (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
from contextlib import closing
from pprint import pprint
import MySQLdb

#: Four characters for year and two for the week number.
WEEK_SUFFIX_LENGTH = 6


def main():
    connection = MySQLdb.connect(
        host='localhost', user='root', passwd='', database='database'
    )
    with closing(connection):
        cursor = connection.cursor()
        cursor.execute('SHOW TABLES')
        table_name_suffixes = (row[0][:-WEEK_SUFFIX_LENGTH] for row in cursor)
        weeks = sorted(
            set(
                (int(week_string[:4]), int(week_string[4:]))
                for week_string in table_name_suffixes
                if week_string.isdigit()
            )
        )
    pprint(weeks)


if __name__ == '__main__':
    main()
Wobei hier die Werte auch in Tupel mit Jahreszahl und Wochennummer aufgeteilt werden. Was man noch hätte machen können ist das umwandeln in `datetime.date`-Objekte wobei man so auch ungültige Werte herausfiltern könnte. Denn hier besteht ja die Gefahr das auch Tabellen zum Ergebnis beitragen deren Name zwar mit 6 Ziffern enden, die aber gar nicht Jahr und Woche repräsentieren.
Antworten