Подтвердить что ты не робот

У Python есть прототипы классов (или форвардные декларации)?

У меня есть серия классов Python в файле. Некоторые классы ссылаются на другие.

Мой код выглядит примерно так:

class A():
    pass

class B():
    c = C()

class C():
    pass

Попытка запустить это, я получаю NameError: name 'C' is not defined. Достаточно справедливо, но есть ли способ заставить его работать, или мне нужно вручную переупорядочить мои классы для размещения? В С++ я могу создать прототип класса. Имеет ли Python эквивалент?

(Я на самом деле играю с моделями Django, но я старался не усложнять вопросы).

4b9b3361

Ответ 1

В Python вы не создаете прототип как таковой, но вам нужно понять разницу между атрибутами класса и атрибутами уровня экземпляра. В приведенном выше примере вы объявляете атрибут класса в классе B, а не атрибут уровня экземпляра.

Это то, что вы ищете:

class B():
    def __init__(self):
        self.c = C()

Ответ 2

Собственно, все вышеперечисленное - замечательные замечания о Python, но ни один из них не решит вашу проблему.

Django нужно разбирать вещи.

Правильный способ сделать то, что вы хотите, это следующее:

class Car(models.Model):
    manufacturer = models.ForeignKey('Manufacturer')
    # ...

class Manufacturer(models.Model):
    # ...

Обратите внимание на использование имени класса в виде строки, а не для литерала. Django предлагает эту альтернативу для решения именно такой проблемы, что Python не предоставляет форвардные декларации.

Этот вопрос напоминает мне о классическом вопросе поддержки, который вы всегда должны задавать любому клиенту с вопросом: "Что вы действительно пытаетесь сделать?"

Ответ 3

Это решит вашу проблему как представленную (но я думаю, что вы действительно ищете атрибут экземпляра, как ответил jholloway7):

class A:
    pass

class B:
    pass

class C:
    pass

B.c = C()

Ответ 4

У Python нет прототипов или открытых классов в стиле Ruby. Но если они вам действительно нужны, вы можете написать метакласс, который перегружает новый, чтобы он просматривал текущее пространство имен, чтобы узнать, существует ли этот класс уже существующий, и если он действительно возвращает существующий объект типа чем создание нового. Я сделал что-то подобное на ORM, который я написал некоторое время назад, и это сработало очень хорошо.

Ответ 5

Все правильные ответы о атрибутах экземпляра класса. Однако причина, по которой вы имеете ошибку, - это просто порядок определения ваших классов. Конечно, класс C еще не определен (поскольку код класса выполняется сразу при импорте):

class A():
    pass

class C():
    pass

class B():
    c = C()

Будет работать.

Ответ 6

Спустя десятилетие после того, как вопрос задан, я столкнулся с той же проблемой. В то время как люди предполагают, что ссылки должны выполняться внутри метода init, бывают случаи, когда вам нужно получить доступ к данным как "атрибуту класса", прежде чем класс будет фактически создан. По этой причине я придумал простое решение с использованием дескриптора.

class A():
    pass

class B():
    class D(object):
        def __init__(self):
            self.c = None
        def __get__(self, instance, owner):
            if not self.c:
                self.c = C()
            return self.c
    c = D()

class C():
    pass

>>> B.c
>>> <__main__.C object at 0x10cc385f8>