Kellerspeicher und umgekehrte Polnische Notation

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.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Leonidas hat geschrieben:Was soll das soll das ``k`` vor den Namen?
Vielleicht hast du gerade einen KDE-Entwickler enttarnt :D
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

hi,
@Leonidas:
Das `k` vor den Namen steht für "Keller-"
Ich wäre dir verbunden wenn du den Hinweis auf
die Namespaces nochmal in diesem Zusammenhang
erläutern könntest, kapier ich nämlich nicht :?:
Wenn man den Kellerspeicher benutzt benutzt man
doch nur "alphabet":

Code: Alles auswählen

IMkeller = Kellerspeicher(alphabet=[1,2,3,4])
MfG Jonas :D
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

@jonas Die Aufgabenstellung löst dass wohl nicht so ganz und die Underscores bei push und pop gehören da nicht hin. Wenn überhaupt verwendet man zwei vor dem Namen aber hier will man ja von außen darauf zugreifen.
Zu den namespaces kellerspeicher.kalphabet vs. kellerspeicher.alphabet was erscheint dir sinnvoller?

Sinnvoller ist es hier von list zu erben und append(, pop) zu überschreiben.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hi,
@DasIch:
Danke für die hilfreichen Anregungen zum Code.
Wann benutzt man den genau "Underscores"?
Erben von z.B. list werd ich mir nochmal ansehen.
:D

MfG Jonas
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jonas hat geschrieben:Das `k` vor den Namen steht für "Keller-"
Ich wäre dir verbunden wenn du den Hinweis auf
die Namespaces nochmal in diesem Zusammenhang
erläutern könntest, kapier ich nämlich nicht :?:
Ja, aber welchen Sinn haben die ``k``? Es ist schon klar, dass ``alphabet`` zu ``Kellerspeicher`` gehört, es ist ja ein Attribut der Klasse.

Du stimmst mir sicher zu, dass

Code: Alles auswählen

kellerspeicher = Kellerspeicher(['a'])
print kellerspeicher.kalphabet
irgendwie seltsam ist wenn ``kellerspeicher.alphabet`` genauso möglich wäre.

Außerdem hast du da ein Mutables Objekt in der Signatur, das solltest du lassen, denn damit kannst du dir erstaunlich abstruse Fehler einfangen. So wird die Liste nur einmal erstellt und behält ihre Inhalte (statt immer auf [] gesetzt zu werden) - sowas willst du mit hoher Sicherheit nicht haben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hi,
@Leonidas:
Das

Code: Alles auswählen

print kellerspeicher.alphabet
komfortabler ist als

Code: Alles auswählen

print kellerspeicher.kalphabet
damit hast du Recht!
Aber das mit mutable object versteh ich noch nicht so ganz...
Meinst du meine Forensignatur?

MfG Jonas
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Code: Alles auswählen

In [87]: def foo(bar=[]):
   ....:     return bar
   ....:

In [88]: a = foo()

In [89]: a.append('spam')

In [90]: foo()
Out[90]: ['spam']
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jonas hat geschrieben:Aber das mit mutable object versteh ich noch nicht so ganz...
Meinst du meine Forensignatur?
Nein, ich meine die Funktionssignatur von ``__init__``.

Beispiel wo sowas zu Problemen führt:

Code: Alles auswählen

>>> class K(object):
...   def __init__(self, args=[]):
...     args.append(7)
...     self.args = args
... 
>>> k1 = K([1, 2, 3])
>>> k2 = K()
>>> k1.args
[1, 2, 3, 7]
>>> k2.args
[7]
>>> k3 = K()
>>> k3.args
[7, 7]
Wie du siehst, bekommst du da ``[7, 7]`` wo du eher ``[7]`` erwartet hättest.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@jonas: Die doppelten Unterstriche vor und nach dem Namen verwendet man, wenn man eine der "magischen" Methoden implementiert, die eine besondere Bedeutung in der Sprache haben. Zum Beispiel um ein Objekt iterierbar zu machen, Operatoren zu überladen, oder Indexzugriff zu ermöglichen.

Nachtrag: Mit dem Kelleralphabet ist der Kellerspeicher für die Aufgabe nicht brauchbar, oder soll man da wirklich alle Zahlen übergeben, mit denen man rechnen können soll!?

Das Du Fehler mit ``print`` ausgibst, statt Ausnahmen auszulösen und sogar vorhandene Ausnahmen auf diese Weise "verschluckst", ist auch äusserst ungünstig.

