質問

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()
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top