Ok I have two modules, each containing a class, the problem is their classes reference each other.
Lets say for example I had a room module and a person module containing CRoom and CPerson.
The CRoom class contains infomation about the room, and a CPerson list of every one in the room.
The CPerson class however sometimes needs to use the CRoom class for the room its in, for example to find the door, or too see who else is in the room.
The problem is with the two modules importing each other I just get an import error on which ever is being imported second :(
In c++ I could solve this by only including the headers, and since in both cases the classes just have pointers to the other class, a forward declaration would suffice for the header eg:
class CPerson;//forward declare
class CRoom
{
std::set<CPerson*> People;
...
Is there anyway to do this in python, other than placing both classes in the same module or something like that?
edit: added python example showing problem using above classes
error:
Traceback (most recent call last):
File "C:\Projects\python\test\main.py", line 1, in
from room import CRoom
File "C:\Projects\python\test\room.py", line 1, in
from person import CPerson
File "C:\Projects\python\test\person.py", line 1, in
from room import CRoom
ImportError: cannot import name 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)
Pip Check Command – Check Python Dependencies After Installation. Because pip doesn't currently address dependency issues on installation, the pip check command option can be used to verify that dependencies have been installed properly in your project. For example: $ pip check No broken requirements found.
There are two ways to specify dependencies for Cloud Functions written in Python: using the pip package manager's requirements. txt file or packaging local dependencies alongside your function. Dependency specification using the Pipfile/Pipfile.
While many Python developers use Pip as a Dependency Manager, it was never intended to be used as one. Pip will not flag dependency conflicts. As a result, it will happily install multiple versions of a dependency into your project, which will likely result in errors.
No need to import CRoom
You don't use CRoom
in person.py
, so don't import it. Due to dynamic binding, Python doesn't need to "see all class definitions at compile time".
If you actually do use CRoom
in person.py
, then change from room import CRoom
to import room
and use module-qualified form room.CRoom
. See Effbot's Circular Imports for details.
Sidenote: you probably have an error in Self.NextId += 1
line. It increments NextId
of instance, not NextId
of class. To increment class's counter use CRoom.NextId += 1
or Self.__class__.NextId += 1
.
Do you actually need to reference the classes at class definition time? ie.
class CRoom(object):
person = CPerson("a person")
Or (more likely), do you just need to use CPerson in the methods of your class (and vice versa). eg:
class CRoom(object):
def getPerson(self): return CPerson("someone")
If the second, there's no problem - as by the time the method gets called rather than defined, the module will be imported. Your sole problem is how to refer to it. Likely you're doing something like:
from CRoom import CPerson # or even import *
With circularly referencing modules, you can't do this, as at the point one module imports another, the original modules body won't have finished executing, so the namespace will be incomplete. Instead, use qualified references. ie:
#croom.py
import cperson
class CRoom(object):
def getPerson(self): return cperson.CPerson("someone")
Here, python doesn't need to lookup the attribute on the namespace until the method actually gets called, by which time both modules should have completed their initialisation.
First, naming your arguments with uppercase letters is confusing. Since Python does not have formal, static type checking, we use the UpperCase
to mean a class and lowerCase
to mean an argument.
Second, we don't bother with CRoom and CPerson. Upper case is sufficient to indicate it's a class. The letter C isn't used. Room
. Person
.
Third, we don't usually put things in One Class Per File format. A file is a Python module, and we more often import an entire module with all the classes and functions.
[I'm aware those are habits -- you don't need to break them today, but they do make it hard to read.]
Python doesn't use statically defined types like C++. When you define a method function, you don't formally define the data type of the arguments to that function. You merely list some variable names. Hopefully, the client class will provide arguments of the correct type.
At run time, when you make a method request, then Python has to be sure the object has the method. NOTE. Python doesn't check to see if the object is the right type -- that doesn't matter. It only checks to see if it has the right method.
The loop between room.Room
and person.Person
is a problem. You don't need to include one when defining the other.
It's safest to import the entire module.
Here's 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
Works fine as long as Person is eventually defined in the namespace where this is executing. Person does not have to be known when you define the class.
Person does not have to be known until runtime when then Person(...) expression is evaluated.
Here's person.py
import room
class Person( object ):
def something( self, x, y ):
aRoom= room.Room( )
aRoom.addPerson( self.firstName, self.lastName, self.gender )
Your main.py
looks like this
import room
import person
r = room.Room( ... )
r.addPerson( "some", "name", "M" )
print r
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With