[gelöst] Bessere Lösung für weiterlaufenden Zähler?

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.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Ich stehe gerade vor folgendem Problem, zu dem ich auch mit meinen bisher getesteten Suchbegriffen nichts in der (zugegebenermassen fluechtigen) Suche gefunden habe:
Ich möchte in einem umfangreicheren Porgramm immer, wenn ich eine bestimmte Operation durchgeführt habe, etwas abspeichern. Ich bin aber zu faul, jedesmal den Namen der Datei mit Hand einzugeben. Ich möchte also fortlaufende Dateinamen "produzieren" können. Ich bin derzeit bei folgender Lösung, die mir etwas unglücklich erscheint, auch wenn sie funktioniert:
Am Programmanfang steht:

Code: Alles auswählen

import os, sys, os.path, Image, ImageOps, copy
...
# Zaehler erzeugen:
Zaehlerdatei = open("Zaehler.txt", "w")
Zaehlerdatei.write("1")
Zaehlerdatei.close()
und dann weiter "hinten":

Code: Alles auswählen

def ExportMuesterchen(i, j, image, Bildbreite, Bildhoehe, Mustername, Mustergroesse):
    """ exportiert einen Bildausschnitt, dessen Größe durch "Mustergröße" vorgegeben ist.
    Bereiche, die näher am Rand liegen, werden abgeschnitten!
    """
    (startl, starto, endr, endu) = Ecken_bestimmen(i, j, Bildbreite, Bildhoehe, Mustergroesse)
    Zaehlerdatei = open("Zaehler.txt", "r")
    Zaehler = int(Zaehlerdatei.readline())
    Zaehlerdatei.close()
    print "Zaehler: ", Zaehler
    Zaehler += 1
    Zaehlerdatei = open("Zaehler.txt", "w")
    Zaehlerdatei.write(str(Zaehler))
    Zaehlerdatei.close()

    Muesterchen = image.crop((startl, starto, endr, endu))
    print "Muesterchen: ", Muesterchen.size
    Bildnummer = str(Zaehler)
    Dateityp = ".bmp"
    Bildname = os.path.join(Mustername) + Bildnummer + Dateityp
    Muesterchen.save(Bildname, "BMP")
Kann man das irgendwie eleganter lösen?
Zuletzt geändert von merlin_emrys am Montag 26. Februar 2007, 16:08, insgesamt 1-mal geändert.
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Ich weiß nicht ganz, was du machen möchtest aber du könntest eine fortlaufende Dateinamen-Nummerierung folgendermaßen bewerkstelligen
(ungetestet und eher Beispielhaft gemeint!)

Code: Alles auswählen

import os

class Bildbenenner(object):
    def __init__(self):
        self.zaehler = 0
        self.path = 'gib/hier/den/pfad/an'

    def write_file(self, file_type, data):
        self.zaehler += 1
        f = open(os.path.join(self.path, 'bild_nr%d.%s' % (self.zaehler, file_type)))
        f.write(data)
        f.close()
Ich weiß net, ob es das ist, was du wolltest....


MfG EnTeQuAk
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

EnTeQuAk hat geschrieben: Ich weiß net, ob es das ist, was du wolltest....
Ich zugegebenermassen auch nicht... Das liegt in meinem Fall aber daran, dass ich nicht weiss, wie man mit "class"-Sachen umgeht. Will sagen: Ich wüsste nichtmal, wie ich das in meinen Muesterchenexport einbauen sollte, wenn ich es unverändert übernehmen könnte...

self.path dürfte "hier" sein, also mehr oder minder nicht existent. Dafür müsste ich "bild_nr" durch einen variablen Teil ersetzen, aber das könnte irgendwie in der Form

Code: Alles auswählen

f = open(os.path.join(self.path, '%s%d.%s' % (Mustername, self.zaehler, file_type)))
machbar sein?

Unklar ist mir, warum die Datei erst geöffnet wird; ich bin mir nicht sicher, ob ich dann etwas sinnvolles zum Hineinschreiben habe. Ginge auch der direkte Weg

Code: Alles auswählen

Muesterchen.save(os.path.join(self.path, '%s%d.%s' % (Mustername, self.zaehler, file_type)), "BMP")
und an anderer Stelle

Code: Alles auswählen

AnderesBild.save(os.path.join(self.path, '%s%d.%s' % (Mustername, self.zaehler, file_type)), "BMP")
oder beisst sich da dann was und das Bild gehört an die Stelle von "data"?
Dann müsste es sowas wie

