Erstes Modul erstellen

Probleme bei der Installation?
Antworten
HerrAyas
User
Beiträge: 5
Registriert: Montag 1. April 2024, 14:51

Hi Leute,
Anfängerproblem, bzw. der Noob kann jetzt ein bisschen Python, hat aber keine Ahnung, was hinter den Kulissen stattfindet:

Ich habe vor einen zufällig generierten Array (code steht in array_zufall.py) sortieren zu lassen (code steht in sortier_algorithmen.py)

Also habe ich ganz naiv an den Anfang der Sortier-Datei "import array_zufall" bzw. "from array_zufall.py import zuf_liste" geschrieben und gemerkt, dass Python der Meinung ist, dass es "not a package" ist.

Ich habe mit os.chdir herumexperimentiert, etwas von sys.path gelesen, Fehlermeldungen von pylance erhalten und bin jetzt vollkommen verwirrt...

So sieht "sortier_algorithmen.py" aus:

Code: Alles auswählen

#Die Arbeitsumgebung wird hier festgelegt:
import os
print("Ursprünglich: ",os.getcwd()) # Get Current Working Directory

os.chdir("D:\Spielwiese") #Ändert das CWD
print("Geändert: ", os.getcwd())

from array_zufall.py import zuf_liste


print(zuf_liste(20))

#Probleme mit dem Importieren von array_zufall.py "is not a package"
#Wenn ich die Liste hier mal reinbekomme, schreibe ich hier die Sortieralgorithmen hin:
#Algo1

#Algo2
Und das ist array_zufall.py (die ich in anderen .py-Dateien verwenden möchte)

Code: Alles auswählen

import math as m
import random

# Eine (geordnete) Liste wird erzeugt und mit pop(i) ein zufälliges Element in ein neues Array geschrieben

# Initialisierung von zwei leeren Listen
def zuf_liste(anzahl):
    geordnet = []
    zufall = []
    #anzahl = int(input("Wie lang soll das Zufallsarray werden? "))
    #Erstellung der Ausgangsliste
    for i in range(anzahl):
        geordnet.append(i+1)

    # print("Startliste: ",geordnet)


    #Die Zufallsliste wird generiert
    while len(geordnet)>0: #solange noch Zahlen da sind, mach...
            #zufall.append(geordnet.pop(random.randint(0,len(geordnet)-1))) 
            # funktioniert - aber ist unleserlich, ich zoppel das auseinander:

        actlen = len(geordnet)                  #Es wird geguckt, wie lang die Restliste ist
        z = random.randint(0, actlen-1)         #Zufallszahl z wird erzeugt, die Werte zwischen 0 und Länge-1 annehmen kann
        nehme = geordnet.pop(z)                 #Das z-te Element aus meiner Liste wird genommen
        gebe = nehme                            #Das Element wird jetzt übergeben
        zufall.append(gebe)                     #An die Liste "zufall" wird das genommene Element gegeben
    #print("Zufallsliste, alle Zahlen zwischen 1 und ",anzahl," sind genau einmal enthalten:")
    #print(zufall)
    return(zufall)
Ich arbeite "zum schnell mal Testen" in der IDLE Umgebung, und wenn ich mich länger dransetze in VisualStudioCode. Und habe gerade festgestellt, dass ich zwar zurechtkomme, aber keine Ahnung hat wer wem eigentlich was erlaubt, bzw. sich wo herumtreibt.
Wie kann ich meinem Python sagen, arbeite bitte nicht in c:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.12_3.12.2032.0_x64_qbz...\Lib\site-packages (oder so ähnlich, sagt mir zumindest der "PathBrowser" von IDLE)
sondern in "D:\Spielwiese" macht mich schon die erste Fehlermeldung stutzig "Syntax Warning invalid escape sequence \S .."Stört der sich an Großbuchstaben?

Das Zufalls-Listen erzeugen klappt gut, aber wenn ich sortieren_algorithmen.py starte, bekomme ich folgenden Output:
Python 3.12.7 (tags/v3.12.7:0b05ead, Oct 1 2024, 03:06:41) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.

