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

Ich muss sagen: Meine Grenze ist wohl langsam erreicht. Die mehrstufigen Loops bei den Dictionaries waren mir zu schnell. Didaktisch war das bestimmt auch nicht ganz optimal von Scott. Jedenfalls nicht für Newbies.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

@meego: ich denke Du meinst diese Funktion, richtig?

Code: Alles auswählen

# CIPHER und message sind globale Variabalen
def decode():
    dmsg = ""
    for ch in message:
        for key, value in CIPHER.items():
            if ch == value:
                dmsg += key
    print message, "decodes to", dmsg
Das Hantieren mit globalen Variablen ist natürlich nicht so gut überschaubar, leider mussten sie deren "simplegui" dranbringen, bevor Sie Objekte/Klassen durchnehmen...

Er wählt auch u.a. die Bezeichner nicht einsteigerfreundlich, da muss ich auch oft 2x überlegen:

Code: Alles auswählen

def decode():
    decoded_message = ""
    for character in encoded_message:
        for key, value in CIPHER.items():
            if character == value:
                decoded_message += key
    print encoded_message, "decodes to", decoded_message
Ansonsten finde ich diese doppelte for-Schleife nicht so schwierig, die 2. Schleife brauchst Du ja nur, weil man Dictionarys nicht nach Values durchsuchen kann, deshalb musst Du Dir jedes Item einzeln ansehen.

Hoffe geholfen zu haben :-)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum kann man in Kursen nicht mit den Grundfunktionen anfangen, »join«, »map«, wozu Dictionaries einzig und alleine da sind?

Code: Alles auswählen

DECIPHER = dict((value, key) for key, value in CIPHER.items())
def decode(encoded_message):
    return ''.join(map(DECIPHER.get, encoded_message))

print encoded_message, "decodes to", decode(encoded_message)
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

@Sirius: ich denke die haben einen eigenen Parser/Crosscompiler gebaut, der zu Javascript kompiliert:
http://www.codeskulptor.org/docs.html