Code: Alles auswählen

write_file(self, bmp, Muesterchen)
geben? Wie vereinbare ich das dann mit dem "Wunsch" der Python Imaging Library, zum Speichern von Bildern die Formulierung

Code: Alles auswählen

Bild.save(Bildname.Dateierweiterung, "DATEITYP")
zu bekommen?

Bitte um Entschuldigung, ob Klassen liegen derzeit noch ausserhalb meines Programmierhorizonts... :-(
BlackJack

So wie es im ersten Beitrag aussieht fängt das Programm bei jedem Lauf wieder mit 1 an? Dann ist das speichern überflüssig und man könnte `itertools.count()` benutzen um die Zahlen zu erzeugen:

Code: Alles auswählen

In [45]: counter = itertools.count(1)

In [46]: counter.next()
Out[46]: 1

In [47]: counter.next()
Out[47]: 2

In [48]: counter.next()
Out[48]: 3

In [49]: counter.next()
Out[49]: 4
Und man sollte die Zahlen in den Dateinamen rechts mit ein paar 0en auffüllen, dann werden die Namen alphabetisch "richtig" sortiert, wenn es mehr als 10 werden.

Code: Alles auswählen

In [50]: '%05d' % 42
Out[50]: '00042'

In [51]: '%05d' % counter.next()
Out[51]: '00005'
Ist `Mustername` eine Sequenz von Zeichenketten oder nur eine einzelne? Im ersten Fall wäre der Name nicht so passend, im zweiten ist `os.path.join(Mustername)` überflüssig.

Edit: `os.path` braucht man nicht importieren, das ist in `os` schon inklusive.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Hallo merlin_emrys...

also ich denke, was du tun moechtest ist simplerweise das hier:

Code: Alles auswählen

bild01.bmp
bild02.bmp
bild03.bmp
bild04.bmp
bild05.bmp
#usw
...also einfach dafuer sorgen, dass dein Programm die Dateinamen jedesmal mit einer um eins erhoehten Nummer versieht.

Das wuerde ich so anstellen (ich programmiere es Prozedural, okay ;) ):

Code: Alles auswählen

bitmaps = [os.path.splitext(bmp)[0] for bmp in os.listdir(".") if bmp.endswith(".bmp")]

#vorausgesetzt die Dateien enden mit einer zweistelligen Nummer:
bildnr = "%2d" %(int(bitmaps[-1][-2:])+1)

#bildbearbeitungskrams...
bildname = os.path.join(mustername)+bildnr+endung
Bild.save(bildname, "BMP")
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
BlackJack

`os.listdir()` liefert die Dateinamen in einer willkürlichen Reihenfolge und nicht sortiert und man müsste bei jeder neuen Datei immer wieder alle Dateinamen durchgehen.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

BlackJack hat geschrieben:`os.listdir()` liefert die Dateinamen in einer willkürlichen Reihenfolge und nicht sortiert...
okay, dann machen wir noch ein:

Code: Alles auswählen

bitmaps.sort()
in Zeile 3 :)
BlackJack hat geschrieben:...und man müsste bei jeder neuen Datei immer wieder alle Dateinamen durchgehen.
Das koennte man umgehen, indem man sich die letzte Zahl merkt und das Programm hochzaehlen laesst. Also setzt man irgendwie einen Schalter der mir sagt: Ja ich hab schonmal nachgeschaut, was die letzte Datei ist, also zaehle ich die Variable Zaehler jetzt direkt hoch und schaue nicht nochmal, bevor ich die naechste Datei speichere.
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
BlackJack

Das mit dem Sortieren funktioniert nur wenn sich die Namen auch sortieren lassen, d.h. wenn die Zahlen rechts mit 0en aufgefüllt sind. Ausserdem berücksichtigt Dein Quelltext den Namen gar nicht, wenn man also 'spam01.bmp' bis 'spam05.bmp' und 'zikzak01.bmp' bis 'zikzak20.bmp' hat und ein neues 'spam*'-Bild speichern möchte, dann bekommt man 'spam21.bmp' als Ergebnis. Und es gäbe noch den Fall das noch gar kein Bild existiert: `IndexError`.

Code: Alles auswählen

import os


