Fragen zur OOP

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
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

Ich arbeite mich gerade durch das offizielle Python-Tutorial und habe ein paar Probleme mit dem Kapitel "Klassen":
  • Was genau ist ein Namensraum? In der Doku steht: "Zuordnung von Namen zu Objekten". Aber wie genau kann ich mir das vorstellen?
  • Was ist ein Gültigkeitsbereich? (scheitert vor allem an meinem fehlenden Verständnis von Namensräumen)
  • Ein Klassenobjekt ist eine Verpackung um den Inhalt des Namensraums, der von der Klassendefinition erstellt wurde. Wie ist das gemeint? Wie sieht sowas konkret aus?
  • Was sind Methodenobjekte?
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

welches Tutorial hast du den gelesen (Link) - das offizielle Tutorial ist ja englisch, du verwendest deutsche Begriffe. Hast du ein Übersetzung gelesen oder ist das dein Übersetzung?

Gruß, noisefloor
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ein Namensraum ist ein (ggf gedachter) Ort, an dem bestimmte Namen existieren. Du heißt vielleicht Peter, aber wenn du mit deinen Kumpels auf Bootstour bist, dann bist du vielleicht “Beule”. Die Bootstour (bzw der Freundeskreis) sind also ein Namensraum. Wichtig hierbei ist die Beobachtung, das ein und dasselbe Ding oder Person mehrere Namen haben kann!

In Python sind zb Module Namensräume. Wenn du “import sys” machst, kannst du mit sys. vorangestellt auf die Namen in sys zugreifen. Wenn du ein Skript startest, hat das auch einen impliziten Namensraum, __main__. Wenn du in diesem Skript eine Funktion foo definierst, dann ist der Code der Funktion aufzufinden eben unter dem Namen foo.

Du kannst namensräume auch zusammenfassen: wenn im Skript “from sys import argv” steht, dann wird argv ein Name in __main__.

Ein Gültigkeitbereich ist auch ein Namensraum. Wenn du ein foo eine Variable bar anlegst, ist die nur in dem Gültigkeitsbereich der Funktion, und vor allem auch nur wenn die aufgerufen wird (in erster Näherung. Closures machen das etwas komplizierter), existent.

Du kannst auch eine Variable argv in foo definieren. Die hat dann Vorrang vor dem mit from... importierten Namen!

Code: Alles auswählen

from sys import argv

def foo():
      argv = 10
      print(argv)

foo()
Eine Klasse stellt nun eine Art Schablone zur Erzeugung von namensräumen dar! Ein Name, den du in der Klasse im Inititialisator erzeugt hast, gilt nur innerhalb des namesnraumes einer Objektinstanz. Du kannst aber 100 Objekte aus der gleichen Klasse machen.

Dein Auto ist zb ein BMW Q7. Der hat ein Lenkrad, das du nur anfassen kannst, wenn du im Auto sitzt. Aber dein Nachbar hat auch einen Q7 mit Lenkrad. Das ist ja aber ein anderes Lenkrad. BMW Q7 ist als die Klasse, und Lenkrad der Name für das Ding an dem du kurbelst um die Richtung zu ändern - aber NUR wenn du im Auto sitzt, also Zugriff auf das Auto hast.
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

@noisefloor: Ich verwende die deutsche Übersetzung: http://py-tutorial-de.readthedocs.io/de/python-3.3/

@__deets__: Danke für deine ausführliche Antwort.
  • Mir ist nur noch nicht ganz der Unterschied zwischen Namensraum und Gültigkeitsbereich klar. Ein Gültigkeitbereich ist auch ein Namensraum. Gibt es auch Namensräume, die kein Gültigkeitsbereich sind? Ist beides letztendlich das Gleiche?
  • Was ist in deinem Beispiel mit dem BMW Q7 genau das Klassenobjekt? Zum Beispiel der Q7 vom Nachbarn?
  • Was wäre in dem Beispiel ein Methodenobjekt?
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Variablen, Attribute und Funktion / Methoden haben einen Gültigkeitsbereich, der sich auf den Namensraum bezieht, in dem sie existieren. Dabei dürfen sie auch, wie im Tutorial steht, gleiche Namen haben, weil der Name an den Namensraum gebunden ist und es deswegen keine Kollisionen gibt. Beispiel:

Code: Alles auswählen

>>> def foo():
...     x = 5
...     print(x)
... 
>>> x = 10
>>> x
10
>>> foo()
5
>>> x
10
>>> def bar():
...     print(x)
... 
>>> bar()
10
>>> x
10
>>>
Die Funktion `foo` definiert x, diese x ist aber nur im Namensraum von `foo` gültig und kollidiert nicht mit dem x, was auf oberster Ebene (`x=10` ) definiert ist. In der Funktion `bar` ist kein x definiert, aber die Funktion "kennt" auch den globalen Namensraum und gibt darum `10` aus.

Zur Klasse bzw. zum Auto, Beispiel:

Code: Alles auswählen

>>> class Car:
...     def __init__(self, make, model):
...         self.make = make
...         self.model = model
...     def full_description(self):
...         return 'Das Auto ist ein {} {}'.format(self.make, self.model)
... 
>>> mein_auto = Car('BMW', 'X7')
>>> nachbar_auto = Car('BMW', 'X7')
>>> id(mein_auto)
139755601467880
>>> id(nachbar_auto)
139755601468048
Du hast eine Klasse `Car` und kreierst davon zwei Instanzen, dein Auto und das Nachbarsauto. Obwohl es gleich ist, bekommst du zwei neue Objekte (zu erkennen an den unterschiedlichen id) für dein und das Nachbarsauto.

Zum Methodenobjekt, Beispiel:

Code: Alles auswählen

>>> mein_auto.full_description
<bound method Car.full_description of <__main__.Car object at 0x7f1b628fac50>>
>>> mein_auto.full_description()
'Das Auto ist ein BMW X7'
>>>
Beim 1. Aufruf bekommst du das Methodenobjekt, beim 2. wird die Methode ausgeführt. Letzteres ist das, was man üblicherweise will. Die könntest das Methodenobjekt auch an einen weiteren Namen binden, aber das braucht man IMHO eher selten bzw. am Anfang eher nicht. Es reicht zu wissen, dass das geht.

Gruß, noisefloor
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Hier geht die Definition von Namensräumen, Objekten und Attributen etwas durcheinander.

Namensräume sind verschachtelt, also ein Name der nicht im aktuellen Namensraum definiert ist, wird im übergeordneten gesucht.
Der oberste Namensraum ist der Builtin-Namensraum, also alle Funktionen und Objekte, die einfach da sind. Dann kommt das Modul als Namensraum. Jede Funktion und Subfunktion und Subsubfunktion stapelt wieder je einen Namensraum oben drauf.

Klassen bilden bei ihrer Definition wieder ihren eigenen Namensraum, der nur während der Definition existiert, insbesondere nicht, wenn man eine Methode der Klasse ausführt.

Code: Alles auswählen

foo = 5
class Bar:
    foo = 9
    print(foo)

    def __init__(self):
        print(foo)

bar = Bar()
Alles was mit Instanzen von Klassen und deren Attribute zu tun hat, sind keine Namensräume, auch wenn die Auflösung von Attributen einer ähnlichen Hierarchie folgt.

Gültigkeit ist nur die Tatsache, dass man nur auf Namen innerhalb des aktuellen und aller übergeordneten Namensräume zugreifen kann.
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

Vielen Dank für die zahlreichen Antworten. Das hilft auf jeden Fall weiter :)
Antworten