Unterschied os.getcwd() live und Tests

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.
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

Hallo zusammen,

ich habe mir einen Filehandler geschrieben, um in der Projektstruktur zu navigieren. Diese Methode liefert mir den Path zum "src" Verzeichnis. Allerdings im Testfall bekomme ich nur den Laufwerksbuchstaben geliefert.

Kann mir bitte jemand sagen, warum, und wie ich vorgehen muss?

Code: Alles auswählen

    def __getSrcDir(self):
        """
        get src Directory form this project
        
        :return: src directory
        """
        dir = os.getcwd()
        off = dir.find("\\src") + 4
        src = dir[0:off]
        return src
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich verstehe nicht, was du meinst. Was ist ein Filehandler? Und os.getcwd() ist immer eine schlechte Idee, das Arbeitsverzeichnis kann sonstewo stehen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Fehler liegt darin, dass Du versuchst, Pfade wie Zeichenketten zu behandeln.
Dafür gibt es pathlib.Path.

Methoden scheibt man wie andere Funktionen auch, komplett klein. Doppelte führende Unterstriche benutzt man nicht. `self` wird nicht verwendet, das ist also gar keine Methode.


PS: schau mal, wie find funktioniert, ist unabhängig von diesem Problem eine gute Idee.
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

__deets__ hat geschrieben: Freitag 25. November 2022, 12:04 Ich verstehe nicht, was du meinst. Was ist ein Filehandler?
Ich will im Verzeichnis meines Projektes navigieren. Also zum Beispiel im Projekt/src/qt die ui-Files finden, oder Projekt/data/die .db Files. Um dies an zentraler Stelle zu behandeln, habe ich eine Klasse "Filehandler".
__deets__ hat geschrieben: Freitag 25. November 2022, 12:04 Und os.getcwd() ist immer eine schlechte Idee, das Arbeitsverzeichnis kann sonstewo stehen.
Es würde auch mit "os.path.abspath(os.curdir)" gehen. Was ist da der Unterschied?
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

Sirius3 hat geschrieben: Freitag 25. November 2022, 12:05 Der Fehler liegt darin, dass Du versuchst, Pfade wie Zeichenketten zu behandeln.
Dafür gibt es pathlib.Path.
Der Rückgabewert ist doch immer eine Zeichenkette, egal welche Funktion man wählt. Zumindest habe ich bisher nicht gegenteiliges gefunden.

Sirius3 hat geschrieben: Freitag 25. November 2022, 12:05 Methoden scheibt man wie andere Funktionen auch, komplett klein.
ok, akzeptiert :)
Sirius3 hat geschrieben: Freitag 25. November 2022, 12:05 Doppelte führende Unterstriche benutzt man nicht. `self` wird nicht verwendet, das ist also gar keine Methode.
Das ist eine private Methode.
Sirius3 hat geschrieben: Freitag 25. November 2022, 12:05 PS: schau mal, wie find funktioniert, ist unabhängig von diesem Problem eine gute Idee.
Find benutze ich doch "directory.find("\\src")"
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der doppelte Unterstrich ist nicht fuer private Methoden gedacht. Sondern zur Vermeidung von Namenskollisionen. Das nicht zu beachten kann zu subtilen Fehlern fuehren. Gewoehn es dir also erst gar nicht an.

Weisst du, was das current working directory ist? Denn davon haengt die Frage ab, ob das passt, oder nicht. Augenscheinlich ja eher nicht, sonst wuerde es ja funktionieren. So richtig klar, was das alles mit "navigieren" zu tun hat, ist es immer noch nicht. Ist das Teil deines IDE-Setups, oder wo kommt das zum Einsatz?
Benutzeravatar
DeaD_EyE
User
Beiträge: 1012
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Die Methode der Klasse könnte eine staticmethod sein. Da du in der Methode self nicht verwendest, ist es auch nicht notwendig, die Instanz zu übergeben. Private Attribute/Methoden fangen mit nur einem Unterstrich an.

Das src-Verzeichnis würde ich ganz anders "finden".
Dein Programm/Script liegt irgendwo relativ zu dem src-Verzeichnis.