def get_highest_number(names, prefix, postfix, start=1):
    max_number = start
    prefix_length = len(prefix)
    postfix_length = len(postfix)
    for name in names:
        if name.startswith(prefix) and name.endswith(postfix):
            try:
                number = int(name[prefix_length:-postfix_length])
                if number > max_number:
                    max_number = number
            except ValueError:
                pass
        assert max_number >= start
    return max_number


def main():
    print get_highest_number(os.listdir('.'), '_scan', '.png')
Edit: `os.listdir()` aus der Funktion herausgezogen.
Zuletzt geändert von BlackJack am Sonntag 25. Februar 2007, 18:36, insgesamt 1-mal geändert.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

BlackJack hat geschrieben:Ausserdem berücksichtigt Dein Quelltext den Namen gar nicht, wenn man also 'spam01.bmp' bis 'spam05.bmp' und 'zikzak01.bmp' bis 'zikzak20.bmp' hat und ein neues 'spam*'-Bild speichern möchte, dann bekommt man 'spam21.bmp' als Ergebnis. Und es gäbe noch den Fall das noch gar kein Bild existiert: `IndexError`.
oops :oops: ...naja :)
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Wow - danke fuer die vielen Vorschlaege!
BlackJack hat geschrieben:So wie es im ersten Beitrag aussieht fängt das Programm bei jedem Lauf wieder mit 1 an? Dann ist das speichern überflüssig und man könnte `itertools.count()` benutzen um die Zahlen zu erzeugen:

Code: Alles auswählen

In [45]: counter = itertools.count(1)
Ja, das Programm zaehlt jedesmal neu hoch, wenn ich es neu starte. Mein Problem war, dass ich den Zaehler danach nur ueber die txt-Datei in meine Defintion hineinbekommen konnte, ohne dass er jedesmal zurueckgesetzt wurde.

Nebenbei:
BlackJack hat geschrieben:Ausserdem berücksichtigt Dein Quelltext den Namen gar nicht, wenn man also 'spam01.bmp' bis 'spam05.bmp' und 'zikzak01.bmp' bis 'zikzak20.bmp' hat und ein neues 'spam*'-Bild speichern möchte, dann bekommt man 'spam21.bmp' als Ergebnis.
Das ist in meiner Version auch der Fall und stoert mich nicht sonderlich. Im Prinzip bekomme ich die Reihenfolge, in der die verschiedenen Bilder gespeichert wurden, auch ueber die Zeit, zu der sie gespeichert wurden, aber es macht nichts, wenn ihre Nummern das auch nochmal widerspiegeln.
BlackJack hat geschrieben: Und man sollte die Zahlen in den Dateinamen rechts mit ein paar 0en auffüllen, dann werden die Namen alphabetisch "richtig" sortiert, wenn es mehr als 10 werden.
Ja, das sollte ich wirklich einbauen. Derzeit lasse ich die Dateien einfach nach Speicherzeitpunkt sortieren, dann sind sie auch in der richtigen Reihenfolge :-) .
Ich probiere den counter aus, sobald ich wieder an einem Rechner bin, auf dem ich die PIL installiert habe (das ist hier leider nicht der Fall :-( ...)
BlackJack hat geschrieben: Ist `Mustername` eine Sequenz von Zeichenketten oder nur eine einzelne? Im ersten Fall wäre der Name nicht so passend, im zweiten ist `os.path.join(Mustername)` überflüssig.
Das verstehe ich jetzt nicht, vor allem das "nicht so passend". Ich speichere derzeit kleine Pixelmuster ab, um mir anzusehen, nach welcher Systematik ich am besten zwischen zwei Grund-Situationen unterscheide, deshalb habe ich die zugehoerigen Begriffe durch ein "Muster-" oder "Muesterchen-" gekennzeichnet. Das sind dann jeweils einzelne Zeichenketten.
(Wenn Intersse daran besteht, was ich da genauer treibe, kann ich das nocht etwas ausfuehrlicher erlaeutern.)
BlackJack hat geschrieben: Edit: `os.path` braucht man nicht importieren, das ist in `os` schon inklusive.
Oh... danke.
nkoehring hat geschrieben:Das wuerde ich so anstellen (ich programmiere es Prozedural, okay ;) ):

Code: Alles auswählen

bitmaps = [os.path.splitext(bmp)[0] for bmp in os.listdir(".") if bmp.endswith(".bmp")]

#vorausgesetzt die Dateien enden mit einer zweistelligen Nummer:
bildnr = "%2d" %(int(bitmaps[-1][-2:])+1)

