22 Stimmen

Selbstreferenzierende Klassendefinition in Python

Gibt es eine Möglichkeit, innerhalb der Klassendeklaration auf einen Klassennamen zu verweisen? Es folgt ein Beispiel:

class Plan(SiloBase):
    cost = DataField(int)
    start = DataField(System.DateTime)
    name = DataField(str)
    items = DataCollection(int)
    subPlan = ReferenceField(Plan)

Ich habe eine Metaklasse, die diese Informationen liest und tut einige Setup, und die Basisklasse implementiert einige gemeinsame speichern Zeug. Ich würde gerne in der Lage sein, rekursive Definitionen wie diese zu erstellen, aber bisher in meinem Experimentieren ich nicht in der Lage gewesen, den Effekt zu erhalten, die ich wünsche, in der Regel läuft in eine "Plan ist nicht definiert" Fehler. Ich verstehe, was passiert ist, der Name der Klasse ist nicht im Bereich innerhalb der Klasse.

25voto

Evan Fosmark Punkte 93825

Versuchen Sie dies:

class Plan(SiloBase):
    cost = DataField(int)
    start = DataField(System.DateTime)
    name = DataField(str)
    items = DataCollection(int)

Plan.subPlan = ReferenceField(Plan)

ODER verwenden Sie __new__ wie diese:

class Plan(SiloBase):

    def __new__(cls, *args, **kwargs):
        cls.cost = DataField(int)
        cls.start = DataField(System.DateTime)
        cls.name = DataField(str)
        cls.items = DataCollection(int)
        cls.subPlan = ReferenceField(cls)
        return object.__new__(cls, *args, **kwargs)

1 Stimmen

Awesome, dieses tut genau, was ich es zu wünschen, und sein nicht ein humongous Hack. noch versuchend, meinen Kopf um diese vollständige dynamische Sache, haha zu wickeln

9voto

Miles Punkte 29684

Ich habe eine Metaklasse, die diese Informationen liest und einige Einstellungen vornimmt

Die meisten Frameworks, die Metaklassen verwenden, bieten eine Möglichkeit, dieses Problem zu lösen. Zum Beispiel, Django :

subplan = ForeignKey('self')

Google App Engine :

subplan = SelfReferenceProperty()

Das Problem bei Lösungen wie dem Anbringen einer zusätzlichen Eigenschaft zu einem späteren Zeitpunkt oder der Verwendung von __new__ ist, dass die meisten ORM-Metaklassen erwarten, dass die Klasseneigenschaften bereits zum Zeitpunkt der Erstellung der Klasse vorhanden sind.

1 Stimmen

Toll, dass Sie auch Google App Engine erwähnt haben! +1

1 Stimmen

In Google App Engine - DB ist dies möglich, aber in NDB nicht. Um zu sehen, wie man das in NDB macht, schauen Sie hier: stackoverflow.com/questions/3531936/

2voto

Piotr Findeisen Punkte 16757

Ich verstehe, was passiert ist, der Name der Klasse ist nicht im Geltungsbereich innerhalb der Klasse.

Nicht ganz. Der Name der Klasse ist noch nicht definiert bei der Definition seines Inhalts (z. B. des Geltungsbereichs).

1voto

RaamEE Punkte 2363

Sinus Python 3.7 und PEP 563 es gibt eine Möglichkeit, das zu tun.

Hinzufügen der Einfuhr

from __future__ import annotations

und der folgende Code wird funktionieren

from __future__ import annotations
from typing import List

class Refer(object):
    def __init__(self, x: Plan):
        self.x: Plan = x

class Plan(object):
    def __init__(self):
        pass
    subPlan: Refer(Plan())

0voto

Daniel Roseman Punkte 565786

Nein, das können Sie nicht tun. Überlegen Sie, was passieren würde, wenn Sie das tun würden:

 OtherPlan = Plan
 other_plan = OtherPlan()

Bei der Instanziierung von other_plan Wie lautet der Name der Klasse?

Wie auch immer, diese Art von Dingen macht man am besten im __new__ Methode, die eine cls Parameter, der sich auf die Klasse bezieht.

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