Wenn dein Programm z.B. im Home-Verzeichnis liegt (C:\Windows\Users\benutzer\code.py) und im gleichen Verzeichnis das Verzeichnis src, dann kann man den absoluten Pfad so erstellen:

Code: Alles auswählen

from pathlib import Path
src_dir = Path(__file__).parent.joinpath("src").absolute()
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Icke: Zwischen `os.getcwd()` und ``os.path.abspath(os.curdir)`` gibt es keinen wesentlichen Unterschied. Darum sind auch beide keine gute Idee.

`pathlib.Path`-Objekte sind keine Zeichenketten. Und Pfade auch in Zeichenkettenform sind nicht einfach beliebige Zeichenketten, sondern welche die bestimmten Regeln folgen, damit es gültige Pfade sind, und die man nicht einfach mit normalen Zeichenkettenoperationen bearbeiten kann, ohne das man Gefahr läuft dass am Ende ungültige Pfadangaben dabei heraus kommen. Oder gültige aber falsche. `pathlib` ist dazu da eine, einfache, verständliche, und robuste API für die manipulation von Pfadangaben zu haben.

Du benutzt `find()` das war Sirius3 schon klar. Die Anmerkungen kam ja gerade weil er gesehen hat *wie* Du `find()` benutzt. Denn daraus wird klar, das Dir nicht so ganz klar ist was die Funktion in welchem Fall als Wert liefert. Ich persönlich verwende deswegen eigentlich immer `index()` statt `find()`, und ärgere mich auch ein bisschen warum `find()` beim wechsel auf Python 3 nicht beerdigt wurde, oder zumindest die API so geändert wurde, dass nicht jedes Ergebnis unbesehen als Index verwenden werden kann.

Bei "\src" kann es übrigens Probleme geben, denn selbst Windows kommt auch mit "/" als Pfadtrenner klar. Auch wieder ein Grund warum man Pfade nicht einfach mit normalen Zeichenkettenoperationen verarbeiten sollte, die nichts über die Regeln für Pfade wissen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

__deets__ hat geschrieben: Freitag 25. November 2022, 12:42 Der doppelte Unterstrich ist nicht fuer private Methoden gedacht. Sondern zur Vermeidung von Namenskollisionen. Das nicht zu beachten kann zu subtilen Fehlern fuehren. Gewoehn es dir also erst gar nicht an.
Das steht in der Doku und im allgemeinen INet aber anders. Ein Unterstrich deklariert protected, zwei Unterstriche privat.
Mir ist dabei bewusst, dass es in Python keine wirkliche Verschattung gibt, sondern die nur deklarativen Charakter hat.
__deets__ hat geschrieben: Freitag 25. November 2022, 12:42 Weisst du, was das current working directory ist? Denn davon haengt die Frage ab, ob das passt, oder nicht. Augenscheinlich ja eher nicht, sonst wuerde es ja funktionieren. So richtig klar, was das alles mit "navigieren" zu tun hat, ist es immer noch nicht. Ist das Teil deines IDE-Setups, oder wo kommt das zum Einsatz?
Nein, es hat nicht mit der IDE zu tun. Mit navigieren meinte ich, in meinem Project/Application zu bestimmten Dateien/Verzeichnissen zu navigieren. Wie zB. zur einem db.File.
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Im Internet steht halt viel Mist. Und das ist ein Beispiel.

Was deine Frage angeht: das ist und bleibt der falsche Ansatz. Das Arbeitsverzeichnis kann auf eine beliebige Stelle zeigen. Dafür ist es sogar gedacht.

Wenn du Dateien relativ zu deinem Code lokalisieren willst, macht man das mit der __file__ Variable. Wurde hier schon oft diskutiert und vorgemacht. Inzwischen bevorzugt mit pathlib.
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

__blackjack__ hat geschrieben: Freitag 25. November 2022, 18:41 @Icke: Zwischen `os.getcwd()` und ``os.path.abspath(os.curdir)`` gibt es keinen wesentlichen Unterschied. Darum sind auch beide keine gute Idee.