Wenn das Programm etwas mit dem Kellerspeicher anstellt, was nicht in Ordnung ist, dann möchte man wohl kaum, dass das Programm sagt, hey hier ist was dummes passiert, und dann einfach weiter macht, als wenn nichts gewesen wäre.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hi,
@Leonidas:
Danke für den für mich persönlich hilfreichen Beitrag.
So etwas, wie in deinem Beispiel zu sehen, wäre natürlich
denkbar schlecht.
@Blackjack:
Danke für die hilfreiche Aufklärung über die "magischen" Methoden.
Mit

Code: Alles auswählen

def irgendeinefunktion ():
    try:
        ## tuEtwas...
    except :
        print """Hallo es gab irgendeinen Error aber
                machen Sie sich mal keine Sorgen..."""
hast du natürlich Recht, auch das wäre denkbar ungünstig.
MfG Jonas :D
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Ein einzelner Underscrore steht für die Dinge, die nicht "öffentlich" sein sollen, also von außen nicht benutzt werden sollen. Das ist aber nur eine Konvention, es wird also nichts erzwungen. Beispielsweise ist ein solcher Einsatz denkbar wenn du eine Klasse erstellst, die eine API implementiert (add_thing, remove_thing, do_somethign_important ...), und dann eine spezialisiertere Klasse erstellst, die von dieser abgeleitet ist. Willst du dort für Ordnung sorgen und etwas in eine eigene Methode auslagern, (zb "_build_important_structure"), kannst / solltest du den Underscore benutzen.

Doppelte Underscores werden einerseits für die "magischen Methoden" verwendet, andererseits kann man damit Dinge vor einem direkten Zugriff "schützen", der von außerhalb erfolgt (auch wenn sie nicht wirklich geschützt sind, man kommt noch über Umwege dran). "Offiziell" wird das aber nur dazu benutzt, um dem Mangel an Schreibweisen in Bezug auf einen bestimmten Namen zu vermeiden.

Praktisch braucht man das nie, außer für magische Methoden.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hi.
@str1442:
str1442 hat geschrieben:[...]Beispielsweise ist ein solcher Einsatz denkbar wenn du eine Klasse erstellst, die eine API implementiert (add_thing, remove_thing, do_somethign_important ...), und dann eine spezialisiertere Klasse erstellst, die von dieser abgeleitet ist.[...]
Ist so eine spezialisierte Klasse z.B. Frog <=> Tkinter ?
MfG Jonas
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

jonas hat geschrieben:Ist so eine spezialisierte Klasse z.B. Frog <=> Tkinter ?
Nein, Frog ist ein gutes Beispiel um zu zeigen wie man soetwas missbrauchen kann um den Nutzer unnötig einzuschränken.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Frog kenne ich nicht.

Aber zb sowas:

Code: Alles auswählen

class AbstractCls(object):
    def add(self):
         pass
    def request(self):
         pass

class Cls(AbstractCls):
    def add(self):
         # Wichtiger Code
    def _do_sth_for_add(self):
        # Mach irgendwas und nutze Instanzvariablen dazu.
Anwendung zb bei Objekten, die alle das gleiche Interface brauchen, aber nicht wissen
sollen, mit wem sie konkret agieren. Da ist "_do_sth_for_add" auch etwas, was diesem Objekt nicht bekannt ist. So kann man damit ganz banal verschiedene Parser für Dateitypen von einem "AbstractParser" ableiten, hoffe du verstehst das Prinzip.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

hi,
str1442 hat geschrieben:So kann man damit ganz banal verschiedene Parser für Dateitypen von einem "AbstractParser" ableiten, hoffe du verstehst das Prinzip.
Sorry aber nicht wirklich :oops:
MfG Jonas
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Naja, Abstrakte Klassen sind ja auch eher wenig gebräuchlich in Python (übrigens würden die dann eher NotImplementedError werfen, statt still und leise mit pass zurückzukehren). Das ist in Java (Interfaces) und Scala (Traits) etwas anders, dort definiert so eine Abstrakte Klasse eine API und die konkreten Klassen implementieren das. Ermöglicht also nichts was nicht in Python auch so schon möglich ist, soll aber wohl etwas mehr Konsistenz sicherstellen (auch wenn ich davon selbst eigentlich nicht besonders überzeugt bin).

