import innerhalb von Funktionen "erlaubt"??

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
shakebox
User
Beiträge: 175
Registriert: Montag 31. März 2008, 17:01

Hallo!

Ich bin ja nachwievor neu in Python und steh grad mal wieder an ner Stelle wo ich nicht sicher bin ob ich da evtl. was voellig "Verbotenes" im Sinne von "sauber ist das nicht und sollte man nicht machen" tue oder ob das ok ist. Deshalb einfach mal die Frage an Euch:

Ich hab mir ein Modul geschrieben das mir alle moeglichen Funktionen sammelt,, die ich in verschiedenen Scripten hier im Haus brauchen kann. Die Funktionen selbst haben meist nix miteinander zu tun, fuer jede aber ein eigenes Modul zu machen ist irgendwie auch nicht ganz sinnvoll. Einen main-Teil hat das Modul nicht, dient also nur dem Import und nicht der direkten Ausfuehrung.

Einige der Funktionen brauchen jetzt spezielle andere Module. Diese Module werden aber eben nicht fuer alle Funktionen gebraucht. Ist es jetzt erlaubt, den import-Befehl nicht wie ueblich ganz oben im Modul zu definieren sondern innerhalb der jeweiligen Funktionsdefinition zu platzieren, damit nur importiert wird wenn das Modul auch wirklich gebraucht wird oder ist das keine schoene Art und Weise bzw. fuehrt das evtl. zu Problemen, weil das dann im falschen Namespace importiert wird oder sowas?

Hoffe das ist verstaendlich formuliert. Danke schonmal fuer jegliche Hinweise!
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Wenn es um sowas geht:

Code: Alles auswählen

In [1]: def my_func():
   ...:     import sys
   ...:     print sys.platform
Gibts da keine Probleme. Ich hab die PEPs nicht studiert, aber ich verwende sowas oft um zirkuelle-imports zu vermeiden.


MfG EnTeQuAk
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

ALso grundsätzlich sehe ich da eigentlich keine Unsauberkeit - es bleibt imho aber eine Frage: Ist Python so clever, dass es den import nur dann durchführt, wenn noch nichts importiert wurde? Wenn nein, würde ja bei jedem Aufruf aus einer Funktion die dortigen imports ausgeführt ... und das wäre sicherlich alles andere als performant.

Ich habe dazu direkt im wiki leider grad nichts gefunden auf die Schnelle.

Also mal abwarten, was die Gurus hier noch zu sagen ;-)
shakebox
User
Beiträge: 175
Registriert: Montag 31. März 2008, 17:01

ok, die Profis scheinen schon in den Pfingstferien zu sein :wink:

Aber danke Euch mal soweit, klingt ja dann nicht voellig problematisch. Bei nem Test hat es auch geklappt wie ich mir das vorstelle, nur wollte ich halt ausschliessen dass ich mir damit irgendwie durch die Hintertuer eine ueble Falle fuer spaeter stelle.

Schoenes langes Wochenende wuenscht Euch der

Shakebox
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo shakebox!

Du weißt ja schon: Normalerweise sind die Imports am Anfang des Moduls unterzubringen. Damit erkennt man sofort was das Modul alles zum Arbeiten braucht.

Aber natürlich ist nichts gegen ein paar Ausnahmen einzuwenden. Wenn du glaubst, dass ein Import in einer Funktion viel besser aufgehoben ist, als im Modulkopf, dann schreibe den Import in die Funktion. Das ist überhaupt kein Problem.

Module werden nur einmal importiert. Egal wie oft du im Code ein Modul importierst, es wird nicht noch einmal ausgeführt. Allerdings findet bei jedem Import eine Prüfung statt, die feststellt, ob das Modul bereits importiert wurde. Das ist zwar viel schneller als der eigentliche Import selbst, bremst aber trotzdem ein bischen. Wenn eine Funktion sehr oft hintereinander ausgeführt wird, dann ist diese Funktion kein guter Ort für so einen Import.

Es sollte wirklich einen guten Grund für einen, nicht im Modulkopf stattfindenden Import geben. Ein Import eines __builtin__-Moduls gehört auf jeden Fall in den Modulkopf. Diese Module braucht Python bereits intern. Es bringt also nichts mehr, diese Module in einer Funktion zu importieren, da diese bereits im Speicher sind.

Code: Alles auswählen

