Anfängerkurs in Python bei Coursera

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.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Dann hat sein Stabilitätsargument schon etwas.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

mal ganz sachlich betrachtet: was gewinne ich, wenn ich auf Attribute mit einem Getter zugreife?
- z.B: »game.get_level()«, heißt soviel wie, oh dafür gibt es eine Funktion, also darf ich das Attribut auch lesen.
Das sagt mir aber noch nicht, dass das für meinen Anwendungsfall auch sinnvoll ist. Genauso gut könnte ich auch direkt »game.level« schreiben und in die Klassendokumentation schreiben, dass »level« ein öffentliches Attribut ist und dies und das bedeutet.
Was kann ich falsch machen? Ich kann mich verschreiben, was in beiden Fällen zu einem AttributeError führt.
Fazit: ein Getter bietet mir keinen Vorteil, es führt nur zu umständlicherem, komplexerem und langsamerem Code.

Nun zu den Settern: »game.set_level(3)«. Wenn es diese Methode nicht gibt, heißt das soviel wie, das Attribut ist von außen read-only. Aber das kann ich genauso gut erreichen, wenn ich in die Dokumentation hinter »level« „read-only“ schreibe. Wenn sich dann jemand nicht daran hält, wird er schon genau wissen, was er tut, oder eben nicht, dann ist ihm aber auch nicht mehr zu helfen.
Wenn ich mich beim Setzen verschreibe kann das zu schwer auffindbaren Fehlern führen, weil das Problem nicht sofort gemeldet wird. Ein falsch geschriebener Setter meldet sich sofort mit einem AttributeError. Andererseits sollten Programmteile sowieso nicht so komplex und nicht getestet sein, dass sich ein solcher Fehler lange verstecken kann.
Fazit: auch Setter haben nicht wirklich einen Vorteil.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

meego hat geschrieben:Dann hat sein Stabilitätsargument schon etwas.
Das wurde doch eben von /me widerlegt…

Was wir brauchen sind Getter für Setter! Denn Getter sind ja auch nur Attribute, auf die kann man ja auch zugreifen oder sie *gasp* editieren. Da würde ich empfehlen auf Nummer sicher zu gehen und für die Setter auch Getter schreiben, ``class.get_setter('level').set(42)``. Ohnein, jetzt ist der ``get_setter`` auch ein öffentliches Attribut das man ebenfalls editieren kann, und dann gehen alle Setter kaputt! Wir brauchen einen ``class.get_setter_getter().get_setter('level').set(42)``. Verdammt, nun wiederholt sich das Problem. Vielleicht eine ``GetSetterFactory`` probieren? Wir könnten die Getter und Setter aber auch aus dem Quellcode rausnehmen und in einer XML-Datei konfigurieren. ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Ein bißchen off-topic, aber zum Kapseln ganz wichtig:

Code: Alles auswählen

import inspect

def protected(func):
    def check(self, *args,**kw):
        caller=inspect.stack()[1][0]
        caller_cls=type(caller.f_locals.get('self'))
        assert caller_cls in self._FRIENDS, "protected method call"
        return func(self, *args,**kw)
    return check

class MyFriend(object):
    def __init__(self, obj):
        print obj.get_value()

class ILikeCpp(object):
    _FRIENDS = [MyFriend]
    
    def __init__(self, value):
        self.__value = value # double __ for extra security
    
    @protected
    def get_value(self):
        return self.__value
    
if __name__ == '__main__':
    obj = ILikeCpp(23)
    MyFriend(obj)
    print obj.get_value()  # not allowed
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

meego hat geschrieben:Dann hat sein Stabilitätsargument schon etwas.
Nicht im Kontext von Python.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

meego hat geschrieben:The mangling, however, is predictable, so it still doesn't prevent external access."
Dieses Kurszitat ist in dem Kontext auch nicht richtig. Technisch stimmt es zwar, hat aber nichts mit der Kapselung privater Codestellen zu tun, sondern ist als Python-Sprachmittel zur Umgehung von Namenskollisionen bei Vererbungshierarchien gedacht. Als solches sollte es auch vermittelt werden — statt dessen wird es zumeist im Zusammenhang mit "privaten" Variablen eingeführt und fälschlicherweise auch oft so verwendet.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

"was gewinne ich, wenn ich auf Attribute mit einem Getter zugreife?"

M.A. wird der Code damit sehr viel übersichtlicher.
BlackJack

