Виртуальные классы: делать это правильно? - PullRequest
11 голосов
/ 19 июня 2010

Я читал документацию, описывающую наследование классов, абстрактные базовые классы и даже интерфейсы Python.Но ничто не похоже на то, что я хочу.А именно, простой способ построения виртуальных классов.Когда виртуальный класс вызывается, я хотел бы, чтобы он создал экземпляр более специфического класса, основанного на параметрах, которые ему переданы, и передал его обратно вызывающей функции.На данный момент у меня есть сводный способ перенаправления вызовов к виртуальному классу вниз к базовому классу.

Идея заключается в следующем:

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)

Мое изменение маршрута далеко не оптимально, так каквызовы функции number_of_edges () передаются.Добавление чего-то подобного в Shape также не помогает,

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

Что я делаю не так?Вся идея плохо реализована?Любая помощь с благодарностью.

Ответы [ 4 ]

18 голосов
/ 19 июня 2010

Я согласен с TooAngel , но я бы использовал метод __ new__ .

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.
14 голосов
/ 19 июня 2010

Я бы предпочел сделать это с фабрикой:

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)

или:

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]

и наследовать классы от Shape

class Line(Shape):
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 1
1 голос
/ 19 июня 2010

В Python нет виртуальных классов из коробки.Вам придется реализовать их самостоятельно (это должно быть возможно, возможности отражения Python должны быть достаточно мощными, чтобы позволить вам это сделать).

Однако, если вам нужны виртуальные классы, то почему бы вам просто не использоватьязык программирования, в котором есть виртуальные классы, такие как Beta, gBeta или Newspeak?(Кстати: есть ли другие?)

В данном конкретном случае, однако, я не вижу, как виртуальные классы упростят ваше решение, по крайней мере, в приведенном вами примере.Может быть, вы могли бы объяснить, почему вы думаете, что вам нужны виртуальные классы?

Не поймите меня неправильно: мне нравятся виртуальные классы, но тот факт, что только три языка когда-либо их реализовывали, только один из этих трех еще живи ровно 0 из этих трех фактически используются кем-то, что несколько говорит…

0 голосов

Вы можете изменить класс с помощью object.__class__, но гораздо лучше просто создать функцию, которая возвращает экземпляр произвольного класса.

С другой стороны, все классы должны наследоваться от object, если тольковы используете Python 3, как это, иначе вы получите класс старого стиля:

class A(object):
    pass
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...