>>> import sys
>>> sys.builtin_module_names
('__builtin__', '__main__', '_ast', '_bisect', '_codecs', 
'_codecs_cn', '_codecs_hk', '_codecs_iso2022', '_codecs_jp', 
'_codecs_kr', '_codecs_tw', '_csv', '_functools', '_heapq', 
'_hotshot', '_locale', '_lsprof', '_md5', '_multibytecodec', 
'_random', '_sha', '_sha256', '_sha512', '_sre', '_struct', 
'_subprocess', '_symtable', '_types', '_weakref', '_winreg', 
'array', 'audioop', 'binascii', 'cPickle', 'cStringIO', 'cmath', 
'collections', 'datetime', 'errno', 'exceptions', 'gc', 'imageop', 
'imp', 'itertools', 'marshal', 'math', 'mmap', 'msvcrt', 'nt', 
'operator', 'parser', 'rgbimg', 'signal', 'strop', 'sys', 'thread', 
'time', 'xxsubtype', 'zipimport', 'zlib')
>>> 
Eigentlich ist so ein Import in einer Funktion nur dann eine Alternative, wenn allein der Import eines Moduls und aller seiner Untermodule sehr lang dauert und den Rest des Moduls ziemlich lange bremsen würde. Zum Beispiel bremst der Import von wxPython (wx) den Start des Programmes viel länger als es der Import von z.B. *shelve* machen würde. Auch wenn ich *shelve* nur in einer einzigen Funktion brauche, würde ich *shelve* im Modulkopf importieren. Und wenn ich *wx* nur in einer Funktion brauchen würde, dann würde ich mir überlegen, diese Funktion in einem anderen Modul unterzubringen. Es bringt ja eh nichts, GUI und Logik in einem Bibliotheks-Modul zu vereinen.

Aber im Endeffekt bleibt es deine Entscheidung, wie du deine Python-Module verwaltest und wie du darauf zugreifst. Denn eines ist klar. Funktionieren wird der Import in der Funktion ebenso wie im Modulkopf. Aber wenn du in der Funktion importierst, dann muss es einen spürbaren Vorteil bringen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sechsrad
User
Beiträge: 173
Registriert: Montag 31. März 2008, 17:09

was voellig "Verbotenes" im Sinne von "sauber ist das nicht und sollte man nicht machen" tue oder ob das ok ist.
na, wenn du meinst, dann bau es hinein.

mfg
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

sechsrad hat geschrieben:na, einen eigenen willen und stärke hast du ja nicht.
Hallo sechsrad!

Python ist nicht nur die Programmiersprache. Python ist auch die Art und Weise wie man programmiert. Zu Python gehört, dass man versucht, ein Programm so lesbar wie möglich zu schreiben. Was bei anderen Programmiersprachen komplett nebensächlich ist, wird bei Python als die hohe Kunst gewürdigt.

Hier wird beschrieben, wie ein Python-Programm aufgebaut sein soll: http://www.python.org/dev/peps/pep-0008/
Man sollte sich weitgehendst daran halten. Und wenn man davon abweicht, dann sollte es einen triftigen Grund dafür geben.

Freiheit, JA! Aber nicht ohne vorher darüber nachzudenken.

mfg
Gerold
:-)

Nachtrag:

Code: Alles auswählen

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>> 
.
Zuletzt geändert von gerold am Freitag 9. Mai 2008, 14:17, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
lunar

Geladene Module werden "gespeichert". Bei einem erneuten Import gibt das Statement nur eine Referenz auf das bereits geladene Objekt zurück. Andernfalls wäre reload ja ziemlich sinnlos, oder? ;)

Ein lokaler Import ist eigentlich selten wirklich von Nöten. Zum Vermeiden zirkulärer Imports sollte man sowas eigentlich nicht machen, viele zirkuläre Abhängigkeiten sind eigentlich eher ein Zeichen für ein dringend anstehendes Refactoring ;)

Sinn machen lokale Imports, wenn das betreffende Modul in einer selten verwendeten Funktion steht, aber gleichzeitig sehr groß oder ein 3rd Party Modul ist. Ein Beispiel wäre eine Modul, welches auch als Skript ausgeführt werden kann, und dazu z.B. argparse nutzt, welches nicht Teil der Standardbibliothek ist. In diesem Fall würde ich ``import argparse`` in die ``main`` Funktion aufnehmen, um zu verhindern, dass ein an sich ziemlich nutzlose Modul installiert werden muss, wenn das Modul nur als Modul genutzt wird.

Es gibt auch andere Fälle, aber die sollte man eigentlich immer gut eingrenzen, exzessiver Gebrauch lokaler Imports ist schlechtes Design (würde ich jetzt mal pauschal sagen). Ein erklärender Kommentar an der Seite eines lokalen Imports ist eigentlich auch empfehlenswert.

@sechsrad
*Dein* Ego scheint ziemlich schwach zu sein, wenn du solchen Schwachsinn posten musst, um dich selbst zu bestätigen, und dann noch nicht mal die Ehrlichkeit besitzt, diesen Mist der Kritik auszusetzen, die er verdient.
Zuletzt geändert von lunar am Freitag 9. Mai 2008, 14:17, insgesamt 1-mal geändert.
shakebox
User
Beiträge: 175
Registriert: Montag 31. März 2008, 17:01