@meego: Warum? Was ist an `spam.get_parrot()` übersichtlicher als `spam.parrot`? Das kann ich nicht nachvollziehen.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Beim Aufruf gibt es wenige Unterschiede, aber innerhalb des Moduls wird ggf. klarer, welche Attribute öffentlich gedacht sind.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Kebap: Nein, wird es nicht. Ein führender Unterstrich genügt völlig. Und falls Du unbedingt einen getter/setter brauchst, kann Du eine entsprechende property anlegen.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

BlackJack hat geschrieben:@meego: Warum? Was ist an `spam.get_parrot()` übersichtlicher als `spam.parrot`? Das kann ich nicht nachvollziehen.
Normalerweise will man ja eher nicht auf eine einzelne Variable zugreiffen. Wieso also bei Einzelattributen auf andere Konzepte ausweichen? Mir kommt das etwas inkonsistent vor.
BlackJack

@meego: Sorry, das verstehe ich nicht. Natürlich will man auch auf einzelne Variablen zugreifen. Wenn Du `spam.get_parrot()` schreibst, dann willst Du ja auf den `parrot`-Wert zugreifen. Warum soll alles was auf einem Objekt als Attribut vorhanden ist, aufrufbar sein? Zumal das ja im Gegensatz zur Standardbibliothek und den meisten Modulen von Drittanbietern inkonsistent wäre. Denn dort gibt es ja nicht nur aufrufbare Objekte als Attribute.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Gehn wir mal einen Schritt zurueck: Getter, Setter und Attributszugriffe (von aussen) sind alle aus dem gleichen Grund schlecht: Man weiss zuviel ueber andere Klassen.

Stattdessen sollte man eben Methoden aufrufen, die auf dem Zustand operieren, so wie Gott^WAlan Kay das wollte.

Warum man nicht auf eine einzelne Variable (besser: Namen) zugreifen will, ist mir allerdings ein Raetsel. Was ist denn ein Getter, wenn nicht ein umstaendlicher Attributszugriff?
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

BlackJack hat geschrieben:@meego: Sorry, das verstehe ich nicht. Natürlich will man auch auf einzelne Variablen zugreifen. Wenn Du `spam.get_parrot()` schreibst, dann willst Du ja auf den `parrot`-Wert zugreifen.
Ich find's halt übersichtlicher, wenn es explizit als Methode daherkommt.
Warum soll alles was auf einem Objekt als Attribut vorhanden ist, aufrufbar sein?
Ich dachte, in Python wäre alles irgendwie als Attribut vorhanden.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

meego hat geschrieben:Ich find's halt übersichtlicher, wenn es explizit als Methode daherkommt.
Du magst es gewohnt sein, aber vergleiche das folgende:

Code: Alles auswählen

class Car(object):
    color = 'red'
    
    def get_color():
        return self.color
    
my_car = Car()
print my_car.get_color()

# versus:

class Car(object):
    color = 'red'
    
my_car = Car()
print my_car.color
Bei kurzen Beispielen mag man die zusätzliche Methode und den damit einhergehenden umständlichen Aufruf ja noch verschmerzen, aber stelle Dir mal ein umfangreiches Programm vor, das auf diese Weise — ohne Mehrwert — künstlich aufgebläht wird.
BlackJack

@meego: Objekte haben Attribute, aber nicht jedes Attribut ist aufrufbar. Genau das forderst Du aber weil das übersichtlicher sein soll. Letztendlich forderst Du das es Datenattribute geben müsste, die man nicht direkt abrufen kann. Also zumindest nicht ausserhalb von Methoden auf dem Objekt.

Wie stehst Du zu der Aussage das die vielen dann nötigen trivialen Getter und Setter den Quelltext einer Klasse nur unnötig aufblähen und damit unübersichtlicher machen, weil man diesen Boilerplate-Code immer ignorieren muss, beziehungsweise genau hinschauen muss, ob die wirklich trivial sind, oder vielleicht doch etwas machen? Und innerhalb von Methoden auf der Klasse muss man sich dann immer entscheiden ob man auf das Attribut direkt zugreift, oder über die Getter/Setter.

Das hier:

Code: Alles auswählen

class A(object):
    def __init__(self):
        self._spam = 42
        self._parrot = 23

    def get_spam(self):
        return self._spam

    def set_spam(self, value):
        self._spam = value

    def get_parrot(self):
        return self._parrot

    def set_parrot(self, value):
        self._parrot = value

    def modify(self):
        self.set_parrot(self.get_parrot() * 2 + self.get_spam())
ist übersichtler als das hier

Code: Alles auswählen

class A(object):
    def __init__(self):
        self.spam = 42
        self.parrot = 23

    def modify(self):
        self.parrot = self.parrot * 2 + self.spam
?