#bildbearbeitungskrams...
bildname = os.path.join(mustername)+bildnr+endung
Bild.save(bildname, "BMP")
Das ist auch eine pfiffige Idee - und ich verstehe sogar, wie es funktioniert :-) ! Man muesste allerdings vermutlich, wenn in dem Verzeichnis verschiedene Namen vor der Zahl kommen, den Namensteil vor dem Sortieren abschneiden, andernfalls gibt es vielleicht doch ein Problem, wenn einfach immer wieder das Bild "Zufall01" als Basis fuer das Weiterzaehlen genommen wird... Eventuell werde ich fuer das Hochzaehlen auf BlackJacks Vorschlag mit dem counter zurueckgreifen, aber dies loest vermutlich meine Frage, wie ich verhindern kann, dass bei mehreren Durchlaeufen fuer dasselbe Bild immer wieder dieselben Sicherungskopien unter demselben Namen angelegt werden, was ja irgendwie etwas ueberfluessig ist (und bei grossen Bildern einfach auch Zeit kostet)... Im Moment sage ich jeweils, ob ich eine Kopie haben will, aber ich werde wohl irgendwann dazu uebergehen, einen Programmdurchlauf am Abend zu starten und am Morgen nach Ergebnissen zu sehen; zu dem Zeitpunkt sollte moeglichst alles "von selbst" entschieden werden koennen. Insofern auch dafuer ein glueckliches "Danke!"
nkoehring hat geschrieben: Das koennte man umgehen, indem man sich die letzte Zahl merkt und das Programm hochzaehlen laesst. Also setzt man irgendwie einen Schalter der mir sagt: Ja ich hab schonmal nachgeschaut, was die letzte Datei ist, also zaehle ich die Variable Zaehler jetzt direkt hoch und schaue nicht nochmal, bevor ich die naechste Datei speichere.
Das Problem daran ist, dass ich dafuer irgendwo die Information brauche, auf welchem Wert mein "Zaehler" denn gerade steht?
Hm, also, angesehen habe ich es. Aber dann kommt im Grunde dieselbe Fragenliste, die ich schon als "duemmster anzunehmender Programmierer" an EnTeQuAk geschrieben habe: Mir ist unklar, wie dann der Speicherbefehl auszusehen haette?
BlackJack

merlin_emrys hat geschrieben:
BlackJack hat geschrieben:

Code: Alles auswählen

In [45]: counter = itertools.count(1)
Ja, das Programm zaehlt jedesmal neu hoch, wenn ich es neu starte. Mein Problem war, dass ich den Zaehler danach nur ueber die txt-Datei in meine Defintion hineinbekommen konnte, ohne dass er jedesmal zurueckgesetzt wurde.
Wenn man das selber schreiben und sauber kapseln will, kommt man um eine Klasse oder ein Closure nicht drumherum.
BlackJack hat geschrieben: Ist `Mustername` eine Sequenz von Zeichenketten oder nur eine einzelne? Im ersten Fall wäre der Name nicht so passend, im zweiten ist `os.path.join(Mustername)` überflüssig.
Das verstehe ich jetzt nicht, vor allem das "nicht so passend". Ich speichere derzeit kleine Pixelmuster ab, um mir anzusehen, nach welcher Systematik ich am besten zwischen zwei Grund-Situationen unterscheide, deshalb habe ich die zugehoerigen Begriffe durch ein "Muster-" oder "Muesterchen-" gekennzeichnet. Das sind dann jeweils einzelne Zeichenketten.
Der "nicht so passend"-Fall greift dann ja auch gar nicht, sondern das `os.path.join()` ist einfach überflüssig. Das verbindet mehrere Pfadelemente mit dem für die Plattform passenden Pfadtrenner. Wenn man nur ein Element angibt, dann ist das eine Operation bei der immer wieder nur dieses Element als Ergebnis herauskommt.

Code: Alles auswählen

In [2]: os.path.join('bild.bmp')
Out[2]: 'bild.bmp'

In [3]: os.path.join('spam')
Out[3]: 'spam'

In [4]: os.path.join('parrot')
Out[4]: 'parrot'
Der Aufruf bewirkt also nichts und kann weggelassen werden.
nkoehring hat geschrieben: Das koennte man umgehen, indem man sich die letzte Zahl merkt und das Programm hochzaehlen laesst. Also setzt man irgendwie einen Schalter der mir sagt: Ja ich hab schonmal nachgeschaut, was die letzte Datei ist, also zaehle ich die Variable Zaehler jetzt direkt hoch und schaue nicht nochmal, bevor ich die naechste Datei speichere.
Das Problem daran ist, dass ich dafuer irgendwo die Information brauche, auf welchem Wert mein "Zaehler" denn gerade steht?
Du kannst ja auch beide Vorschläge kombinieren. `itertools.count()` nimmt als Argument die Zahl entgegen bei der angefangen werden soll, und die kannst Du aus den bisher vorhandenen Dateinamen gewinnen.

