Verständnisfrage zum nutzen von Classen

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
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

Grüße mal wieder

Hätte da mal ne Verständisfrage zum nutzen von Klassen.
Kann/darf ich innerhalb einer Klasse eine instanzierte andere Klasse ansprechen (Beispiel),

Code: Alles auswählen

class MyClass1:
    
    def __init__(self):
        pass
    
    def func_one(self):
        pass
    
    
class MyClass2:
    def __init__(self):
        pass
    
    def func_two(self):
        My1.func_one()
        pass
    
My1 = MyClass1()
My2 = MyClass2()

def main():
    My2.func_two()
    
if __name__ == '__main__':
    main()
oder muss ich My1 übergeben?

Code: Alles auswählen

class MyClass1:

    def __init__(self):
        pass

    def func_one(self):
        pass


class MyClass2:
    def __init__(self, oMy):
        self.oMy1 = oMy
        pass

    def func_two(self):
        self.oMy1.func_one()
        pass

My1 = MyClass1()
My2 = MyClass2(My1)

def main():
    My2.func_two()

if __name__ == '__main__':
    main()
Oder müsste das ganz anders aussehen?
Zuletzt geändert von harryberlin am Samstag 20. Februar 2016, 18:14, insgesamt 1-mal geändert.
empty Sig
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Es gibt für beides sinnvolle Anwendungszwecke.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

Also einfacher finde ich Ersteres, weil es weniger Tipparbeit ist.
My1 darf dann halt nicht umbenannt werden.

Hab grad mal beides in Pycharm mit ner simplen print ausgabe getestet.
Läuft auch.
empty Sig
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du willst idR. definitiv Variante 2 verwenden! Bei Variante 1 hast du eine globale Variable, von der die Funktion abhängt. Das solltest Du vermeiden, wo es nur geht.

@DasIch: Welchen sinnvollen Anwendungszweck gibt es denn überhaupt für Variante 1? :K
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Oops, hab mich ganz gewaltig verlesen. Variante 1 nicht ganz abwegig z.B. wenn ich an Flask denke oder die Engine bei SQLAlchemy aber grundsätzlich ist Variante 2 zu bevorzugen.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

Warum geht hier nur die E-Mailbenachrichtigung nicht mehr???

Variante 1 finde ich besser, weil PyCharm dann nach dem Punkt setzen auch die Funktionen der Klasse vorschlägt.

Aber gut, werde es wie in Variante 2 übergeben. Das war ja auch meine Frage.

global ist es eigentlich schon, da ich eine klasse für nen serial port hab. den kann man nur einmal öffnen.
nen zweiten öffnen, steht nicht zur debatte.
empty Sig
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

harryberlin hat geschrieben:global ist es eigentlich schon, da ich eine klasse für nen serial port hab. den kann man nur einmal öffnen.
nen zweiten öffnen, steht nicht zur debatte.
Für Tests könntest du aber einen Mock erstellen und übergeben. Das funktioniert nicht so wirklich wenn alles auf ein globales Objekt zugreift.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

In Kurzform: Vertraue uns! Globale Variablen sind eine schlechte Idee - und zwar in fast jedem Fall! Für einen Anfänger gilt dabei: Sind sie *immer* eine schlechte Idee ;-)

Stell Dir vor, die ``print``-Funktion würde gar keinen Parameter übernehmen, sondern einfach eine bestimmte globale Variable ausgeben. Hier mal ein Beispiel für diese sehr schlechte Lösung:

Code: Alles auswählen

In [1]: def myprint():
   ...:     print(text)
   ...:

In [2]: text = "Hallo Welt!"

In [3]: myprint()
Hallo Welt!

In [4]: for word in "Fuchs Du hast die Gans gestohlen".split():
   ...:     text = word
   ...:     myprint()
   ...:
Fuchs
Du
hast
die
Gans
gestohlen
(Nicht von den "In []" und "Out []" verwirren lassen; das sind lediglich die Prompts der Shell IPython!)

Du siehst schön, wie umständlich das ganze ist! Zum einen wäre ``text`` quasi nie für etwas anderes nutzbar, zum anderen müsstest Du immer eine Zuweisung machen, bevor du etwas ausgeben kannst. Jetzt stell Dir vor, die Standardlib würde so vorgehen - Du müsstest Dir ja hunderte "magische" Namen merken, die Du zum einen verwalten und zum anderen selber nicht für eigene Variablen verwenden dürftest.

Es wird noch gefährlicher, wenn z.B. der Name noch nicht gebunden ist:

Code: Alles auswählen

In [6]: del text

In [7]: myprint()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-7-1a515c1beb4a> in <module>()
----> 1 myprint()

<ipython-input-1-6085ca9e2b89> in myprint()
      1 def myprint():
----> 2     print(text)
      3

NameError: name 'text' is not defined
Dazu kommen noch fortgeschrittenere Sachen wie "Thread Sicherheit" usw., die das ganze noch gefährlicher und weniger kontrollierbar machen. Oder Dinge, wie das Faken von Objekten für Tests, was DasIch angesprochen hat, oder auch alles, was in den Bereich "Interception" fällt, also das "Abfangen" von Objekten und ggf. dem Verändern von deren Funktionalität zur Laufzeit (Decorator-Pattern uvm)

Auch wenn Du faktisch ein Objekt haben wirst, von dem nur ein Exemplar existieren wird, so ist das dennoch kein Grund, dieses global verfügbar zu machen. In vielen Programmen gibt es von vielen Sachen nur ein Objekt - aber man benötigt sie idR. nur für spezielle Sachen, also sollten sie auch nur in diesen Bereichen zur Verfügung stehen.

Edit: Lange nichts mehr gepostet... das Codebox-Problem ist ja ätzend! :(
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

jup passt.
dass man globale variablen nicht nehmen soll, wurde mir schon mitgeteilt.
nur blick ich da auch nicht ganz durch, wo global anfängt und aufhört.
empty Sig
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

harryberlin hat geschrieben:nur blick ich da auch nicht ganz durch, wo global anfängt und aufhört.
Alles was auf Modulebene definiert wird ist global. Der Zustand von allem was global ist sollte sich nicht ändern. Jemand der das Modul importiert, sollte dann unabhängig davon wann das Modul importiert wird und was andere davor schon damit gemacht wurde, immer dass gleiche Modul sehen mit dem gleichen Verhalten.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ergaenzend: Du solltest in Funktionen (bzw Methoden) arbeiten und alle Namen, die du benutzt, sollten entweder Parameter der Funktion, in der Funktion selbst erstellt werden oder durch das Modul importiert werden; dazu kommen noch Klassen- bzw Exemplarattribute bei Klassen.

Wenn du nicht durch einen Blick auf die Funktion und den Modulkopf sagen kannst, was der Name bedeutet, dann arbeitest du falsch.
Antworten