Python 3 bietet noch ein etwas anderes Konzept, sogenannte Abstract Base Classes (ABC), aber das werd ich jetzt auch nicht groß diskutieren, bei Interesse einfach in die Dokumentation gucken.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ganz einfach ein Underscore signalisiert dass man das, was auch immer es ist, nicht verwenden oder verändern sollte aber es behindert nicht dabei sollte man es damit etwas anstellen.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

@jonas

Diese Abstrakten Klassen waren nur ein Beispiel. Die Methoden mit Unterstrichen stellen einfach Dinge da, die man nicht verwenden sollte. Meistens sind das Dinge, die die Klasse intern braucht. Abstrakte Klassen finde ich sind da ein gutes Beispiel, da es bei dem Beispiel egal ist, ob du noch 5 andere Unterklassen von "AbstractCls" hast, da alle die grundlegenden Operation von "AbstractCls" benutzen. Und genau diese sind nur anderen Objekten, die damit umgehen sollen, bekannt. Insofern macht es keinen Sinn, "_do_sth_with_add" ohne Unterstrich zu schreiben, da die Methode sowieso keinem anderem Objekt bekannt ist und somit auch nicht dafür gedacht ist, von diesen verwendet zu werden. Der Unterstrich signalisiert also "Achtung, verwende mich nicht, wenn du nicht weißt, was du machst!". In dem "AbstractCls" Beispiel könnte zb jemand diese Methode verwenden, weil er denkt, jede Klasse hätte sie und sie gehört zur "Api", obwohl sie ja nur zur "Cls" gehört. ---> "NameError: ....".

Generell sind Unterstriche zum Zweck, den DasIch auch schon erläutert hat, gedacht. Das ist nur ein Anwendungsfall.

@Leonidas:

Die einzelnen Methoden müssen ja nicht einfach durchgehen. In Java ist das afaik ja zwingend, das man eine interface Methode nicht weiter spezifieren kann. Aber wenn 5 verschiedene Parser beispielsweise sowieso immer ~3 Methoden haben, die komplett gleich sind, unterscheidet sich das nicht vom normalen Einsatzzweck von Vererbung.

Statt dem NotImplementedError gibts auch das NotImplemented Singleton. Wäre wohl besser, das zurückzugeben. Zumindest meine ich, das sollte man auch machen (hab da irgendwas, was mit Dive into Python in Verbindung steht, im Hinterkopf).
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

str1442 hat geschrieben:Die einzelnen Methoden müssen ja nicht einfach durchgehen. In Java ist das afaik ja zwingend, das man eine interface Methode nicht weiter spezifieren kann. Aber wenn 5 verschiedene Parser beispielsweise sowieso immer ~3 Methoden haben, die komplett gleich sind, unterscheidet sich das nicht vom normalen Einsatzzweck von Vererbung.
Ja, natürlich, aber funktionen die implementiert werden sollten, sollten Ausnahmen werfen. Sonst kann man sie auch einfach nicht implementieren und sich wundern warum dann an seltsamen Stellen ``None`` auftaucht. Ich finde es ähnlich wie du auch wenig sinnvoll wenn man in Interfaces nicht auch teile der Implementation haben kann. In Scalas Traits ist das anders, dort kann man in den Traits schon eine Implementation haben aber wenn man abstrakte Methoden des Traits nicht implementiert, wird es nicht kompilieren. Sowas kann man eben mit normalen Klassen und NotImplementedError auch haben; allerdings zur Laufzeit.
str1442 hat geschrieben:Statt dem NotImplementedError gibts auch das NotImplemented Singleton. Wäre wohl besser, das zurückzugeben.
Wieso? Statt ``None`` wird man dann ``NotImplemented`` im Programm umherfliegen haben und man darf dann den Debugger anwerfen um festzustellen welche Funktion nicht implementiert wurde. Da finde ich Ausnahmen wesentlich besser, weil eben der letzte Frame im Traceback der Funktion entspricht, die man überschreiben muss.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Wieso? Statt ``None`` wird man dann ``NotImplemented`` im Programm umherfliegen haben und man darf dann den Debugger anwerfen um festzustellen welche Funktion nicht implementiert wurde. Da finde ich Ausnahmen wesentlich besser, weil eben der letzte Frame im Traceback der Funktion entspricht, die man überschreiben muss.
Wie gesagt, ich meine nur irgendwo mal was diesbezüglich gelesen zu haben. Ansonsten ist eine Ausnahme wohl besser geeignet, ja. Welchen Zweck hat aber NotImplemented, wenn man es sowieso nie zurückgeben sollte? Gibt ja dann eigentlich keinen Einsatzzweck mehr dafür.
Antworten