Und für Werte die über Aufrufe hinweg erhalten bleiben sollen, sind Klassen da. Hast Du eigentlich Erfahrung in einer anderen Programmiersprache?
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

BlackJack hat geschrieben:Wenn man das selber schreiben und sauber kapseln will, kommt man um eine Klasse oder ein Closure nicht drumherum.
Ich muss gestehen, dass mir die Bedeutung von "sauber kapseln" nicht wirklich klar ist. Wenn es darum geht, aufzupassen, dass niemand anders mit dem Programm Sachen anstellt, für die es nicht gedacht ist - das ist für mich bisher ein eher theoretisches Problem ;-) . Solange ich nicht versehentlich programmiere, daß Python meine Festplatte löscht, kann da eigentlich fast nichts grob schiefgehen :-) .
Das Programm ist nur dazu gedacht, eine Auswertung zu automatisieren, deren Endergebnisse ich gerne hätte, die mir aber zu mühsam mit Hand zu machen ist. Ich bin mir nicht sicher, ob ich ernsthaft damit Zeit spare, sie zu programmieren, statt sie "von Hand" zu machen; aber beim Programmieren ist der Langweile-Faktor wesentlich geringer :-) .
BlackJack hat geschrieben: Der "nicht so passend"-Fall greift dann ja auch gar nicht, sondern das `os.path.join()` ist einfach überflüssig. Das verbindet mehrere Pfadelemente mit dem für die Plattform passenden Pfadtrenner. Wenn man nur ein Element angibt, dann ist das eine Operation bei der immer wieder nur dieses Element als Ergebnis herauskommt.
Die Verwendung geht auf diesen Thread zurück: Ich habe versucht, die Namenselemente "Vorname", Zähler und Dateierweiterung auf verschiedenen Weise per "Addition" von Strings zu verbinden, habe aber nur Fehlermeldungen bekommen. Als ich auf Anraten Masarus zu `os.path.join()` gewechselt bin, ging es - das ist für mich im Moment Grund genug, dabei zu bleiben :-) .
Hast Du eigentlich Erfahrung in einer anderen Programmiersprache?
Annähernd nein. Ich habe vor Jahrzehnten mal Basic gelernt und in Pascal hineingeschnuppert, aber zu wirklichen Programmen hat es nie gereicht. Ich würde sagen, ich weiss jetzt schon mehr von Python als ich von den beiden je begriffen haben.
Klassen sind insofern halt nochmal ein ganz neuer "Denkansatz" für mich - und ein ziemlich schwieriger noch dazu.

Der counter hat übrigens auf Anhieb funktioniert! Vielen Dank nochmal!
BlackJack

merlin_emrys hat geschrieben:Ich muss gestehen, dass mir die Bedeutung von "sauber kapseln" nicht wirklich klar ist. Wenn es darum geht, aufzupassen, dass niemand anders mit dem Programm Sachen anstellt, für die es nicht gedacht ist - das ist für mich bisher ein eher theoretisches Problem ;-) .
Nein darum ging es auch nicht, sondern darum den Quelltext einfacher und verständlicher zu machen. Womit er dann auch leichter zu warten und erweitern wäre wenn das mal nötig wird. "Sauber kapseln" bedeutet im Grunde Daten und Funktionalität zu einer Einheit zusammen zu schnüren und nach aussen eine einfache API anzubieten, statt eigentlich zusammengehörigen Code und Daten überall zu verstreuen.

Ein Beispiel ohne Klassen ist Dein Ansatz mit der Zählerdatei. Das ist im Quelltext auf zwei Stellen verteilt, liesse sich aber in einer Funktion zusammenfassen, die nach aussen hin das Problem "Gib mir die nächste Nummer" löst. Ungetestet:

Code: Alles auswählen

def next_number(counter_name='counter'):
    counter_filename = counter_name + '.txt'
    try:
        counter_file = open(counter_filename, 'r')
        result = int(counter_file.readline())
        counter_file.close()
    except IOError:
        result = 0
    result += 1
    counter_file = open(counter_filename, 'w')
    counter_file.write('%s\n' % result)
    counter_file.close()
    return result
