У Python есть прототипы классов (или форвардные декларации)?
У меня есть серия классов Python в файле. Некоторые классы ссылаются на другие.
Мой код выглядит примерно так:
class A():
pass
class B():
c = C()
class C():
pass
Попытка запустить это, я получаю NameError: name 'C' is not defined
. Достаточно справедливо, но есть ли способ заставить его работать, или мне нужно вручную переупорядочить мои классы для размещения? В С++ я могу создать прототип класса. Имеет ли Python эквивалент?
(Я на самом деле играю с моделями Django, но я старался не усложнять вопросы).
Ответы
Ответ 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>