Python: наследование от встроенных типов - PullRequest
2 голосов
/ 26 мая 2009

У меня вопрос по поводу подтипов встроенных типов и их конструкторов. Я хочу, чтобы класс наследовал как от кортежа, так и от пользовательского класса.

Позвольте привести конкретный пример. Я много работаю с графиками, имея в виду узлы, связанные с ребрами. Я начинаю делать некоторые работы над своим собственным графовым фреймворком.

Существует класс Edge, который имеет свои атрибуты и методы. Он также должен наследоваться от класса GraphElement. (GraphElement - это каждый объект, который не имеет значения вне контекста конкретного графа.) Но на самом базовом уровне ребро - это просто кортеж, содержащий два узла. Было бы неплохо синтаксического сахара, если бы вы могли сделать следующее:

edge = graph.create_edge("Spam","Eggs")
(u, v) = edge

Таким образом (u, v) будет содержать «Спам» и «Яйца». Это также поддержало бы итерацию как

for node in edge: ...

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

Итак, вот мой класс Edge и его init :

class Edge(GraphElement, tuple):

def __init__(self, graph, (source, target)):
    GraphElement.__init__(self, graph)
    tuple.__init__((source, target))

Когда я звоню

Edge(aGraph, (source, target))

Я получаю TypeError: tuple () принимает максимум 1 аргумент (2 дано). Что я делаю не так?

Ответы [ 3 ]

9 голосов
/ 26 мая 2009

Поскольку кортежи неизменны, вам также необходимо переопределить метод __new__. Смотри http://www.python.org/download/releases/2.2.3/descrintro/#__new__

class GraphElement:
    def __init__(self, graph):
        pass

class Edge(GraphElement, tuple):
    def __new__(cls, graph, (source, target)):
        return tuple.__new__(cls, (source, target))
    def __init__(self, graph, (source, target)):
        GraphElement.__init__(self, graph)
6 голосов
/ 26 мая 2009

Для того, что вам нужно, я бы избежал множественного наследования и реализовал бы итератор с использованием генератора:

class GraphElement:
    def __init__(self, graph):
        pass

class Edge(GraphElement):
    def __init__(self, graph, (source, target)):
        GraphElement.__init__(self, graph)
        self.source = source
        self.target = target

    def __iter__(self):
        yield self.source
        yield self.target

В этом случае оба использования работают нормально:

e = Edge(None, ("Spam","Eggs"))
(s, t) = e
print s, t
for p in e:
    print p
3 голосов
/ 26 мая 2009

Вам необходимо переопределить __new__ - в настоящее время вызывается tuple.__new__ (поскольку вы не переопределяете его) со всеми аргументами, которые вы передаете Edge.

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