Warning (from warnings module):
File "D:\Spielwiese\sortier_algorithmen.py", line 4
os.chdir("D:\Spielwiese") #Ändert das CWD
SyntaxWarning: invalid escape sequence '\S'
>>>
================= RESTART: D:\Spielwiese\sortier_algorithmen.py ================
Ursprünglich: D:\Spielwiese
Geändert: D:\Spielwiese
Traceback (most recent call last):
File "D:\Spielwiese\sortier_algorithmen.py", line 6, in <module>
from array_zufall.py import zuf_liste
ModuleNotFoundError: No module named 'array_zufall.py'; 'array_zufall' is not a package


Würde mich sehr freuen, wenn ich Links, Erklärungen, Videos oder irgendwas hilfreiches erfahre. Ich habe mich bei der Suche nach einer Lösung immer mehr der Tatsache stellen müssen, dass ich über die Vorgänge "hinter den Kulissen" eigentlich gar keine Ahnung habe...
Danke & liebe Grüße,
Alexander
Sirius3
User
Beiträge: 18215
Registriert: Sonntag 21. Oktober 2012, 17:20

os.chdir sollte in einem sauberen Programm nicht vorkommen. Module sollten im Modulsuchpfad liegen.
Dein Modul heißt array_zufall und nicht array_zufall.py.
Deshalb wird es auch nicht gefunden.
Listen sind keine Arrays, sollten also nicht so genannt werden.
Funktionen sollten wie alle anderen Namen auch keine Abkürzungen enthalten. Außerdem nennt man Funktionen nach Tätigkeiten. Also nicht zus_liste, sondern erzeuge_zufallsliste.
math kürzt man nicht mit m ab. Wird aber auch gar nicht gebraucht.
Es gibt random.shuffle:

Code: Alles auswählen

liste = list(range(1, anzahl + 1))
random.shuffle(liste)
HerrAyas
User
Beiträge: 5
Registriert: Montag 1. April 2024, 14:51

Lieber Sirius3,
1000 Dank. PY weggemacht und schon klappt's :)
Ist das "Arbeitsverzeichnis" also immer das Verzeichnis (egal wo), in dem die Ursprungsdatei liegt? Wenn ich dann Unterordner einbaue gebe ich dann nur den relativen Pfad (z.B. import \unterordner\modul1) an?
Listen und Arrays: Autsch, ja.. habe zuerst mit arrays gespielt und dann die Namen gemixt.
Danke für die Benamsungstipps: Keine Abk. und Tätigkeit
Wieso nicht math mit m abk.? pygame als pg, screen als sc, ... dann besser auch nicht?
die random Funktion kannte ich, die sortieralgorithmen gibt's ja auch schon. Ich versuche nur gerade langsam ohne Stützräder zu fahren.

Danke für die Hinweise! Problem superschnell gelöst...
lg alex
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@HerrAyas: Das Arbeitsverzeichnis ist etwas was zum Prozess gehört und bestimmt wo relativ angegebene Pfade anfangen. Das hat mit Modulimporten erst einmal nicht so viel zu tun. Sollte es zumindest nicht. Das Verzeichnis vom Modul das als Programm ausgeführt wird, liegt im Modulsuchpfad.

Auch wenn Packages in Orndern organisiert sind, sollte man da nicht einfach an Unterordner denken. Denn auch für Packages gilt das mit dem Modulsuchpfad, das heisst ein ``from package import modul`` liegt zwar sehr wahrscheinlich eine ``modul.py`` neben einer ``__init__.py`` in einem ``package/``-Ordner — der wiederum liegt im Modulsuchpfad.

Wenn man mehr als ein Modul hat, macht es in der Regel Sinn die in einem Package zusammenzufassen, damit nur dieser Package-Name mit allen anderen Namen von installierten Packages und Modulen konkurriert. Das verringert die Gefahr, dass man ein eigenes Modul wie ein Package/Modul benennt was direkt oder indirekt mal vom eigenen Programm benutzt wird.