Jetzt steckt alles in einer einfachen Funktion die eine gut abgegrenzte Aufgabe erfüllt. Und die kann man ändern, solange sie weiterhin die gleiche Aufgabe erfüllt, ohne dass man sich an anderen Stellen im Quelltext allzuviele Gedanken darum machen muss. Das bedeutet "(sauber) gekapselt". Beispielsweise kann man sie durch folgendes ersetzen (auch ungetestet):

Code: Alles auswählen

def next_number(counter_name='counter', _counters=dict()):
    result = _counters.get(counter_name, 0) + 1
    _counters[counter_name] = result
    return result
Am Aufruf ändert sich nichts, es werden jetzt aber keine Dateien mehr benutzt.

Die Funktion nutzt übrigens aus, dass Default-Werte für Argumente nur *einmal* bei Ausführung der Definition ausgewertet werden. Das Dictionary dient der Funktion als "Gedächtnis" über Aufrufe hinweg. Damit kann man die ``CONST`` Deklaration bei lokalen Variablen bei Prozeduren und Funktionen in Pascal "simulieren".
BlackJack hat geschrieben:… `os.path.join()` …
Die Verwendung geht auf diesen Thread zurück: Ich habe versucht, die Namenselemente "Vorname", Zähler und Dateierweiterung auf verschiedenen Weise per "Addition" von Strings zu verbinden, habe aber nur Fehlermeldungen bekommen. Als ich auf Anraten Masarus zu `os.path.join()` gewechselt bin, ging es - das ist für mich im Moment Grund genug, dabei zu bleiben :-) .
Das hat auch in dem Thread nichts zur Lösung des Problems beigetragen, da war es genauso überflüssig.
Hast Du eigentlich Erfahrung in einer anderen Programmiersprache?
Annähernd nein. Ich habe vor Jahrzehnten mal Basic gelernt und in Pascal hineingeschnuppert, aber zu wirklichen Programmen hat es nie gereicht. Ich würde sagen, ich weiss jetzt schon mehr von Python als ich von den beiden je begriffen haben.
Klassen sind insofern halt nochmal ein ganz neuer "Denkansatz" für mich - und ein ziemlich schwieriger noch dazu.
Ich fragte, weil man dann vielleicht den Einsatz und Sinn von Klassen aus einer Dir vertrauteren Programmiersprache motivieren könnte und Parallelen, zum Beispiel zwischen einer Klasse mit Daten und Methoden in Python und einem RECORD und Prozeduren und Funktionen die damit arbeiten in Pascal, aufzeigen könnte.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

BlackJack hat geschrieben: Nein darum ging es auch nicht, sondern darum den Quelltext einfacher und verständlicher zu machen. Womit er dann auch leichter zu warten und erweitern wäre wenn das mal nötig wird. "Sauber kapseln" bedeutet im Grunde Daten und Funktionalität zu einer Einheit zusammen zu schnüren und nach aussen eine einfache API anzubieten, statt eigentlich zusammengehörigen Code und Daten überall zu verstreuen.
Okay, ich verstehe... naja, fast, ich muss nochmal nachforschen, was eine API ist. Aber das sollte sich finden lassen :-) .

Ich werde mal sehen, ob ich mir das "Kapseln" irgendwie angewöhnen kann; den Sinn der Sache sehe ich schon. Nur: Oft bin ich derzeit einfach noch damit zufrieden, wenn meine Programme überhaupt tun, was sie sollen, und Konstruktionen wie "try/except" sind für mich doch sehr schwierig überhaupt zum Laufen zu bringen... Da ist es ungleich leichter und schneller, im "Hauptprogramm" Dinge zur Verfügung zu stellen und sich dann darauf zu verlassen, dass sie auch da sind, wenn ich sie brauche. Und bei 200 Zeilen Quelltext sucht man ja auch nicht so lange... Aber ich gewöhne mich vermutlich trotzdem besser jetzt schon an eine bessere Praxis - immer vorausgesetzt, ich kann sie zum Laufen bringen :-o .
BlackJack hat geschrieben: Ich fragte, weil man dann vielleicht den Einsatz und Sinn von Klassen aus einer Dir vertrauteren Programmiersprache motivieren könnte und Parallelen, zum Beispiel zwischen einer Klasse mit Daten und Methoden in Python und einem RECORD und Prozeduren und Funktionen die damit arbeiten in Pascal, aufzeigen könnte.
Sowas gibt es in Pascal? Soweit bin ich da nie gekommen. Kurz nach der ganz einfachen Mathematik und der Erklärung vom "for-loop" (?) war der Kurs leider zu Ende, und dann hab ich die Uni gewechselt und mit HTML weitergemacht...

