18 Stimmen

Warum schlägt setattr bei einer gebundenen Methode fehl

Im Folgenden gelingt es setattr im ersten Aufruf, aber im zweiten scheitert es mit:

AttributeError: 'method' object has no attribute 'i'

Warum ist das so und gibt es eine Möglichkeit, ein Attribut an einer Methode so zu setzen, dass es nur für eine Instanz existiert und nicht für jede Instanz der Klasse?

Klasse c:

    def m(self):

        print(type(c.m))
        setattr(c.m, 'i', 0)

        print(type(self.m))
        setattr(self.m, 'i', 0)

Python 3.2.2

0 Stimmen

Warum brauchst du das? Warum nicht Instanzattribute verwenden? Wie self.m_i = 0 oder self.m_data = { 'i': 0 }, wenn du viele Attribute pro Methode möchtest.

0 Stimmen

@eye Danke für Ihr Interesse. Ich versuche, statische Funktionsvariablen gemäß stackoverflow.com/questions/279561/… zu implementieren, aber das funktioniert auch ordnungsgemäß mit Methoden. Ich habe den Großteil der Implementierung, aber dies ist ein Knackpunkt. Es könnte jedoch einen besseren Weg geben, das ursprüngliche Problem zu lösen.

34voto

Ferdinand Beyer Punkte 61121

Die kurze Antwort: Es gibt keine Möglichkeit, benutzerdefinierte Attribute zu gebundenen Methoden hinzuzufügen.

Die lange Antwort folgt.

In Python gibt es Funktionsobjekte und Methodenobjekte. Wenn Sie eine Klasse definieren, erstellt die def-Anweisung ein Funktionsobjekt, das im Namensraum der Klasse existiert:

>>> class c:
...     def m(self):
...         pass
...
>>> c.m

Funktionsobjekte verfügen über ein spezielles __dict__-Attribut, das benutzerdefinierte Attribute speichern kann:

>>> c.m.i = 0
>>> c.m.__dict__
{'i': 0}

Methodenobjekte sind unterschiedliche Tiere. Sie sind winzige Objekte, die lediglich eine Referenz auf das entsprechende Funktionsobjekt (__func__) und eine auf ihr Hostobjekt (__self__) halten:

>>> c().m
>
>>> c().m.__self__
<__main__.c object at 0x02625070>
>>> c().m.__func__

>>> c().m.__func__ is c.m
True

Methodenobjekte verfügen über ein spezielles __getattr__, das den Attributzugriff an das Funktionsobjekt weiterleitet:

>>> c().m.i
0

Dies gilt auch für die __dict__-Eigenschaft:

>>> c().m.__dict__['a'] = 42
>>> c.m.a
42
>>> c().m.__dict__ is c.m.__dict__
True

Das Setzen von Attributen folgt jedoch den Standardregeln, und da sie keinen eigenen __dict__ haben, gibt es keinen Weg, willkürliche Attribute festzulegen.

Dies ähnelt userdefinierten Klassen, die __slots__ definieren und keinen __dict__-Slot haben, wenn beim Versuch, einen nicht vorhandenen Slot zu setzen, ein AttributeError ausgelöst wird (siehe die Dokumentation zu __slots__ für weitere Informationen):

>>> class c:
...     __slots__ = ('a', 'b')
...
>>> x = c()
>>> x.a = 1
>>> x.b = 2
>>> x.c = 3
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'c' object has no attribute 'c'

1voto

Lennart Regebro Punkte 157632

Q: "Gibt es eine Möglichkeit, ein Attribut auf einer Methode festzulegen, sodass es nur für eine Instanz existiert, nicht für jede Instanz der Klasse?"

A: Ja:

class c:

    def m(self):

        print(type(c.m))
        setattr(c.m, 'i', 0)

        print(type(self))
        setattr(self, 'i', 0)

Die statische Variable bei Funktionen im Beitrag, auf den Sie verlinken, ist nicht nützlich für Methoden. Es setzt ein Attribut auf die Funktion, damit dieses Attribut beim nächsten Aufruf der Funktion verfügbar ist, damit Sie einen Zähler oder ähnliches erstellen können.

Aber Methoden haben eine mit ihnen verbundene Objektinstanz (self). Daher haben Sie keine Notwendigkeit, Attribute auf der Methode festzulegen, da Sie es einfach auf der Instanz festlegen können. Genau darum geht es bei der Instanz.

Der Beitrag, auf den Sie verlinken, zeigt, wie man eine Funktion mit einer statischen Variable erstellt. Ich würde sagen, dass dies in Python fehlgeleitet wäre. Schauen Sie stattdessen auf diese Antwort: Was ist das Python-Äquivalent für statische Variablen innerhalb einer Funktion?

Das ist der Weg, wie man es in Python macht, der klar und leicht verständlich ist. Sie verwenden eine Klasse und machen sie aufrufbar. Das Festlegen von Attributen auf Funktionen ist möglich und es gibt wahrscheinlich Fälle, in denen es eine gute Idee ist, aber im Allgemeinen wird es die Leute nur verwirren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X