2009-10-12 7 views
60

मान लें कि मेरे पास निम्न निर्देशिका संरचना है:पाइथन में परिपत्र आयात निर्भरता

a\ 
    __init__.py 
    b\ 
     __init__.py 
     c\ 
      __init__.py 
      c_file.py 
     d\ 
      __init__.py 
      d_file.py 

a पैकेज के __init__.py में, c पैकेज आयात किया जाता है। लेकिन c_file.py आयात a.b.d

प्रोग्राम विफल रहता है, यह कहता है कि bc_file.py आयात करने का प्रयास करता है जब c_file.pya.b.d आयात करने का प्रयास करता है। (और यह वास्तव में अस्तित्व में नहीं है, क्योंकि हम इसे आयात करने के बीच में थे।) Xzx34

इस समस्या का समाधान कैसे किया जा सकता है?

+1

शायद आप सापेक्ष आयात की कोशिश कर सकते हैं? http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python – eremzeit

+1

इस मदद मिल सकती है https://ncoghlan_devs-python-notes.readthedocs.org/en /latest/python_concepts/import_traps.html – maazza

+0

भी एक संदर्भ के रूप में, ऐसा लगता है कि पाइथन 3.5 (और शायद परे) पर सर्कुलर आयात की अनुमति है, लेकिन 3.4 (और शायद bellow) नहीं। –

उत्तर

53

यदि कोई सी और सी पर निर्भर करता है, तो क्या वे वास्तव में एक ही इकाई नहीं हैं?

आपको वास्तव में जांच करनी चाहिए कि आपने दो पैकेजों में क्यों विभाजित किया है, क्योंकि आपके पास कुछ कोड है, आपको किसी अन्य पैकेज में विभाजित करना चाहिए (उन्हें दोनों नए पैकेज पर निर्भर करने के लिए, लेकिन एक-दूसरे को नहीं), या आपको उन्हें एक पैकेज में विलय करना चाहिए।

+83

हां, उन्हें एक ही पैकेज माना जा सकता है। लेकिन अगर इसका परिणाम बड़े पैमाने पर बड़ी फाइल में होता है तो यह अव्यवहारिक होता है। मैं मानता हूं कि अक्सर, परिपत्र निर्भरता का मतलब है कि डिजाइन को फिर से सोचा जाना चाहिए। लेकिन वहां कुछ डिज़ाइन पैटर्न हैं जहां यह उचित है (और जहां फाइलों को एक साथ विलय करना एक बड़ी फाइल होगी) इसलिए मुझे लगता है कि यह कहना उचित है कि संकुल को संयुक्त किया जाना चाहिए या डिज़ाइन का फिर से मूल्यांकन किया जाना चाहिए। –

140

आप a/__init__.py में आयात, उदाहरण के लिए स्थगित हो सकता है:

def my_function(): 
    from a.b.c import Blah 
    return Blah() 

है कि, आयात स्थगित जब तक यह वास्तव में जरूरत है। हालांकि, मैं अपने पैकेज परिभाषाओं/उपयोगों पर भी नजदीकी नजर रखूंगा, क्योंकि चक्रीय निर्भरता के रूप में एक दिशा-निर्देश एक डिजाइन समस्या का संकेत दे सकता है।

+5

खुशी है कि आपने इसे इंगित किया है, यह मेरे लिए पूरी तरह से काम करता है। मैंने सावधानी से अपने डिजाइन पर विचार किया और सोचा कि इस मामले में, यह अच्छा है। –

+3

कभी-कभी परिपत्र संदर्भ वास्तव में अपरिहार्य हैं। यह एकमात्र दृष्टिकोण है जो इन परिस्थितियों में मेरे लिए काम करता है। –

+1

क्या यह foo के प्रत्येक कॉल में बहुत अधिक ओवरहेड नहीं जोड़ता है? –

-3

एक अन्य समाधान d_file के लिए प्रॉक्सी का उपयोग करना है।

उदाहरण के लिए, मान लीजिए कि आप bl_ क्लास को c_file के साथ साझा करना चाहते हैं। d_file इस प्रकार शामिल हैं:

class blah: 
    def __init__(self): 
     print("blah") 

यहाँ तुम क्या c_file.py में दर्ज है:

# do not import the d_file ! 
# instead, use a place holder for the proxy of d_file 
# it will be set by a's __init__.py after imports are done 
d_file = None 

def c_blah(): # a function that calls d_file's blah 
    d_file.blah() 

और एक init है .py में:

from b.c import c_file 
from b.d import d_file 

class Proxy(object): # module proxy 
    pass 
d_file_proxy = Proxy() 
# now you need to explicitly list the class(es) exposed by d_file 
d_file_proxy.blah = d_file.blah 
# finally, share the proxy with c_file 
c_file.d_file = d_file_proxy 

# c_file is now able to call d_file.blah 
c_file.c_blah() 
+11

एक अलग फ़ाइल में वैश्विक मॉड्यूल विशेषताओं को संशोधित करने जैसे कि जल्दी से एक दुःस्वप्न – Antimony

19

मैं इस आश्चर्य किया है कुछ बार (आमतौर पर उन मॉडलों से निपटने के दौरान जिन्हें एक दूसरे के बारे में जानने की आवश्यकता होती है)। सरल समाधान सिर्फ पूरे मॉड्यूल को आयात करने के लिए है, फिर आपको जिस चीज की आवश्यकता है उसका संदर्भ लें।

बजाय अन्य में

from models import Student 
एक में

, और

from models import Classroom 

करने का, बस उनमें से एक में

import models 

करते हैं, तो models.Classroom जब फोन तूम्हे इस्कि जरूरत है।

+1

सुरुचिपूर्ण और शानदार !! – nish

0

समस्या है जब एक निर्देशिका से चल रहा है, डिफ़ॉल्ट रूप से है कि केवल संकुल है कि उप निर्देशिकाओं रहे हैं, उम्मीदवार के आयात के रूप में दिखाई दे रहे हैं, ताकि आप a.b.d. आयात नहीं कर सकते है हालांकि आप बीडी आयात कर सकते हैं। चूंकि बी एक उप पैकेज है।

यदि आप वास्तव में c/__init__.py में a.b.d आयात करना चाहते हैं तो आप इसे ऊपर एक निर्देशिका होने के लिए सिस्टम पथ को बदलकर और a/__init__.py में आयात को एक .b.c. आयात करने के लिए आयात करके इसे पूरा कर सकते हैं।

आपका a/__init__.py इस तरह दिखना चाहिए:

import sys 
import os 
# set sytem path to be directory above so that a can be a 
# package namespace 
DIRECTORY_SCRIPT = os.path.dirname(os.path.realpath(__file__)) 
sys.path.insert(0,DIRECTORY_SCRIPT+"/..") 
import a.b.c 

एक अतिरिक्त कठिनाई पैदा होती है जब आप स्क्रिप्ट के रूप में सी में मॉड्यूल चलाना चाहते हैं। यहां पैकेज ए और बी मौजूद नहीं हैं। Sys.path को शीर्ष-स्तरीय निर्देशिका में इंगित करने के लिए __int__.py को हैक कर सकते हैं और फिर c.b.d आयात करने के लिए पूर्ण पथ का उपयोग करने में सक्षम होने के लिए सी के अंदर किसी भी मॉड्यूल में __init__ आयात करें। मुझे संदेह है कि __init__.py आयात करना अच्छा अभ्यास है लेकिन उसने मेरे उपयोग के मामलों के लिए काम किया है।