Pregunta

Ok, tengo dos módulos, cada uno contiene una clase, el problema es que sus clases se hacen referencia entre sí.

Digamos, por ejemplo, que tenía un módulo de sala y un módulo de persona que contiene CRoom y CPerson.

La clase CRoom contiene información sobre la sala y una lista de CPerson de cada uno en la sala.

Sin embargo, la clase CPerson a veces necesita usar la clase CRoom para la habitación en la que está, por ejemplo para encontrar la puerta, o también para ver quién más está en la habitación.

El problema es que los dos módulos se importan entre sí. Solo recibo un error de importación en el que se importa en segundo lugar :(

En c ++ podría resolver esto al incluir solo los encabezados, y dado que en ambos casos las clases solo tienen punteros a la otra clase, una declaración directa sería suficiente para el encabezado, por ejemplo:

class CPerson;//forward declare
class CRoom
{
    std::set<CPerson*> People;
    ...

¿Hay alguna forma de hacer esto en Python, aparte de colocar ambas clases en el mismo módulo o algo así?

edit: ejemplo de python agregado que muestra un problema al usar las clases anteriores

error:

  

Traceback (última llamada más reciente):
   Archivo " C: \ Projects \ python \ test \ main.py " ;, línea 1, en
     desde la sala de importación CRoom
   Archivo " C: \ Projects \ python \ test \ room.py " ;, línea 1, en
     de importación de persona CPerson
   Archivo " C: \ Projects \ python \ test \ person.py " ;, línea 1, en
     desde la sala de importación CRoom
  ImportError: no se puede importar el nombre de CRoom
  room.py

from person import CPerson

class CRoom:
    def __init__(Self):
        Self.People = {}
        Self.NextId = 0

    def AddPerson(Self, FirstName, SecondName, Gender):
        Id = Self.NextId
        Self.NextId += 1#

        Person = CPerson(FirstName,SecondName,Gender,Id)
        Self.People[Id] = Person
        return Person

    def FindDoorAndLeave(Self, PersonId):
        del Self.People[PeopleId]

person.py

from room import CRoom

class CPerson:
    def __init__(Self, Room, FirstName, SecondName, Gender, Id):
        Self.Room = Room
        Self.FirstName = FirstName
        Self.SecondName = SecondName
        Self.Gender = Gender
        Self.Id = Id

    def Leave(Self):
        Self.Room.FindDoorAndLeave(Self.Id)
¿Fue útil?

Solución

No es necesario importar CRoom

No usas CRoom en person.py , así que no lo importes. Debido al enlace dinámico, Python no necesita " ver todas las definiciones de clase en tiempo de compilación " ;.

Si realmente lo hace usa CRoom en person.py , cambie de la sala de importación CRoom a < code> import room y use el formulario calificado por el módulo room.CRoom . Consulte Importaciones circulares de Effbot para más detalles.

Sidenote: es probable que tenga un error en la línea Self.NextId + = 1 . Incrementa NextId de instancia, no NextId de clase. Para incrementar el contador de la clase, use CRoom.NextId + = 1 o Self .__ class __. NextId + = 1 .

Otros consejos

¿Realmente necesita hacer referencia a las clases en el momento de la definición de clase? es decir.

 class CRoom(object):
     person = CPerson("a person")

O (más probable), ¿solo necesita usar CPerson en los métodos de su clase (y viceversa). por ejemplo:

class CRoom(object):
    def getPerson(self): return CPerson("someone")

Si es el segundo, no hay problema, ya que cuando el método se llama en lugar de definirlo, se importará el módulo. Su único problema es cómo referirse a él. Es probable que estés haciendo algo como:

from CRoom import CPerson # or even import *

Con módulos de referencia circular, no puede hacer esto, ya que en el punto en que un módulo importa otro, el cuerpo de los módulos originales no habrá terminado de ejecutarse, por lo que el espacio de nombres estará incompleto. En su lugar, use referencias calificadas. es decir:

#croom.py
import cperson
class CRoom(object):
    def getPerson(self): return cperson.CPerson("someone")

Aquí, Python no necesita buscar el atributo en el espacio de nombres hasta que se llame al método, momento en el que ambos módulos deberían haber completado su inicialización.

Primero, nombrar sus argumentos con letras mayúsculas es confuso. Dado que Python no tiene una verificación de tipo estática formal, usamos UpperCase para referirnos a una clase y lowerCase para referirnos a un argumento.

Segundo, no nos molestamos con CRoom y CPerson. La mayúscula es suficiente para indicar que es una clase. La letra C no se usa. Room . Persona .

En tercer lugar, no solemos poner las cosas en formato Una clase por archivo . Un archivo es un módulo de Python, y con mayor frecuencia importamos un módulo completo con todas las clases y funciones.

[Soy consciente de que son hábitos, no es necesario que los rompas hoy, pero hacen que sea difícil de leer.]

Python no usa tipos estáticamente definidos como C ++. Cuando define una función de método, no define formalmente el tipo de datos de los argumentos de esa función. Simplemente enumera algunos nombres de variables. Con suerte, la clase de cliente proporcionará argumentos del tipo correcto.

En el tiempo de ejecución, cuando realiza una solicitud de método, Python debe asegurarse de que el objeto tenga el método. NOTA. Python no verifica si el objeto es del tipo correcto, eso no importa. Solo verifica si tiene el método correcto.

El bucle entre room.Room y person.Person es un problema. No necesita incluir uno al definir el otro.

Es más seguro importar todo el módulo.

Aquí está room.py

import person
class Room( object ):
    def __init__( self ):
        self.nextId= 0
        self.people= {}
    def addPerson(self, firstName, secondName, gender):
        id= self.NextId
        self.nextId += 1

        thePerson = person.Person(firstName,secondName,gender,id)
        self.people[id] = thePerson
        return thePerson 

Funciona bien siempre y cuando Persona se defina en el espacio de nombres donde se está ejecutando. La persona no tiene que ser conocida cuando define la clase.

La persona no tiene que ser conocida hasta el tiempo de ejecución cuando se evalúa la expresión de la Persona (...).

Aquí está person.py

import room
class Person( object ):
    def something( self, x, y ):
        aRoom= room.Room( )
        aRoom.addPerson( self.firstName, self.lastName, self.gender )

Su main.py tiene este aspecto

import room
import person
r = room.Room( ... )
r.addPerson( "some", "name", "M" )
print r

Podrías simplemente alias el segundo.

import CRoom

CPerson = CRoom.CPerson

@ S.Lott si no importo nada en el módulo de sala, aparece un error indefinido (lo importé en el módulo principal como lo mostró)

  

Traceback (última llamada más reciente):
   Archivo " C: \ Proyectos \ python \ test \ main.py " ;, línea 6, en
     Ben = Room.AddPerson ('Ben', 'Blacker', 'Male')
   Archivo " C: \ Projects \ python \ test \ room.py " ;, línea 12, en AddPerson
     Persona = CPerson (Nombre, Segundo Nombre, Género, Id)
  NameError: el nombre global 'CPerson' no está definido

Además, la razón por la que hay diferentes módulos es que encontré que el problema para comenzar con la clase de contenedor (es decir, la sala) ya tiene varios cientos de líneas, por lo que quería los elementos (por ejemplo, las personas) en un archivo separado.

EDITAR: main.py

from room import CRoom
from person import CPerson

Room = CRoom()

Ben = Room.AddPerson('Ben', 'Blacker', 'Male')
Tom = Room.AddPerson('Tom', 'Smith',   'Male')

Ben.Leave()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top