Betr. `os.path.join()`:
BlackJack hat geschrieben:Das hat auch in dem Thread nichts zur Lösung des Problems beigetragen, da war es genauso überflüssig.
Rein von der "Symptomatik" her würde ich da widersprechen wollen... Ich habe es noch nicht wieder probiert, aber bisher habe ich keine andere Lösung für das Problem gefunden. Ich bin mir ziemlich sicher, dass ich den Dateinamen irgendwie als String zusammensetzen können muß, ohne daß ich mit den Anführungsstrichen in Teufels Küche komme, aber ich konnte nicht herausfinden, wie. Ich muss sie offenbar irgendwie in den String einbauen, weil ich sie ja nicht in die Klammer hineinschreiben kann - dann wird der Verweis selbst als String interpretiert. Innerhalb der image.save-Anweisung erst die ganzen Teile zusammenzusetzen hat auch nicht funktioniert.
Da war ich für os.path.join() ganz dankbar, auch wenn ich es faktisch als "os.filename.join" mißbrauche...
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

BlackJack hat geschrieben:`os.listdir()` liefert die Dateinamen in einer willkürlichen Reihenfolge und nicht sortiert und man müsste bei jeder neuen Datei immer wieder alle Dateinamen durchgehen.
Wirklich? Ich dachte es gibt die Namen in Dateisystem Ordnung zurück.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
mq
User
Beiträge: 124
Registriert: Samstag 1. Januar 2005, 19:14

Code: Alles auswählen

>>> print os.listdir.__doc__
listdir(path) -> list_of_strings
... The list is in arbitrary order ...
Frage beantwortet? :D
BlackJack

Letztendlich wird es die Dateisystemordnung sein, d.h. die Reihenfolge in der der Dateisystemtreiber die Namen liefert. Bei FAT32 in der Reichenfolge in der die Dateien gespeichert wurden oder wo "Lücken" frei geworden sind, bei ReiserFS werden die Namen durch eine Hash-Funktion gejagt und in einem Sortierbaum gespeichert, also ist die Reihenfolge recht "zufällig", usw.

Also keine Ordnung auf die man sich im Programm verlassen sollte. :-)
BlackJack

merlin_emrys hat geschrieben:Ich werde mal sehen, ob ich mir das "Kapseln" irgendwie angewöhnen kann; den Sinn der Sache sehe ich schon. Nur: Oft bin ich derzeit einfach noch damit zufrieden, wenn meine Programme überhaupt tun, was sie sollen, und Konstruktionen wie "try/except" sind für mich doch sehr schwierig überhaupt zum Laufen zu bringen... Da ist es ungleich leichter und schneller, im "Hauptprogramm" Dinge zur Verfügung zu stellen und sich dann darauf zu verlassen, dass sie auch da sind, wenn ich sie brauche. Und bei 200 Zeilen Quelltext sucht man ja auch nicht so lange... Aber ich gewöhne mich vermutlich trotzdem besser jetzt schon an eine bessere Praxis - immer vorausgesetzt, ich kann sie zum Laufen bringen :-o .
Vorsicht: Skripte die irgendetwas automatisieren und mal so eben schnell geschrieben wurden, haben ab und zu die Angewohnheit sehr lange im Einsatz zu sein und mit der Zeit zu wachsen. :-)

Ein weiterer Vorteil von Kapselung in Funktionen und Klassen ist auch, dass man die Teile einzeln testen kann bis sie funktionieren. Die `next_number()` Funktion:

Code: Alles auswählen

In [23]: import test

In [23]: test.next_number()
Out[23]: 1

In [24]: test.next_number()
Out[24]: 2

In [25]: test.next_number()
Out[25]: 3

In [26]: test.next_number('spam')
Out[26]: 1

In [27]: test.next_number('spam')
Out[27]: 2

In [28]: test.next_number('ham')
Out[28]: 1

In [29]: test.next_number('ham')
Out[29]: 2

In [30]: test.next_number()
Out[30]: 4

