it-swarm-eu.dev

Warum brauchen Sie explizit das "Selbst" -Argument in einer Python-Methode?

Wenn Sie eine Methode für eine Klasse in Python definieren, sieht diese in etwa folgendermaßen aus:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

In einigen anderen Sprachen, z. B. C #, haben Sie jedoch einen Verweis auf das Objekt, an das die Methode mit dem Schlüsselwort "this" gebunden ist, ohne es als Argument im Prototyp der Methode anzugeben. 

War dies eine beabsichtigte Sprachentwurfsentscheidung in Python oder gibt es einige Implementierungsdetails, die die Übergabe von "Selbst" als Argument erfordern?

180
Readonly

Ich zitiere gern Peters 'Zen of Python. "Explicit ist besser als implizit."

In Java und C++ kann 'this.' abgeleitet werden, es sei denn, Sie haben Variablennamen, die das Ableiten unmöglich machen. Sie brauchen es manchmal und manchmal nicht.

Python entscheidet, solche Dinge explizit zu machen, anstatt sich auf eine Regel zu stützen. 

Da nichts impliziert oder angenommen wird, werden außerdem Teile der Implementierung offengelegt. self.__class__, self.__dict__ und andere "interne" Strukturen sind auf offensichtliche Weise verfügbar.

88
S.Lott

Es soll den Unterschied zwischen Methoden und Funktionen minimieren. Sie können damit auf einfache Weise Methoden in Metaklassen generieren oder Methoden zur Laufzeit zu bereits vorhandenen Klassen hinzufügen.

z.B.

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

Es erleichtert (soweit ich weiß) auch die Implementierung der Python-Laufzeit.

55
Ryan

Ich schlage vor, dass man Guido van Rossums Blog zu diesem Thema - Warum explizites Ich bleiben muss lesen sollte.

Wenn eine Methodendefinition deklariert ist, wissen wir nicht, ob sie automatisch einen 'self'-Parameter erhalten soll oder nicht: Der Dekorateur kann die Funktion in eine statische Methode (die kein' self 'hat) oder eine Klassenmethode (welche hat eine seltsame Art von Selbst, das sich auf eine Klasse anstatt auf eine Instanz bezieht), oder es könnte etwas völlig anderes tun (es ist trivial, einen Dekorator zu schreiben, der '@classmethod' oder '@staticmethod' in reinem Python implementiert). Es gibt keine Möglichkeit, ohne zu wissen, was der Dekorateur tut, ob die definierte Methode mit einem impliziten 'self'-Argument versehen wird oder nicht.

Ich lehne Hacks wie das Spezialgehäuse '@classmethod' und '@staticmethod' ab.

51
bhadra

Python zwingt Sie nicht dazu, "self" zu verwenden. Sie können ihm einen beliebigen Namen geben. Sie müssen nur daran denken, dass das erste Argument in einem Methodendefinitionsheader eine Referenz auf das Objekt ist.

16

Außerdem können Sie Folgendes tun: (kurz gesagt, der Aufruf von Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) gibt 12 zurück, wird jedoch auf die verrückteste Art und Weise ausgeführt.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Natürlich ist das in Sprachen wie Java und C # schwieriger vorstellbar. Wenn Sie die Selbstreferenz explizit machen, können Sie auf jedes Objekt durch diese Selbstreferenz verweisen. Eine solche Art, mit Klassen zur Laufzeit zu spielen, ist auch in den statischeren Sprachen schwieriger - nicht unbedingt, dass es gut oder schlecht ist. Es ist nur so, dass das explizite Ich all diese Verrücktheit zulässt.

Stellen Sie sich außerdem folgendes vor: Wir möchten das Verhalten von Methoden anpassen (für das Profiling oder für etwas verrückte schwarze Magie). Dies kann uns zum Nachdenken veranlassen: Was wäre, wenn wir eine Klasse Method hätten, deren Verhalten wir überschreiben oder kontrollieren könnten?

Nun, hier ist es:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

Und jetzt: InnocentClass().magic_method() wird sich wie erwartet verhalten. Die Methode wird mit dem innocent_self-Parameter an InnocentClass und mit dem magic_self an die MagicMethod-Instanz gebunden. Komisch, oder? Es ist, als hätte man 2 Schlüsselwörter this1 und this2 in Sprachen wie Java und C #. Magie wie diese erlaubt es Frameworks, Dinge zu tun, die sonst viel ausführlicher wären.