`pathlib.Path`-Objekte sind keine Zeichenketten. Und Pfade auch in Zeichenkettenform sind nicht einfach beliebige Zeichenketten, sondern welche die bestimmten Regeln folgen, damit es gültige Pfade sind, und die man nicht einfach mit normalen Zeichenkettenoperationen bearbeiten kann, ohne das man Gefahr läuft dass am Ende ungültige Pfadangaben dabei heraus kommen. Oder gültige aber falsche. `pathlib` ist dazu da eine, einfache, verständliche, und robuste API für die manipulation von Pfadangaben zu haben.

Du benutzt `find()` das war Sirius3 schon klar. Die Anmerkungen kam ja gerade weil er gesehen hat *wie* Du `find()` benutzt. Denn daraus wird klar, das Dir nicht so ganz klar ist was die Funktion in welchem Fall als Wert liefert. Ich persönlich verwende deswegen eigentlich immer `index()` statt `find()`, und ärgere mich auch ein bisschen warum `find()` beim wechsel auf Python 3 nicht beerdigt wurde, oder zumindest die API so geändert wurde, dass nicht jedes Ergebnis unbesehen als Index verwenden werden kann.
Es gibt wohl in Python gefühlte tausend Wege für ein Ziel, aber nicht jeder stellt den optimalen oder sicheren Weg dar. Das ist alles immer sehr verwirrend. Der Unterschied wir auch durch Dokus nicht klar. Darum auch hier vielen Dank für die Aufklärung. Als Einsteiger in Python sind solche Gegenüberstellungen wirklich wichtig, um es mal zu verstehen. Ich komme berufl. aus der SAP/ABAP Welt, dort gibt es solche gravierenden Unterschiede nicht :)
__blackjack__ hat geschrieben: Freitag 25. November 2022, 18:41 Bei "\src" kann es übrigens Probleme geben, denn selbst Windows kommt auch mit "/" als Pfadtrenner klar. Auch wieder ein Grund warum man Pfade nicht einfach mit normalen Zeichenkettenoperationen verarbeiten sollte, die nichts über die Regeln für Pfade wissen.
Verstanden, Danke.

Ich habe dies inzwischen so gelöst.

Das SRC-Directory finde ich so.

Code: Alles auswählen

    @staticmethod
    def __get_src_dir():
        """
        get src Directory from this project

        :return: src directory
        """
        p = pathlib.Path().absolute()
        while p.name != 'src':
            p = p.parent
        return p
Das "navigieren" im Project-Directory löse ich so

Code: Alles auswählen

    def get_data_dir(self):
        """
        get Data directory in application

        :return: directory
        """
        src = self.__get_src_dir()
        return src.joinpath('data')
Damit sollte ich auf der "sicheren" Seite liegen, oder?
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein. Siehe meine Antwort. Die Verwendung von pathlib ist gut. Aber du verlässt dich immer noch auf das Arbeitsverzeichnis. Und das funktioniert nur zufällig.
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

__deets__ hat geschrieben: Sonntag 27. November 2022, 10:27 Nein. Siehe meine Antwort. Die Verwendung von pathlib ist gut. Aber du verlässt dich immer noch auf das Arbeitsverzeichnis. Und das funktioniert nur zufällig.
Was meinst Du mit Arbeitsverzeichnis? Das "c:/username/documents" o.ä.? Ich bin hier in meiner Struktur des Projectes/Application. Dort ist die Struktur ja vorgegeben.
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du eine feste Struktur hast, warum musst Du dann src so kompliziert suchen?
Normalerweise definiert man sich ein project_path-Attribut, das entweder explizit gesetzt ist, oder auch meinetwegen als default das aktuelle Arbeitsverzeichnis.
Von dort aus kannst Du in das src- oder data-Verzeichnis absteigen.
Aber warum willst du denn im Verzeichnisbaum aufsteigen?

