2010-06-19 2 views
11

Я читал документацию, описывающую наследование классов, абстрактные базовые классы и даже интерфейсы 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) 

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

+0

'__getattr__' работает только для новых классов. Это означает, что ваши классы должны быть подклассами 'object'. –

+0

То, что вы пытаетесь сделать, также называется классом, имеющим виртуальный конструктор (а не «виртуальные классы»).См. Соответствующий вопрос [_Что такое фабрика классов? _] (Http://stackoverflow.com/questions/2526879/what-exactly-is-a-class-factory) – martineau

ответ

14

я предпочел бы делать это с завода:

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 
+0

Ваша вторая фабричная функция строит объект каждого типа каждый время, когда оно называется, хотя вы только возвращаете один из них. Лучше хранить классы в словаре, чем объекты: 'class_dict = {« Плоский »: Line, ...}' then 'return class_dict [description] (description)'. –

0

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

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

class A(object): 
    pass 
1

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

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

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

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

+1

* Кстати: есть ли другие? *: C++ приходит на ум. – user1717828

+0

Интересно! Я этого не знал. У вас есть ссылка, где я могу читать виртуальные классы на C++? Согласно Википедии, в C++ вложенные классы являются статическими членами охватывающего класса. Другими словами: они не являются фактически * истинными * вложенными классами (которые являются членами охватывающего * экземпляра * охватывающего класса). И учитывая, что виртуальные классы - это особый случай истинных вложенных классов (а именно, истинные вложенные классы, которые переопределяются в подклассе, как и любой другой виртуальный член), это, по-видимому, препятствует тому, чтобы C++ имел виртуальные классы. –

+0

Mmm, AFAIK C++ тип * определяет *, какие виртуальные классы есть, потому что язык настолько популярен и делает такое интенсивное использование. A [виртуальный/абстрактный класс] (https://en.m.wikipedia.org/wiki/Virtual_method_table#Example) не может быть создан, только унаследован, поэтому в некотором роде он больше похож на шаблон для других классов. – user1717828

18

Я согласен с TooAngel, но я бы использовал __new__ method.

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. 
+1

nice - я тоже думал о чем-то подобном, но не знал синтаксиса python для него – TooAngel

+0

В этом примере Shape известен как _metaclass_. –

+2

@ Даниэль: Я так не думаю. Метаклассы обычно меняют способ работы класса. В Objective-C это будет называться кластер Класса *. Я не уверен, какое имя для него принадлежит Python. –

 Смежные вопросы

  • Нет связанных вопросов^_^