Auch hier möchte ich die Ethik dieses Materials nicht kommentieren. Ich wollte nur Dinge zeigen, die ohne explizite Selbstreferenz schwieriger zu machen wären.

6
vlad-ardelean

Ich denke, der wahre Grund neben "The Zen of Python" ist, dass Funktionen erstklassige Bürger in Python sind. 

Was sie im Wesentlichen zu einem Objekt macht. Nun ist die grundlegende Frage, ob Ihre Funktionen auch Objekt sind. Wie würden Sie im objektorientierten Paradigma Nachrichten an Objekte senden, wenn die Nachrichten selbst Objekte sind? 

Sieht aus wie ein Hühnerei-Problem. Um dieses Paradoxon zu reduzieren, besteht die einzige Möglichkeit darin, einen Ausführungskontext an Methoden zu übergeben oder ihn zu erkennen. Da Python jedoch geschachtelte Funktionen haben kann, ist dies nicht möglich, da sich der Kontext der Ausführung für innere Funktionen ändern würde. 

Das heißt, die einzig mögliche Lösung ist, explizit 'self' (Der Kontext der Ausführung) zu übergeben.

Ich glaube, es ist ein Implementierungsproblem, das das Zen später brachte.

2
pankajdoharey

Ich denke, es hat mit PEP 227 zu tun:

Namen im Klassenbereich sind nicht zugänglich. Namen werden in der .__ aufgelöst. innerster umschließender Funktionsumfang. Wenn eine Klassendefinition in einer .__ vorkommt. In einer Kette verschachtelter Bereiche überspringt der Auflösungsprozess die Klasse Definitionen. Diese Regel verhindert ungerade Interaktionen zwischen der Klasse Attribute und Zugriff auf lokale Variablen. Wenn eine Namensbindungsoperation tritt in einer Klassendefinition auf, erstellt ein Attribut in der resultierenden Klassenobjekt. Zugriff auf diese Variable in einer Methode oder in einer Funktion Innerhalb einer Methode verschachtelt, muss eine Attributreferenz verwendet werden, entweder über selbst oder über den Klassennamen.

2
daole

Wie in self in Python erklärt, Demystified

alles wie obj.meth (args) wird zu Class.meth (obj, args). Der aufrufende Prozess ist automatisch, während der empfangende Prozess nicht explizit ist. Aus diesem Grund muss der erste Parameter einer Funktion in class das Objekt selbst sein. 

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from Origin"""
        return (self.x**2 + self.y**2) ** 0.5

Invokationen:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init () definiert drei Parameter, aber wir haben gerade zwei (6 und 8) übergeben. In ähnlicher Weise erfordert distance () eins, aber es wurden keine Argumente übergeben. 

Warum beklagt sich Python nicht über diese Argument-Nummernübereinstimmung?

Wenn wir eine Methode mit einigen Argumenten aufrufen, wird im Allgemeinen die entsprechende Klassenfunktion aufgerufen, indem das Objekt der Methode vor dem ersten Argument platziert wird. Alles wie obj.meth (args) wird also zu Class.meth (obj, args). Der aufrufende Prozess ist automatisch, während der Empfangsprozess nicht explizit ist.

Aus diesem Grund muss der erste Parameter einer Funktion in class das Objekt selbst sein. Diesen Parameter als "Selbst" zu schreiben, ist lediglich eine Konvention. Es ist kein Schlüsselwort und hat in Python keine besondere Bedeutung. Wir könnten andere Namen verwenden (so), aber ich empfehle Ihnen dringend, dies nicht zu tun. Die Verwendung anderer Namen als "self" wird von den meisten Entwicklern missbilligt und beeinträchtigt die Lesbarkeit des Codes ("Readabilitycounts") . 
...
In ist das erste Beispiel self.x ein Instanzattribut, während x eine lokale Variable ist. Sie sind nicht gleich und liegen in unterschiedlichen Namespaces.

Selbst ist hier zu bleiben

Viele haben vorgeschlagen, in Python ein Schlüsselwort zu erstellen, wie dies in C++ und Java der Fall ist. Dies würde die redundante Verwendung von explizitem Ich aus der Liste der Formalparameter in Methoden ausschließen. Obwohl diese Idee vielversprechend erscheint, wird sie nicht passieren. Zumindest nicht in naher Zukunft. Der Hauptgrund ist die Abwärtskompatibilität. Hier ist ein Blog des Erstellers von Python, der erklärt, warum das explizite Ich bleiben muss.

0
mon