Frage Virtuelle Klassen: macht es richtig?


Ich habe Dokumentation gelesen, die Klassenvererbung, abstrakte Basisklassen und sogar Python-Schnittstellen beschreibt. Aber nichts scheint genau das zu sein, was ich will. Nämlich eine einfache Möglichkeit, virtuelle Klassen zu erstellen. Wenn die virtuelle Klasse aufgerufen wird, möchte ich, dass sie eine spezifischere Klasse instanziiert, basierend auf den Parametern, die sie erhält, und die die aufrufende Funktion zurückgibt. Für jetzt habe ich eine zusammenfassende Möglichkeit, Anrufe an die virtuelle Klasse bis zur zugrunde liegenden Klasse umzuleiten.

Die Idee ist folgende:

class Shape:
    def __init__(self, description):
        if   description == "It's flat":  self.underlying_class = Line(description)
        elif description == "It's spiky": self.underlying_class = Triangle(description)
        elif description == "It's big":   self.underlying_class = Rectangle(description)
    def number_of_edges(self, parameters):
        return self.underlying_class(parameters)

class Line:
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 1

class Triangle:
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 3

class Rectangle:
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 4

shape_dont_know_what_it_is = Shape("It's big")
shape_dont_know_what_it_is.number_of_edges(parameters)

Meine Umleitung ist alles andere als optimal, da nur Aufrufe an die Funktion number_of_edges () weitergeleitet werden. Wenn man Shape so etwas hinzufügt, ist das auch nicht der Fall:

def __getattr__(self, *args):
    return underlying_class.__getattr__(*args)

Was mache ich falsch? Ist die ganze Idee schlecht umgesetzt? Jede Hilfe sehr geschätzt.


11
2018-06-19 17:32


Ursprung


Antworten:


Ich würde es lieber mit einer Fabrik machen:

def factory(description):
    if   description == "It's flat":  return Line(description)
    elif description == "It's spiky": return Triangle(description)
    elif description == "It's big":   return Rectangle(description)

oder:

def factory(description):
    classDict = {"It's flat":Line("It's flat"), "It's spiky":Triangle("It's spiky"), "It's big":Rectangle("It's big")}
    return classDict[description]

und erben die Klassen von Shape

class Line(Shape):
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 1

14
2018-06-19 17:39



Ich bin einverstanden mit TooAngel, aber ich würde das benutzen __new__ Methode.

class Shape(object):
    def __new__(cls, *args, **kwargs):
        if cls is Shape:                            # <-- required because Line's
            description, args = args[0], args[1:]   #     __new__ method is the
            if description == "It's flat":          #     same as Shape's
                new_cls = Line
            else:
                raise ValueError("Invalid description: {}.".format(description))
        else:
            new_cls = cls
        return super(Shape, cls).__new__(new_cls, *args, **kwargs)

    def number_of_edges(self):
        return "A shape can have many edges…"

class Line(Shape):
    def number_of_edges(self):
        return 1

class SomeShape(Shape):
    pass

>>> l1 = Shape("It's flat")
>>> l1.number_of_edges()
1
>>> l2 = Line()
>>> l2.number_of_edges()
1
>>> u = SomeShape()
>>> u.number_of_edges()
'A shape can have many edges…'
>>> s = Shape("Hexagon")
ValueError: Invalid description: Hexagon.

18
2018-06-19 18:03



Python verfügt nicht über virtuelle Klassen. Sie müssen sie selbst implementieren (es sollte möglich sein, Pythons Reflektionsfähigkeiten sollten stark genug sein, um dies zu ermöglichen).

Wenn Sie jedoch virtuelle Klassen benötigen, warum verwenden Sie nicht einfach eine Programmiersprache, die virtuelle Klassen wie Beta, gBeta oder Newspeak hat? (Übrigens: Gibt es noch andere?)

In diesem speziellen Fall sehe ich jedoch nicht wirklich, wie virtuelle Klassen Ihre Lösung vereinfachen würden, zumindest nicht in dem Beispiel, das Sie angegeben haben. Vielleicht könnten Sie näher erläutern, warum Sie glauben, dass Sie virtuelle Kurse benötigen?

Versteh mich nicht falsch: Ich mag virtuelle Klassen, aber die Tatsache, dass nur drei Sprachen sie jemals implementiert haben, nur einer von diesen dreien ist noch am Leben und genau 0 dieser drei sind tatsächlich von irgendjemandem benutzt, sagt etwas ...


1
2018-06-19 17:55



Sie können die Klasse mit ändern object.__class__, aber es ist viel besser, nur eine Funktion zu erstellen, die eine Instanz einer beliebigen Klasse zurückgibt.

Zu einem anderen Hinweis sollte jede Klasse von erben object es sei denn, Sie verwenden Python 3, sonst haben Sie eine Klasse im alten Stil:

class A(object):
    pass

0
2018-06-19 17:46