danke Gerold fuer die ausfuehrliche Antwort, die meine Vermutungen ziemlich bestaetigt.

Konkreter Fall war dass ich fuer eine der Funktionen ein Fremd-Modul brauchte. Erstens bremst der Import natuerlich alle anderen Funktionen aus, auch wenn das Modul dort gar nicht gebraucht wird. Und viel wichtiger: das Fremd-Modul braucht ne 2.5.x-Version von Python. Es sind aber hier im gemischten Netzwerk auch leider noch nicht alle Rechner auf 2.5.x umgestellt sondern teilweise ist da auch noch 2.3 usw. unterwegs. Daran kann ich als Operator und eben als Nicht-Admin nicht so schnell was aendern.

Dummerweise konnte ich jetzt mein Sammel-Modul und dessen Funktionen insgesamt auf solchen Rechnern nicht nutzen, weil eben immer direkt das Fremd-Modul importiert wurde und dann nen Error gebracht hat, auch wenn ich gar nicht diese Funktion verwenden wollte, die dieses Fremdmodul braucht.

Ich werd es also so machen dass ich die Imports der builtin-Module oben mache und dieses spezielle Fremdmodul dann erst innerhalb der Funktion importiere. Die Funktion wird in Scripts eigentlich auch immer nur 1x verwendet, so dass es auch nicht zu dauernden Import-Checks kommt.

Auch Dir ein wunderschoenes Pfingstwochenende,

Shakebox

PS: der Dank gilt natuerlich auch Dir, lunar. Deine Antwort hab ich erst gesehen als ich meine Antwort schon geschrieben hatte.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

gerold hat geschrieben:Es sollte wirklich einen guten Grund für einen, nicht im Modulkopf stattfindenden Import geben. Ein Import eines __builtin__-Moduls gehört auf jeden Fall in den Modulkopf. Diese Module braucht Python bereits intern. Es bringt also nichts mehr, diese Module in einer Funktion zu importieren, da diese bereits im Speicher sind.
Stimmt nicht. Die sind einfach nur eingebaut aber deswegen noch nicht geladen. Importier sie alle durch und du brauchst einen halben MB mehr RAM.
TUFKAB – the user formerly known as blackbird
BlackJack

@sechsrad: gerold hat etwas aus deinem Beitrag zitiert, was dort jetzt nicht mehr steht. So etwas ist mir neulich schon einmal aufgefallen. Texte nachträglich zu ändern, fördert nicht unbedingt flüssige und verständliche Konversationen. Es wäre schön, wenn Du etwas freundlichere Beiträge verfassen würdest, dann besteht auch kein Grund die Geschichte zu revidieren.
shakebox
User
Beiträge: 175
Registriert: Montag 31. März 2008, 17:01

will mich da als Nicht-Admin/Moderator gar nicht einmischen, aber kann es sein dass da auch ein Fehler des Forums ins Spiel kommt? Bei anderen Beitraegen steht klein drunter dass sie nachbearbeitet wurden. Bei dem von sechsrad steht das aber nicht. Oder hat das damit zu tun dass er das nachbearbeitet hat solange noch keine Antwort gepostet wurde und es deshalb noch nicht als "nachbearbeitet" gilt?
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

shakebox hat geschrieben:Oder hat das damit zu tun dass er das nachbearbeitet hat solange noch keine Antwort gepostet wurde und es deshalb noch nicht als "nachbearbeitet" gilt?
Jep.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Off Topic zu phpBB:

Wenn man's ausschaltet, dass man den letzten Beitrag von sich löschen kann, steht immer drunter wenn man's bearbeitet hat... Soweit ich weiß.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

mitsuhiko hat geschrieben:
gerold hat geschrieben:Es sollte wirklich einen guten Grund für einen, nicht im Modulkopf stattfindenden Import geben. Ein Import eines __builtin__-Moduls gehört auf jeden Fall in den Modulkopf. Diese Module braucht Python bereits intern. Es bringt also nichts mehr, diese Module in einer Funktion zu importieren, da diese bereits im Speicher sind.
Stimmt nicht. Die sind einfach nur eingebaut aber deswegen noch nicht geladen. Importier sie alle durch und du brauchst einen halben MB mehr RAM.
Aha! Dann hat man mir Schwachsinn erzählt und ich habe diesen Schwachsinn weitererzählt. Schade.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich finde völlig okay, dass man imports nur nach Bedarf in einer vielleicht selten benutzen Funktion macht. Man muss allerdings beachten, dass dann beim ersten Aufruf der Funktion das Modul geladen wird, was u.U. spürbare Seiteneffekte haben kann. Und natürlich kostet es danach bei jedem Funktionsaufruf ein paar Mikrosekunden Zeit, zu prüfen, ob das Modul bereits geladen ist.

Stefan
Antworten