Grundlage "import"

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.
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Bin sehr frisch mit Python.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from sqlalchemy import *
#import sqlalchemy
print(__version__)
Der sinnhafte Unterschied zwischen den beiden Import-Varianten ist mir klar.
Bei der hier auskommentierten Variante könnte ich einfach sqlalchemy.__version__ schreiben. Wie ist es bei der anderen Variante? __version__ scheint sich hier (vermutlich aus Sicherheitsgründen) jedoch nicht im globalen Namensraum zu befinden.
Wie könnte ich sowas lösen, ohne auf das einfache import zurückzugreifen?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

MoonKid hat geschrieben:__version__ scheint sich hier (vermutlich aus Sicherheitsgründen) jedoch nicht im globalen Namensraum zu befinden.
Doch, genau im globalen Namensraum befindet sich ``__version__``. Und mit Sicherheit hat das nichts mit Sicherheit zu tun, auch wenn manchmal behauptet wird, dass doppelte Unterstriche den Zugriff auf einen Namen von außen verhindern und damit sicher machen würden. Das ist Quatsch.

Sternchenimporte importieren in den Namensraum des importierenden Moduls. Deshalb kannst Du ja eben ``print(__version__)`` machen.
Wenn nun allerdings das importierende Modul selbst einen Namen ``__version__`` besitzt oder Du nach dem Sternchenimport nochmals einen Sternchenimport eines Moduls machst, das ebenfalls den Namen ``__version__`` verwendet, wird ``__version__`` jedesmal überschrieben. Und genau deswegen solltest Du Sternchenimporte auch vermeiden. Ein weiterer Grund das zu vermeiden ist auch der, dass ein ``sqlalchemy.__version__`` ganz klar ausdrückt, worauf sich ``__version__`` bezieht. Dein Code wird dadurch leichter lesbar und verständlicher.

Wenn man, aus welchen Gründen auch immer, nur Teile eines Moduls importieren möchte, kann man auch ``from sqlalchemy import __version__ as sqlversion`` machen. Damit importierst Du nur die Konstante ``__version__`` in den Namensraum des importierenden Moduls und bindest diese dort an den Namen ``sqlversion``. Oder ``from sqlalchemy import __version__`` ohne einen eigenen Namen für ``__version__`` zu vergeben.

Ich persönlich bevorzuge das Importieren des gesamten Moduls und den Zugriff auf dessen Inhalt über den Punktoperator. Damit weiß ich immer, woher die Dinge stammen...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@mutetella: Außnahmsweise hat das mal doch was mit Sicherheit zu tun, dass nämlich nicht jeder blöde *-Import wichtige Systemvariablen überschreibt. Bei einem *-Import werden nur die Namen importiert, die nicht mit einem _ anfangen (solange nicht ein __all__ etwas anderes vorschreibt).

@MoonKid: trotzdem sollte man keine *-Importe machen, sondern die Namen, die man braucht explizit in den eigenen Namensraum holen, oder über den .-Operator darauf zuzugreifen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Sirius3
Wenn ich mir mal sicher bin... :oops: Again what learned!

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Vielen Dank für die Tips.

Könnt ihr bei der Gelgenheit eine Art Liste empfehlen mit Regeln für elegantes und sinnvolles Pythonschreiben, oder eine entsprechende NO-GO-Liste.

Von C++ kenne ich sowas, da kann man aber auch n bisl mehr Unsinn anstellen.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Apropos No-Gos, dein Shebang geht auch dazu.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

@darktrym: Dann sollte man vielleicht noch erwaehnen, was das entsprechende "Go" waere.

In dem Fall also

Code: Alles auswählen

#!/usr/bin/env python3
BlackJack