In [31]: test.next_number('spam')
Out[31]: 3
Betr. `os.path.join()`:
BlackJack hat geschrieben:Das hat auch in dem Thread nichts zur Lösung des Problems beigetragen, da war es genauso überflüssig.
Rein von der "Symptomatik" her würde ich da widersprechen wollen... Ich habe es noch nicht wieder probiert, aber bisher habe ich keine andere Lösung für das Problem gefunden. Ich bin mir ziemlich sicher, dass ich den Dateinamen irgendwie als String zusammensetzen können muß, ohne daß ich mit den Anführungsstrichen in Teufels Küche komme, aber ich konnte nicht herausfinden, wie. Ich muss sie offenbar irgendwie in den String einbauen, weil ich sie ja nicht in die Klammer hineinschreiben kann - dann wird der Verweis selbst als String interpretiert.
Wieso musst Du Anführungstriche in die Zeichenkette hineinbekommen? Das da welche drin waren, war doch gerade das *Problem* in dem anderen Thread!
Da war ich für os.path.join() ganz dankbar, auch wenn ich es faktisch als "os.filename.join" mißbrauche...
Nein das tust Du nicht! Das ginge auch gar nicht weil innerhalb von Dateinamen kein Pfadtrenner vorkommen darf. Du musst mehr geändert haben als nur `os.path.join()` zu benutzen. Und diese *andere* Änderung war die Lösung des Problems. Zeig doch mal Code wo `os.path.join()` nur ein einziges Argument bekommt, der ohne die Funktion nicht mehr funktioniert.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

BlackJack hat geschrieben:Betr. `os.path.join()`:
Wieso musst Du Anführungstriche in die Zeichenkette hineinbekommen? Das da welche drin waren, war doch gerade das *Problem* in dem anderen Thread!
Ohne ging es aber auch nicht...
BlackJack hat geschrieben:
Da war ich für os.path.join() ganz dankbar, auch wenn ich es faktisch als "os.filename.join" mißbrauche...
Nein das tust Du nicht! Das ginge auch gar nicht weil innerhalb von Dateinamen kein Pfadtrenner vorkommen darf. Du musst mehr geändert haben als nur `os.path.join()` zu benutzen. Und diese *andere* Änderung war die Lösung des Problems. Zeig doch mal Code wo `os.path.join()` nur ein einziges Argument bekommt, der ohne die Funktion nicht mehr funktioniert.
Erm... Ich brauche os.path.join(), um drei Namensteile miteinander zu verbinden:
- "Vorname" - der sich aus der Stelle im Programm ergibt, damit ich zuordnen kann, was an Aenderungen ich sehen sollte,
- die laufende Nummer oder einen variablen Input-Teil,
- ".bmp", damit ich die Datei nachher mit Doppelklick oeffnen kann.
Wenn ich nur einen "Fixnamen" habe, nehme ich os.path.join() nicht, weil das auch ohne geht.
BlackJack hat geschrieben:Ein weiterer Vorteil von Kapselung in Funktionen und Klassen ist auch, dass man die Teile einzeln testen kann bis sie funktionieren.
Hmm... dann muss man aber die ganzen Variablen "mit Hand" einfuettern, oder? Wenn die Klasse auf ein Bild zugreifen soll, braucht sie ja vermutlich weiterhin eins, um sich testen zu lassen?
(Ich teste derzeit noch immer durch das Einfuegen von "print"-Befehlen... :-o )

Edit:
Eventuell hab ich aber einfach auch nur den Wald vor laute Baeumen nicht gesehen. Ich habe stundenlang (naja, ich glaube, etwas ueber eine Stunde) lang alle Varianten ausprobiert, die mir eingefallen sind, aber es kann sein, dass die ganz schlichte Variante ohne Anfuehrungsstriche aus irgendeinem andern Problem nicht ging und ich das falsch zugeordnet habe. Nachdem ich dann wusste: "Anfuehrungsstriche weglassen funktioniert nicht", habe ich tatsaechlich erst, als ich zu der os.path.join()-Variante gegriffen habe, die Anfuehrungsstriche wieder komplett weggelassen. Und als das ging, habe ich nicht weiter herumgetestet, weil es ohnehin schon eher spaet war und ich noch andere Sachen im Kopf hatte ;-) . Aber in einem kleinen Trockentest funktioniert zumindest auf diesem Rechner die reine Additionsvariante jetzt auch, d.h.: Kopie.save(Vorname + VariablerTeil + Dateierweiterung, "BMP").
Antworten