Die Eigenschaftsbeschreibung in Python ist seltsam, wenn Sie genau hinschauen (es ist nicht seltsam, wenn Sie genauer überlegen).

Einführung

Ich hatte die Möglichkeit, eine Beschreibung über Python zu schreiben, und als ich versuchte, eine Beschreibung über Eigenschaften zu schreiben,

class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

"Was?" Wie soll ich das erklären? Ich dachte.

Seltsamer Punkt

Also, was ist falsch? Hatte Python übrigens eine Überlastung?

Ja, die folgenden Teile scheinen in der Lage zu sein, die Methode "gleicher Name, aber unterschiedliche Anzahl von Argumenten" für Name (Selbst) und Name (Selbst, Name) zu definieren.

@property
def name(self):
    return self._name

@name.setter
def name(self, name):
    self._name = name

Mit Python geht das nicht. Wenn Sie eine Methode mit demselben Namen definieren, wird diese durch die später definierte überschrieben (genauer gesagt, das Attribut des Methodennamens zeigt auf das später definierte Funktionsobjekt).

Natürlich werden beide der beiden oben genannten Methoden verwendet. Sie können sehen, dass jede Methode ausgeführt wird, wenn Sie den Druck vorbereiten.

Ich habe mich übrigens gefragt, wie ich @ name.setter schreiben soll. Weil sich der Namensteil je nach Eigenschaft ändert.

Karakuri

Dekorateur

Lösen wir das Rätsel. Lassen Sie uns zunächst die Dekorateure überprüfen.

@property
def name(self):
    return self._name

Die Beschreibung ist fast dieselbe wie die folgende.

def name(self):
    return self._name
name = property(name)

Mit anderen Worten, der Name auf der rechten Seite der dritten Zeile ist ein Funktionsobjekt, aber der Name nach Abschluss der Zuweisung auf der linken Seite ist ein Eigenschaftsobjekt.

Ich bin gespannt, wie ich es schreiben soll, aber lassen Sie uns die folgende Beschreibung mit der gleichen Idee konvertieren.

@name.setter
def name(self, name):
    self._name = name

Ich fühle mich so.

def name_setter(self, name):
    self._name = name
name = name.setter(name_setter)

Dout (lacht). Der Methodenname wird auf name_setter gesetzt, dies ist jedoch so, dass die dritte Zeile ordnungsgemäß ausgeführt werden kann. Wenn Sie sich den [Deklarationsteil des Dekorateurs im offiziellen Dokument] ansehen (https://docs.python.jp/3/reference/compound_stmts.html#function-definitions),

Außer dass der vorherige Code die ursprüngliche Funktion nicht vorübergehend an den Namen func bindet.

Es ist geworden. Mit anderen Worten, wenn Sie einen Dekorateur verwenden, wird die Methode mit dem Namen name nicht definiert (der durch @property definierte Name name wird nicht überschrieben).

Zusammenfassung,

  1. Rufen Sie die Setter-Namensmethode (Eigenschaftsobjekt) auf.
  2. Setzen Sie den Rückgabewert erneut auf name

Es bedeutet das.

property.setter

Wenn Sie nun die Setter-Methode der Eigenschaftsklasse kennen, ist die Lösung. Um die Antwort herauszufinden, müssen wir in die Python-Implementierung einsteigen. Die Implementierung der Eigenschaftsklasse finden Sie in Objects / descrobject.c. Wenn Sie die Details der Implementierung weglassen und nur die Hauptpunkte einfügen,

static PyObject *
property_setter(PyObject *self, PyObject *setter)
{
    return property_copy(self, NULL, setter, NULL);
}

Dies ist die C-Implementierung, die der Setter-Methode der Eigenschaftsklasse entspricht. Also, property_copy.

static PyObject *
property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del)
{
    propertyobject *pold = (propertyobject *)old;
    PyObject *new, *type, *doc;

    type = PyObject_Type(old);
    if (type == NULL)
        return NULL;

    if (get == NULL || get == Py_None) {
        Py_XDECREF(get);
        get = pold->prop_get ? pold->prop_get : Py_None;
    }
    if (set == NULL || set == Py_None) {
        Py_XDECREF(set);
        set = pold->prop_set ? pold->prop_set : Py_None;
    }
    if (del == NULL || del == Py_None) {
        Py_XDECREF(del);
        del = pold->prop_del ? pold->prop_del : Py_None;
    }
    if (pold->getter_doc && get != Py_None) {
        /* make _init use __doc__ from getter */
        doc = Py_None;
    }
    else {
        doc = pold->prop_doc ? pold->prop_doc : Py_None;
    }

    new =  PyObject_CallFunctionObjArgs(type, get, set, del, doc, NULL);
    Py_DECREF(type);
    if (new == NULL)
        return NULL;
    return new;
}

Es ist ein bisschen lang, aber um zusammenzufassen, was ich tue

  1. Wenn get, set, del im Argument nicht angegeben sind, wird die ursprüngliche Definition abgerufen.
  2. Erstellen Sie ein Eigenschaftsobjekt und geben Sie es erneut mit dem extrahierten und dem jetzt durch das Argument angegebenen Objekt zurück.

Ich mache das Dies bedeutet, dass für die zurückgegebene Eigenschaftsmethode Getter und Setter definiert sind.

Darüber hinaus zu der Frage "Ich verstehe, dass das Eigenschaftsobjekt festgelegt ist, aber wie funktioniert dies, damit es referenziert und zugewiesen werden kann?" [Sehr guter Artikel](http: / /qiita.com/knzm/items/a8a0fead6e1706663c22) Bitte beziehen Sie sich darauf.

Zusammenfassung

Um die Geschichte zusammenzufassen.

--Frage ――Die Beschreibung der Eigenschaft sieht aus wie eine Überladung, aber Python können Sie das tun? --Was bedeutet @proper name.setter für einen Setter?

Beiseite

Die Erklärung der Eigenschaft, die ich ursprünglich zu schreiben versuchte, ist übrigens

Sie kennen Python immer noch nicht zu gut, um dies zu erklären

Ich habe den Tee so schlammig gemacht (lacht)

Recommended Posts

Die Eigenschaftsbeschreibung in Python ist seltsam, wenn Sie genau hinschauen (es ist nicht seltsam, wenn Sie genauer überlegen).
Wenn Sie der Meinung sind, dass die PyCharm-Umgebung beschädigt ist, liegt dies am Dateinamen
Python> Überprüfen Sie NoneType oder nicht> wenn a == None:> wenn a None ist:
Wenn Sie das Update von ManjaroLinux für seltsam halten