Pergunta

Eu tenho uma série de classes Python em um arquivo. Algumas classes fazem referência a outros.

Meu código é algo assim:

class A():
    pass

class B():
    c = C()

class C():
    pass

Tentando executar isso, eu entendo NameError: name 'C' is not defined. É justo o suficiente, mas há alguma maneira de fazê-lo funcionar, ou tenho que reordenar manualmente minhas aulas para acomodar? No C ++, posso criar um protótipo de classe. Python tem um equivalente?

(Na verdade, estou brincando com os modelos Django, mas tentei não complicar assuntos).

Foi útil?

Solução

No Python, você não cria um protótipo em si, mas precisa entender a diferença entre os "atributos de classe" e os atributos no nível da instância. No exemplo que você mostrou acima, você está declarando um atributo de classe no Classe B, não um atributo no nível da instância.

Isso é o que você está procurando:

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

Outras dicas

Na verdade, todas as opções acima são ótimas observações sobre o Python, mas nenhuma delas resolverá seu problema.

Django precisa introspectar coisas.

o certo Maneira de fazer o que você deseja é o seguinte:

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

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

Observe o uso do nome da classe como um corda em vez da referência de classe literal. O Django oferece essa alternativa para lidar exatamente com o problema de que o Python não fornece declarações avançadas.

Esta pergunta me lembra a pergunta clássica de suporte de que você sempre deve perguntar a qualquer cliente com um problema: "O que você é verdade tentando fazer?"

Isso resolveria seu problema conforme apresentado (mas acho que você está realmente procurando um atributo de instância como Jholloway7 respondeu):

class A:
    pass

class B:
    pass

class C:
    pass

B.c = C()

O Python não possui protótipos ou classes abertas no estilo Ruby. Mas se você realmente precisa deles, pode escrever um metaclasse que sobrecarrega novo para que ele faça uma pesquisa no espaço de nome atual para ver se a classe já existe e se ele retornar o objeto do tipo existente, em vez de criar um novo. Fiz algo assim em um orm, escrevo um tempo atrás e funcionou muito bem.

Todas as respostas corretas sobre atributos de classe vs instância. No entanto, o motivo pelo qual você tem um erro é apenas a ordem de definir suas classes. Obviamente, a classe C ainda não foi definida (pois o código no nível da classe é executado imediatamente na importação):

class A():
    pass

class C():
    pass

class B():
    c = C()

Vai funcionar.

Uma década após a pergunta, encontrei o mesmo problema. Enquanto as pessoas sugerem que a referência deve ser feita dentro do iniciar Método, há momentos em que você precisa acessar os dados como um "atributo de classe" antes que a classe seja realmente instanciada. Por esse motivo, criei uma solução simples usando um descritor.

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>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top