سؤال

حسنًا، لدي وحدتان، تحتوي كل منهما على فصل دراسي، والمشكلة هي أن فصولهما تشير إلى بعضها البعض.

لنفترض على سبيل المثال أن لدي وحدة غرفة ووحدة شخص تحتوي على CRroom وCPerson.

تحتوي فئة CRoom على معلومات حول الغرفة، وقائمة CPerson لكل فرد في الغرفة.

ومع ذلك، تحتاج فئة CPerson في بعض الأحيان إلى استخدام فئة CRoom للغرفة الموجودة فيها، على سبيل المثال للعثور على الباب، أو لمعرفة الأشخاص الآخرين الموجودين في الغرفة أيضًا.

تكمن المشكلة في استيراد الوحدتين لبعضهما البعض، وقد تلقيت خطأ استيراد بشأن أيهما يتم استيراده ثانيًا :(

في لغة c++، يمكنني حل هذه المشكلة عن طريق تضمين الرؤوس فقط، وبما أن الفئات في كلتا الحالتين تحتوي فقط على مؤشرات للفئة الأخرى، فإن الإعلان الأمامي سيكون كافيًا للرأس على سبيل المثال:

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

هل هناك طريقة للقيام بذلك في بايثون، بخلاف وضع كلا الفئتين في نفس الوحدة أو شيء من هذا القبيل؟

يحرر:تمت إضافة مثال بيثون يوضح المشكلة في استخدام الفئات المذكورة أعلاه

خطأ:

التتبع (آخر مكالمة أخيرة):
الملف "C:\Projects\python est\main.py"، السطر 1، في
من غرفة استيراد CRoom
ملف "C:\Projects\python est oom.py"، السطر 1، في
من شخص استيراد CPerson
الملف "C:\Projects\python est\person.py"، السطر 1، في
من غرفة استيراد CRoom
خطأ في الاستيراد:لا يمكن استيراد الاسم 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

أنت لا تستخدم CRoom في person.py, ، لذلك لا تستورده.بسبب الارتباط الديناميكي، لا تحتاج بايثون إلى "رؤية كافة تعريفات الفئات في وقت الترجمة".

إذا كنت فعلا يفعل يستخدم CRoom في person.py, ، ثم تغير from room import CRoom ل import room واستخدام النموذج المؤهل للوحدة 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")

إذا كان الثاني، فلا توجد مشكلة - كما هو الحال في الوقت الذي تحصل فيه الطريقة مُسَمًّى بدلاً من تعريفها، سيتم استيراد الوحدة.مشكلتك الوحيدة هي كيفية الرجوع إليها.من المحتمل أنك تفعل شيئًا مثل:

from CRoom import CPerson # or even import *

مع الوحدات النمطية المرجعية بشكل دائري، لا يمكنك القيام بذلك، لأنه عند النقطة التي تستورد فيها وحدة أخرى، لن يكون نص الوحدات الأصلية قد انتهى من التنفيذ، وبالتالي ستكون مساحة الاسم غير مكتملة.بدلاً من ذلك، استخدم المراجع المؤهلة.أي:

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

هنا، لا تحتاج بايثون إلى البحث عن السمة في مساحة الاسم حتى يتم استدعاء الطريقة فعليًا، وفي ذلك الوقت يجب أن تكون كلتا الوحدتين قد أكملتا التهيئة.

أولاً، إن تسمية وسيطاتك بأحرف كبيرة أمر مربك.نظرًا لأن لغة Python لا تحتوي على فحص رسمي وثابت للنوع، فإننا نستخدم التابع UpperCase يعني فئة و lowerCase ليعني حجة.

ثانيًا، نحن لا نهتم بـ CRroom وCPerson.الأحرف الكبيرة كافية للإشارة إلى أنها فئة.لم يتم استخدام الحرف C. Room. Person.

ثالثًا، نحن لا نضع الأشياء عادةً فئة واحدة لكل ملف شكل.الملف عبارة عن وحدة نمطية في لغة Python، وغالبًا ما نقوم باستيراد وحدة كاملة تحتوي على جميع الفئات والوظائف.

[أنا أدرك أن هذه عادات - لست بحاجة إلى كسرها اليوم، لكنها تجعل من الصعب قراءتها.]

لا تستخدم Python أنواعًا محددة بشكل ثابت مثل C++.عندما تقوم بتعريف دالة أسلوب، فإنك لا تحدد بشكل رسمي نوع بيانات الوسائط الخاصة بتلك الوظيفة.أنت فقط تدرج بعض أسماء المتغيرات.نأمل أن توفر فئة العميل وسيطات من النوع الصحيح.

في وقت التشغيل، عندما تقوم بطلب طريقة، يجب أن تتأكد بايثون من أن الكائن لديه الطريقة.ملحوظة.لا تتحقق بايثون لمعرفة ما إذا كان الكائن من النوع الصحيح أم لا، وهذا لا يهم.إنه يتحقق فقط لمعرفة ما إذا كان لديه الطريقة الصحيحة.

الحلقة بين 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.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

هل يمكن أن مجرد اسم مستعار ثانية واحدة.

import CRoom

CPerson = CRoom.CPerson

و @S.Lott إذا كنت لا تستورد شيئا في وحدة غرفة أحصل على خطأ غير معروف بدلا من ذلك (I استيراده إلى وحدة رئيسية مثلك أظهرت)

<اقتباس فقرة>   

وTraceback (المكالمات الأخيرة الأخيرة):
   ملف "C: \ مشاريع \ الثعبان \ الاختبار \ main.py" خط 6، في
     بن = Room.AddPerson ( 'بن'، 'سوادا'، 'ذكر')
   ملف "C: \ مشاريع \ الثعبان \ الاختبار \ room.py"، السطر 12، في AddPerson
     شخص = CPerson (الاسم الأول، SecondName، الجنس، رقم)
  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