Die doppelten Unterstriche sind ja immer noch da!
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Icke hat geschrieben: Sonntag 27. November 2022, 10:30
__deets__ hat geschrieben: Sonntag 27. November 2022, 10:27 Nein. Siehe meine Antwort. Die Verwendung von pathlib ist gut. Aber du verlässt dich immer noch auf das Arbeitsverzeichnis. Und das funktioniert nur zufällig.
Was meinst Du mit Arbeitsverzeichnis? Das "c:/username/documents" o.ä.? Ich bin hier in meiner Struktur des Projectes/Application. Dort ist die Struktur ja vorgegeben.
Das Arbeitsverzeichnis ist das current working directory. Und das ist ein Begriff, den du dir mal ergoogeln solltest. Denn darauf beziehst du dich hier die ganze Zeit (explizit mit getcwd, und implizit mit der letzten "Loesung"), und der bedeutet etwas komplett anderes, als du das denkst. Das hat *nichts* mit deinem Projekt zu tun. Dass es da hinzeigt, ist ein Seiteneffekt deiner momentanen Umgebung, und Art, wie du das startest. Das hat aber auf Dauer keinen Bestand, spaetestens, wenn das ganze mal an wen anderes gehen soll.

https://en.wikipedia.org/wiki/Working_directory
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

Sirius3 hat geschrieben: Sonntag 27. November 2022, 10:51 Wenn Du eine feste Struktur hast, warum musst Du dann src so kompliziert suchen?
Normalerweise definiert man sich ein project_path-Attribut, das entweder explizit gesetzt ist, oder auch meinetwegen als default das aktuelle Arbeitsverzeichnis.
Von dort aus kannst Du in das src- oder data-Verzeichnis absteigen.
Aber warum willst du denn im Verzeichnisbaum aufsteigen?
Ja, man könnte den Pfad zu SRC auch einmal setzen, würde man sich die While-Schleife jedesmal sparen. Ändert von der Sache aber erstmal nix.
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

__deets__ hat geschrieben: Sonntag 27. November 2022, 10:58 Das Arbeitsverzeichnis ist das current working directory. Und das ist ein Begriff, den du dir mal ergoogeln solltest. Denn darauf beziehst du dich hier die ganze Zeit (explizit mit getcwd, und implizit mit der letzten "Loesung"), und der bedeutet etwas komplett anderes, als du das denkst. Das hat *nichts* mit deinem Projekt zu tun. Dass es da hinzeigt, ist ein Seiteneffekt deiner momentanen Umgebung, und Art, wie du das startest. Das hat aber auf Dauer keinen Bestand, spaetestens, wenn das ganze mal an wen anderes gehen soll.

https://en.wikipedia.org/wiki/Working_directory
Gerade, wenn es mal an jemand anderes gehen sollte, würde es doch funktionieren, da der physische Pfad jedes mal neu ermittelt wird.
Wie setzt man denn sonst solche Pfad Verweise, gerade, wenn dieses Projekt auch mal in einer '.exe landen soll? Alles, was ich dazu ergoogelt habe, lief auf os.getcwd o.ä. hinaus.
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du hast das immer noch nicht durchdrungen. Es geht nicht darum, dass du etwas neu ermittelst. Es geht darum, was der Ausgangspunkt dieser Ermittlung ist. Schreib dir ein simples Skript:

Code: Alles auswählen

import os; print(os.getcwd())
Und dann ruf das mal so auf:

Code: Alles auswählen

$ cd c:\User\wasauchimmer
$ C:\python\python.exe C:\pfad\zum\skript.py
... # ausgabe
$ cd c:\woanders\hin
$ C:\python\python.exe C:\pfad\zum\skript.py
... # ausgabe
Und dann ist das hoffentlich klar, warum das nicht geht.

Wie es geht, wurde auch schon gesagt. __file__ ist die Variable, die auf die Position des Python-Moduls/Skriptes zeigt. Das ist, was du hier offensichtlich (heisst ja nicht umsonst __get_src, wenn auch mit den unnoetigen doppelten Unterstrichen) willst.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nachtrag, weil's vielleicht untergegangen ist: DeadEye hat exact den benoetigten Code bereitgestellt.
Icke
User
Beiträge: 25
Registriert: Mittwoch 23. November 2022, 12:55

__deets__ hat geschrieben: Sonntag 27. November 2022, 16:21 Nachtrag, weil's vielleicht untergegangen ist: DeadEye hat exact den benoetigten Code bereitgestellt.
Das funktioniert aber nur auf oberster Ebene. Ist der Aufrufer in tieferer Ebene, funktioniert dies nicht mehr.
Greetings -=Icke=-

I do this just for fun, not professionell
only Python and absolute beginner
Antworten