Abkürzungen sollte man generell meiden sofern sie nicht allgemein bekannt sind. Es macht Programme schwieriger zu lesen, weil man sich dann zusätzlich merken muss das `m` eigentlich `math` bedeutet, statt *das* im Quelltext zu lesen. Man braucht das ja hauptsächlich um es von anderen Modulen unterscheiden zu können. Wenn man diesen Zusatz nicht haben will, kann man die Namen die man aus einem Modul benötigt, ja auch direkt importieren und sich den Modulnamen so komplett sparen. Es gibt ein paar wenige Modulnamen wo man aus ”Tradition” abkürzt, beispielsweise ``import tkinter as tk`` oder ``import numpy as np``. Meistens bei Modulen die hunderte von Namen enthalten und von denen viele verwendet werden, oder die oft auch in interaktiven Sitzungen verwendet werden.

Ich würde die `zuf_liste()` ja nicht „ohne Stützräder“ bezeichnen sondern mit „Extremstützrädern“, das so detailliert + Kommentar der das alles nochmal beschreibt, zu formulieren. Das auseinaderziehen des Schleifenkörpers ist spätestens bei der Zeile ``gebe = nehme`` jenseits von dem was man ernsthaft schreiben würde.

Ergänzend zu den Kommentaren von Sirius3: Man sollte nicht am Anfang alle Namen definieren, sondern möglichst erst dann wenn man sie benötigt. Das macht den Code verständlicher, man übersieht bei Änderungen nicht so leicht Namen die gar nicht mehr verwendet werden, und man kann leichter zusammengehörenden Code in eigene Funktionen herausziehen.

``while len(geordnet) > 0:`` würde man einfach als ``while geordnet:`` schreiben.

Bei `randrange()` statt `randint()` kann man sich das ``- 1`` sparen.

``return`` ist keine Funktion, das sollte man nicht so schreiben das es wie ein Funktionsaufruf aussieht.

Den Schleifenkörper würde ich maximal auf zwei Zeilen aufteilen. Zwischenstand:

Code: Alles auswählen

import random


def erzeuge_zufallsreihenfolge(anzahl):
    zahlen = list(range(1, anzahl + 1))

    ergebnis = []
    while zahlen:
        index = random.randrange(len(zahlen))
        ergebnis.append(zahlen.pop(index))

    return ergebnis
Das ist gegenüber `random.shuffle()` ineffizienter weil eine Liste immer kleiner wird und eine andere immer grösser, statt das „in situ“ mit *einer* Liste zu machen wo einfach Listenelemente vertauscht werden.

Letztlich stellt sich aber die Frage warum man das selber implementiert, wenn es das doch schon fertig gibt. Es erhöht einfach nur die Wahrscheinlichkeit, dass man es ineffizienter oder sogar falsch macht.

”Die” Sortieralgorithmen gibt es nicht. Soweit ich weiss gibt es nur zwei. Einen relativ komplexen aber effizienten — Timsort oder das was nach Timsort bei `list.sort()`/`sorted()` implementiert wurde und im Grunde ein Heaptsort in der Standardbibliothek das man mit einer Zeile implementieren kann (ungetestet):

Code: Alles auswählen

import heapq

def heapsort(sequence, key=None):
    return heapq.nsmallest(len(sequence), sequence, key)
Bei "\S" stört sich Python nicht am Grossbuchstaben, sondern daran, dass "\S" keine gültige Escape-Sequenz ist. Der \ hat in Zeichenketten eine besondere Bedeutung. "\n" steht beispielsweise für ein Zeilenende-Zeichen. Und "\S" gibt es nicht als Kombination. Wenn man einen \ in einer literalen Zeichenkette haben möchte, muss man den doppelt schreiben um *einen* zu bekommen. Oder man stellt dem Literal ein r oder R voran um dem \ die besondere Bedeutung zu nehmen.

Code: Alles auswählen

In [38]: print("a\nb")
a
b

In [39]: len("\\")
Out[39]: 1

In [40]: print("\\")
\

In [41]: print(R"\S")
\S

In [42]: print(R"\n")
\n
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Antworten