Style Guide for Python Code und Python is not Java wären vielleicht erwähnenswert. Und ``import this`` mal ausführen. :-)
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Wobei ich mich frage, warum man den Code auf Python 3 beschränken sollte. Eine 4. wirds wohl nicht geben und 2 ist wohl nicht gewollt? Das Shebang hat die Aufgabe der Shell deutlich zu machen, das nun kein Shellscript folgt und er doch bitte an jenen Interpreter abgeben soll und nicht für die Kompat. einzelner Programmiersprachen zu sorgen. Ich lass die Zahl immer weg.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Man sollte IMHO schon die passende Version dort angeben, also bei Python 3 wäre das ``python3``. Mir ist jedenfalls noch kein System bekannt das als ``python`` *nicht* Python 2.irgendwas verwendet. Wenn man also Python 3 Quelltext schreibt ist nur ``python`` mit an Sicherheit grenzender Wahrscheinlichkeit der falsche Interpreter.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Mit sicher gehender Wahrscheinlichkeit wird das Programm in Zukunft den Dienst versagen wenn nicht stets der symbolische Link von python auf python3 existiert. Ist hier auch schon so, dass ich von 2.7 auf "" linken muss und den gleichen Spaß bei 3.4 auf 3 hab. Im Sinne der Wartbarkeit ist das nicht optimal und innerhalb der Major Version ändern sich schon genug Sachen gerade bzgl. Abwärtskomp.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Irgendwie verstehe ich Deinen Beitrag nicht. ``python`` ist *immer* ``python2`` und ich glaube auch nicht das sich daran innerhalb der nächsten 5 Jahre bis zum offiziellen Ende von Python 2.7 etwas ändern wird und wohl auch mindestens 5 Jahre danach nicht. Wer einen Link von ``python`` auf eine installierte ``python3.x`` legt schiesst sich selbst in den Fuss. Für Windows gibt es ausserdem ja diesen Starter der die Shebang-Zeile anschaut und bei ``python`` ein installiertes Python 2 und bei ``python3`` ein installiertes Python 3 benutzt um die Datei mit der Endung ``.py`` dann tatsächlich auszuführen. Auch der würde nicht mehr richtig funktionieren wenn man bei Python 3 Quelltext nur ``python`` in die Shebang-Zeile schreibt.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

PEP 394 ist legt übrigens fest was genau `python` machen sollte und zwar Python 2 ausführen. Außerdem legt es fest das Skripte *immer* explizit python2 oder python3 benutzen sollten. `/usr/bin/env python` ist also auch nicht akzeptabel.
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

mutetella hat geschrieben:bevorzuge das Importieren des gesamten Moduls und den Zugriff auf dessen Inhalt über den Punktoperator
Verstehe. Das kann ich gut nachvollziehen.

Wie würdest du das hier lösen?

Code: Alles auswählen

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import *
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Uhrzeitbedingt hab ich mich wahrscheinlich unspezifisch ausgedrückt.

Wie gehe ich mit Modulen um, die einen Punkt im Namen haben?
Oder anders: Was genau ist das?

Sind es tatsächlich simple Module mit Punkt im Namen? Oder gibt es tatsächlich, die durch den Punkt suggerierte Hirarchie in den Modulen?
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@MoonKid: Der Punkt ist eine Hierarchie. Und gerade weil sqlalchemy so viele Objekte hat, sollte man sie explizit importieren.
Zum Beispiel:

Code: Alles auswählen

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.types import Integer, Numeric, String, DateTime, Boolean
from sqlalchemy.schema import Column, MetaData, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
Ist jetzt nicht so viel Arbeit und hilft einem wirklich zu wissen, was gebraucht wird.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

MoonKid hat geschrieben:Verstehe. Das kann ich gut nachvollziehen.

Wie würdest du das hier lösen?

Code: Alles auswählen

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import *
Zwar nicht mutella, aber... sowas macht man grundsätzlich nicht. `from ... import *` ist eine nette Hilfe wenn man sich in einer Python Shell befindet, ansonsten ist es unakzeptabel es einzusetzen, es sei das Modul in dem man so importiert sowie das Modul aus dem man importiert sind teil desselben Projekts. Selbst in diesem einen Ausnahmefall in dem es prinzipiell akzeptabel ist, sollte man es nicht ohne Grund tun.
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Sirius3 hat geschrieben:

Code: Alles auswählen

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, relationship
Ist jetzt nicht so viel Arbeit und hilft einem wirklich zu wissen, was gebraucht wird.
Verstehe. Das widerspricht aber dem Vorschlag, alle Modulelemente grundsätzlich mit Ihrem Modulnamen anzusprechen. Also z.B.

Code: Alles auswählen

sqlalchemy.create_engine
Was mache ich mit Untermodulen?

Code: Alles auswählen

import sqlalchemy as sqla
db = sqla.create_engine("...")
ses = sqla.orm.sessionmaker(...)
sqla.ext.declarative.declarative_base...
Sieht irgendwie komisch aus.
BlackJack

@MoonKid: Ja Du hast da jetzt zwei Widersprüchliche Vorschläge bekommen. Weil verschiedene Leute das unterschiedlich handhaben. Sowas aber auch. :-)
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

BlackJack hat geschrieben:@MoonKid: Ja Du hast da jetzt zwei Widersprüchliche Vorschläge bekommen. Weil verschiedene Leute das unterschiedlich handhaben. Sowas aber auch. :-)
:oops: :P Sorry, wollte jetzt niemandem einen "Fehler" vorhalten. :mrgreen:
Mir is natürlich klar, dass es mehr Wege gibt, obwohl Pythons Philosophie sowas ja verhindern möchte.

War eher daran interessiert, welche diversen(!) Lösungsmöglichkeiten erfahrende Python-er so nutzen.
Antworten