Jedenfalls passiert alles im Browser, und der kann ja leider kein Python :(
map() gibt's da nicht (genausowenig wie enumerate() :evil: )
BlackJack

Dann ist die Kursbeschreibung aber ziemlich irreführend. Da kann man ja gar nicht wirklich Python lernen.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Python 2.7 hat ungefähr 50 Builtin-Funktionen von denen die meisten in einer Zeile implementiert sind:

Code: Alles auswählen

def map(func, *iterables):
    return [func(*el) for el in zip(*iterables)]

def enumerate(iterable, start=0):
    i=start
    for el in iterable:
        yield i, el
        i+=1
:K
Das Schreiben, dass sie »unsupported« sind, dauert da wahrscheinlich länger.
http://www.codeskulptor.org/docs.html hat geschrieben:Unsupported Sequence & Iterable Operations
max() and min() with key argument. zip() with one argument. map() filter() reduce()
Wobei zip mit einem Argument tut, und max,min den key einfach ignorieren anstatt eine ordentliche Fehlermeldung zu melden.

Der Code sieht etwas umständlich aus, aber es gibt noch weitere Einschränkungen:

Code: Alles auswählen

def max(*args, **kw):
    if kw and 'key' not in kw:
        raise TypeError("max() got an unexpected keyword argument")
    if len(args)==1:
        args=args[0]
    if not args:
        raise ValueError("max() arg is an empty sequence")
    key = kw.get('key', lambda x: x)
    max_k = undef = []
    for el in args:
        k = key(el)
        if max_k is undef or max_k<k: max_el, max_k = el, k
    return max_el 

def filter(func, seq):
    if func is None: func=bool
    result = [func(el) for el in seq]
    if isinstance(seq,str):
        return ''.join(result)
    if isinstance(seq,tuple):
        return tuple(result)
    return result
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Mit der neuen Lektion "Object-oriented Programming" wird's tatsächlich noch unpythonischer :-(
Zitat aus dem Video zu dieser Klasse:
"...i've created an interface ... i've given you no way to decrease the health of this character..."

Code: Alles auswählen

class Character:
    def __init__(self, name, initial_health):
        self.name = name
        self.health = initial_health
        self.inventory = []
        
    def __str__(self):
        s  = "Name: " + self.name
        s += " Health: " + str(self.health)
        s += " Inventory: " + str(self.inventory)
        return s
    
    def grab(self, item):
        self.inventory.append(item)
        
    def get_health(self):
        return self.health
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

mcdwerner hat geschrieben:@meego: ich denke Du meinst diese Funktion, richtig?

Code: Alles auswählen

def decode():
    decoded_message = ""
    for character in encoded_message:
        for key, value in CIPHER.items():
            if character == value:
                decoded_message += key
    print encoded_message, "decodes to", decoded_message
Exakt. Ich glaube es ungefähr verstanden zu haben. Eine Schleife über jeden Buchstaben des Wortes. Und darin nochmal eine Schleife über das ganze Dictionary für jeden Buchstaben.

Aber anwenden könnte ich das selber noch nicht.

Ansonsten bin ich immer noch mit Memory beschäftigt. Wenn ich mir den Einblick in nächste Woche so anschaue vergeht mir die Lust.
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Hier nimmt Scott Stellung zu eurem Religionskrieg:
https://class.coursera.org/interactivep ... ad_id=5787
BlackJack

@meego: Der Link führt mich auf die Kursübersichtsseite. Um das Forum lesen zu können muss man wahrscheinlich dort angemeldet sein.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

dann zitier ich hier mal sein Hauptargument:
This allows you to achieve isolation and encapsulation and leads to more robust programs.
Edit: eigentlich ist es sein einziges Argument
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mcdwerner hat geschrieben:dann zitier ich hier mal sein Hauptargument:
This allows you to achieve isolation and encapsulation and leads to more robust programs.
Edit: eigentlich ist es sein einziges Argument
Mal abgesehen davon, dass es in Python so etwas wie private Attribute überhaupt nicht gibt. Es gibt sie zumindest nicht in der Form, dass ein Zugriff technisch unterbunden wird.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Ich hab jetzt nochmal eingehender drüber nachgedacht.

Das Argument, das ja immer für "ungeschützte Attribute" ins Feld gebracht wird ist doch:
"We are all consenting adults"
auf gut deutsch: "Wenn Du ein Attribut veränderst, dann überleg Dir zuerst, was Du da tust"
In Python geht das ja auch, da ich den Quellcode aller verwendeten Klassen zur Verfügung habe (was auf kompilierte Sprachen nicht immer zutrifft).
Ein Anfänger ist davon jedoch schnell überfordert und froh, wenn er eine setter-Methode hat, die ihm (für's Erste) das Denken abnimmt...

nur meine 50ct...
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Dann zitier ich ihn mal auf die Frage hin: "By default in python it seems that you can add fields to an existing class and alter the value of an objects fields directly without method calls. [...] Is there a way to protect fields and classes so that they cannot be externally altered?"

"Python classes do not provide any real protection here. As you've pointed out, you can access fields directly from outside the class. In my opinion, this is bad. In many Python programmers' opinions, this is great. It depends, I suppose on what you are hoping to achieve with a class.

My strong recommendation is "don't do this". Certainly for this class (especially if you are a beginner) you should not access fields directly like this. Only access fields through class methods. This allows you to achieve isolation and encapsulation and leads to more robust programs.

The Pythonic way of "hiding" fields is to prefix them with "_" or "__". When you use "_", such as "self._hidden", you are giving a hint to anyone reading the code that they should never access that field directly. It doesn't actually prevent such access. When you use "__", such as "self.__hidden", Python actually changes (or mangles) the variable name. The mangling, however, is predictable, so it still doesn't prevent external access."
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

meego hat geschrieben:Dann zitier ich ihn mal auf die Frage hin: "[...]

My strong recommendation is "don't do this". Certainly for this class (especially if you are a beginner) you should not access fields directly like this. Only access fields through class methods. This allows you to achieve isolation and encapsulation and leads to more robust programs."
Wenn man eine Bondage&Discipline-Sprache haben möchte, dann kann man Java nehmen. Python gibt einem viel Freiheit und damit viel Flexibilität.

In Python gewinnt man nichts dadurch, dass man den Zugriff auf Instanzattribute nur über Getter und Setter zulässt. Der typische angesprochene Anwendungsfall bezieht sich darauf, dass es ja irgendwann sein kann, dass man beim Zugriff auf das Attribut noch zusätzliche Berechnungen durchführen möchte. In Java wäre das tatsächlich ein Problem, da bei der Umstellung von einem direkten Zugriff auf den Zugriff mit Getter/Setter die Kompatibilität der Klasse dahin ist. In Python ist das nicht so. Dort kann man problemlos später auf Properties umstellen ohne dass sich irgendetwas für den zugreifenden Code ändert.

Python erlaubt einem unglaublich viel. Man sollte nur den Satz aus Spider-Man beachten: "With great power comes great responsibility".
meego
User
Beiträge: 380
Registriert: Montag 4. März 2013, 14:36

Dann hat sein Stabilitätsargument schon etwas.
Sirius3
User
Beiträge: 17741
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: 17741
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.
Antworten