Und wozu bietet die Sprache Properties wenn man immer Getter und Setter schreiben würde?
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

BJ:
Objekte haben Attribute, aber nicht jedes Attribut ist aufrufbar. Genau das forderst Du aber weil das übersichtlicher sein soll. Letztendlich forderst Du das es Datenattribute geben müsste, die man nicht direkt abrufen kann.
Was fordere ich jetzt? Ich sehe Scotts Punkt da schon, grosse Programme würden dadurch erheblich stabiler.
Wie stehst Du zu der Aussage das die vielen dann nötigen trivialen Getter und Setter den Quelltext einer Klasse nur unnötig aufblähen und damit unübersichtlicher machen.
Codefolding?
Und wozu bietet die Sprache Properties wenn man immer Getter und Setter schreiben würde?
Java wird auch Properties haben. Die Frage scheint mir eher, wie sehr man auf OOP setzt und ob man alleine oder in einem Team an etwas arbeitet.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

meego hat geschrieben:Was fordere ich jetzt? Ich sehe Scotts Punkt da schon, grosse Programme würden dadurch erheblich stabiler.
Ich sehe den Punkt dagegen nicht, warum soll denn ein Attributszugriff durch eine Methode passieren? Große Programme werden nicht durch mehr Methoden stabiler, sondern dadurch dass man Zuständigkeiten absteckt. Dazu braucht man keine Zugriffsrechte und schon gar keine Methoden, sondern allein Konventionen.
meego hat geschrieben:
Wie stehst Du zu der Aussage das die vielen dann nötigen trivialen Getter und Setter den Quelltext einer Klasse nur unnötig aufblähen und damit unübersichtlicher machen.
Codefolding?
Code der existiert muss gewartet werden.
meego hat geschrieben:
Und wozu bietet die Sprache Properties wenn man immer Getter und Setter schreiben würde?
Java wird auch Properties haben. Die Frage scheint mir eher, wie sehr man auf OOP setzt und ob man alleine oder in einem Team an etwas arbeitet.
[/quote]

Java hat Properties, aber die bedeuten etwas anderes. Java hat dagegen nichts mit dem man Attributszugriffe transparent durch Funktionen bzw Funktionsaufrufe ersetzen kann.
Das Problem hat nichts mit OOP im eigentlichen Sinne zu tun, sondern ganz allgemein mit dem Arbeiten mit Abstraktionen und Schnittstellen. Man arbeitet nicht deshalb objektorientiert, weil man Getter und Setter hat.

Letztendlich muss man auf den Boden zurückkommen und einsehen: Wir arbeiten mit Python und Python hat keine Zugriffsbeschränkungen für Attribute. Wenn man dennoch darauf beharrt, arbeitet man gegen die Sprache und gegen die Community, die auf Konvention setzt.
BlackJack

@meego: Mir ist kein Editor bekannt der solches Code-Folding beherrscht. Und wenn man triviale Getter und Setter durch Code-Folding wieder ausblenden muss, warum muss man sie denn dann überhaupt *schreiben*. Du sagst doch durch den Boilerplate-Code wird es übersichtlicher. Wenn es übersichtlich wäre, müsste man es doch nicht ausblenden, denn es wäre ja übersichtlicher wenn es *da* ist.

Java hat keine Properties im Sinne von Python (oder C#, D, Vala). Genau *deswegen* schreibt man in Java ja auch triviale Getter und Setter. Nur deshalb ist das dort notwendig wenn man den Code mal ändern will ohne das sich die Schnittstelle nach aussen ändert.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

meego hat geschrieben:[…] grosse Programme würden dadurch erheblich stabiler.
[…] Die Frage scheint mir eher, wie sehr man auf OOP setzt und ob man alleine oder in einem Team an etwas arbeitet.
Ich habe mir jetzt mal verschiedene kleinere Projekte angeschaut (Sqalchemy, django, bottle, mercurial, numpy) Keines davon benutzt Getter oder Setter.
Im Gegenteil: vielfach wird versucht, möglichst viel wie einen Attributzugriff aussehen zu lassen, weil es die bequemste und übersichtlichste Art ist Informationen abzufragen oder zu setzen.

Weil ich es neulich in meiner Excel-Klasse hatte (nicht gerade schön aber für Datenhaltungsklassen praktisch):

Code: Alles auswählen

cell.border.left.color = cell.border.right.color = Color.red
Versuch das mal mit Setter und Getter hinzubekommen. Übrigens so ähnlich auch in VBA für Excel zu schreiben, eine Sprache, die auch maximal gegen Getter eingestellt ist.
Antworten