Pythonモジュールの依存関係
-
03-07-2019 - |
質問
OK 2つのモジュールがあり、それぞれにクラスが含まれています。問題は、クラスが相互に参照していることです。
たとえば、部屋モジュールと、CRoomとCPersonを含む個人モジュールがあったとしましょう。
CRoomクラスには、ルームに関する情報と、ルーム内のすべてのCPersonリストが含まれます。
ただし、CPersonクラスは、たとえば、ドアを見つけるため、または部屋に他の誰がいるかを確認するために、その部屋のCRoomクラスを使用する必要がある場合があります。
問題は、2つのモジュールが相互にインポートしていることです。2番目にインポートしようとしているインポートエラーが表示されるだけです:(
c ++では、ヘッダーのみを含めることでこれを解決できました。どちらの場合も、クラスには他のクラスへのポインターがあるだけなので、ヘッダーには前方宣言で十分です。例:
class CPerson;//forward declare
class CRoom
{
std::set<CPerson*> People;
...
とにかくPythonでこれを行うには、両方のクラスを同じモジュールまたはそのようなものに配置する以外にありますか?
編集:上記のクラスを使用した問題を示すpythonの例を追加
エラー:
トレースバック(最新の呼び出しは最後):
ファイル&quot; C:\ Projects \ python \ test \ main.py&quot ;、
の1行目 ルームインポートからCRoom
ファイル&quot; C:\ Projects \ python \ test \ room.py&quot ;、
の1行目 人のインポートCPerson
ファイル&quot; C:\ Projects \ python \ test \ person.py&quot;、1行目、
ルームインポートからCRoom
ImportError:名前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)
解決
CRoomをインポートする必要はありません
person.py
で CRoom
を使用しないため、インポートしないでください。動的バインディングのため、Pythonは「コンパイル時にすべてのクラス定義を表示する」必要はありません。
実際に do person.py
で CRoom
を使用する場合は、 room import CRoom
を< code>部屋をインポートし、モジュール修飾フォーム room.CRoom
を使用します。詳細については、 Effbotの円形インポートをご覧ください。
補足: Self.NextId + = 1
行にエラーがある可能性があります。クラスの NextId
ではなく、インスタンスの NextId
をインクリメントします。クラスのカウンターをインクリメントするには、 CRoom.NextId + = 1
または Self .__ class __。NextId + = 1
を使用します。
他のヒント
実際にクラス定義時にクラスを参照する必要がありますか?すなわち。
class CRoom(object):
person = CPerson("a person")
または(可能性が高い)クラスのメソッドでCPersonを使用する必要があるだけですか(またはその逆)。例:
class CRoom(object):
def getPerson(self): return CPerson("someone")
2番目の場合、問題はありません-メソッドが定義されるのではなく、呼び出されるように、モジュールがインポートされます。あなたの唯一の問題は、それを参照する方法です。おそらくあなたは次のようなことをしている:
from CRoom import CPerson # or even import *
循環参照モジュールでは、これを行うことはできません。1つのモジュールが別のモジュールをインポートする時点で、元のモジュール本体の実行が完了していないため、名前空間が不完全になります。代わりに、修飾された参照を使用してください。例:
#croom.py
import cperson
class CRoom(object):
def getPerson(self): return cperson.CPerson("someone")
ここで、Pythonは、メソッドが実際に呼び出されるまで名前空間の属性をルックアップする必要はありません。その時点までに、両方のモジュールが初期化を完了する必要があります。
最初に、大文字で引数に名前を付けるのはわかりにくいです。 Pythonには正式な静的型チェックがないため、 UpperCase
を使用してクラスを意味し、 lowerCase
を引数として使用します。
第二に、CRoomとCPersonを気にしません。クラスであることを示すには、大文字で十分です。文字Cは使用されません。 Room
。 Person
。
第3に、通常、ファイルごとに1つのクラスの形式ではありません。ファイルはPythonモジュールであり、多くの場合、すべてのクラスと関数を含むモジュール全体をインポートします。
[これらは習慣であると認識しています。今日それらを破る必要はありませんが、読むのは難しくなります。]
Pythonは、C ++のような静的に定義された型を使用しません。メソッド関数を定義するとき、その関数の引数のデータ型を正式に定義することはありません。いくつかの変数名をリストするだけです。クライアントクラスが正しい型の引数を提供することを願っています。
実行時にメソッドリクエストを行う場合、Pythonはオブジェクトにメソッドがあることを確認する必要があります。注意。 Pythonは、オブジェクトが正しい型であるかどうかを確認しません-それは問題ではありません。正しいメソッドがあるかどうかを確認するだけです。
room.Room
と person.Person
の間のループは問題です。他方を定義するときに、一方を含める必要はありません。
モジュール全体をインポートするのが最も安全です。
こちらは 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
これが実行されているネームスペースで最終的にPersonが定義されている限り、正常に機能します。クラスを定義するときに、人を知る必要はありません。
Person(...)式が評価される実行時まで、Personを知る必要はありません。
こちらは person.py
import room
class Person( object ):
def something( self, x, y ):
aRoom= room.Room( )
aRoom.addPerson( self.firstName, self.lastName, self.gender )
main.py
は次のようになります
import room
import person
r = room.Room( ... )
r.addPerson( "some", "name", "M" )
print r
2番目のエイリアスのみをエイリアス化できます。
import CRoom
CPerson = CRoom.CPerson
@ S.Lott ルームモジュールに何もインポートしない場合、代わりに未定義エラーが表示されます(表示したようにメインモジュールにインポートしました)
トレースバック(最新の呼び出しは最後):
ファイル&quot; C:\ Projects \ python \ test \ main.py&quot;、6行目、
Ben = Room.AddPerson( 'Ben'、 'Blacker'、 'Male')
ファイル&quot; C:\ Projects \ python \ test \ room.py&quot ;、行12、AddPerson
Person = CPerson(FirstName、SecondName、Gender、Id)
NameError:グローバル名「CPerson」が定義されていません
また、異なるモジュールが存在する理由は、コンテナクラス(部屋など)で開始する問題がすでに発生しているためです。そのため、別のファイルに含まれるアイテム(人など)が必要でした。
編集: 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()