यदि दो मॉड्यूल एक दूसरे को आयात करते हैं तो क्या होगा?
समस्या को सामान्य करने के लिए, अजगर में चक्रीय आयात के बारे में क्या?
यदि दो मॉड्यूल एक दूसरे को आयात करते हैं तो क्या होगा?
समस्या को सामान्य करने के लिए, अजगर में चक्रीय आयात के बारे में क्या?
जवाबों:
पिछले साल comp.lang.python में इस पर बहुत अच्छी चर्चा हुई थी। यह आपके प्रश्न का बहुत अच्छी तरह से उत्तर देता है।
आयात बहुत सीधे हैं। बस निम्नलिखित याद रखें:
'आयात' और 'xxx आयात yyy' से निष्पादन योग्य कथन हैं। जब रनिंग प्रोग्राम उस लाइन तक पहुंचता है तो वे निष्पादित करते हैं।
यदि कोई मॉड्यूल sys.modules में नहीं है, तो एक आयात sys.modules में नए मॉड्यूल प्रविष्टि बनाता है और फिर मॉड्यूल में कोड निष्पादित करता है। निष्पादन पूरा होने तक यह कॉलिंग मॉड्यूल पर नियंत्रण वापस नहीं करता है।
यदि कोई मॉड्यूल sys.modules में मौजूद है, तो एक आयात बस उस मॉड्यूल को लौटाता है, चाहे उसने निष्पादन को पूरा किया हो या नहीं। यही कारण है कि चक्रीय आयात मॉड्यूल लौटा सकते हैं जो आंशिक रूप से खाली दिखाई देते हैं।
अंत में, निष्पादित स्क्रिप्ट __main__ नाम के एक मॉड्यूल में चलती है, स्क्रिप्ट को अपने नाम से आयात करने से __main__ से असंबंधित एक नया मॉड्यूल बन जाएगा।
मॉड्यूल आयात करते समय आपको बहुत कुछ लेना चाहिए और आपको कोई आश्चर्य नहीं होना चाहिए।
यदि आप import foo
अंदर bar
और import bar
अंदर करते हैं foo
, तो यह ठीक काम करेगा। जब तक वास्तव में कुछ भी चलता है, तब तक दोनों मॉड्यूल पूरी तरह से लोड हो जाएंगे और एक दूसरे के संदर्भ होंगे।
समस्या यह है कि जब आप करते हैं from foo import abc
और इसके बजाय from bar import xyz
। क्योंकि अब प्रत्येक मॉड्यूल को आयात करने से पहले दूसरे मॉड्यूल को पहले से ही आयात करने की आवश्यकता होती है (ताकि हम जो नाम आयात कर रहे हैं वह मौजूद हो)।
from foo import *
और from bar import *
यह भी ठीक काम करेगा।
from x import y
, और अभी भी परिपत्र आयात त्रुटि मिलती है
import
कथन निष्पादित होने पर उपलब्ध हैं । तो यह त्रुटि नहीं करेगा, लेकिन आपको वे सभी चर नहीं मिल सकते हैं जिनकी आप अपेक्षा करते हैं।
from foo import *
और from bar import *
निष्पादित की गई सभी चीजें foo
प्रारंभिक चरण में हैं bar
, और वास्तविक कार्यों को bar
अभी तक परिभाषित नहीं किया गया है ...
चक्रीय आयात समाप्त हो जाते हैं, लेकिन आपको मॉड्यूल इनिशियलाइज़ेशन के दौरान चक्रीय-आयातित मॉड्यूल का उपयोग न करने के लिए सावधान रहने की आवश्यकता है।
निम्नलिखित फाइलों पर विचार करें:
a.py:
print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules, )
import b
print "a out"
b.py:
print "b in"
import a
print "b out"
x = 3
यदि आप थिंकपैड निष्पादित करते हैं, तो आपको निम्नलिखित मिलेंगे:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out
B.py? S के दूसरे आयात में (दूसरे में) a in
) , Python दुभाषिया b
फिर से आयात नहीं करता है , क्योंकि यह मॉड्यूल में पहले से ही मौजूद है।
आप का उपयोग करने का प्रयास करें b.x
सेa
मॉड्यूल आरंभीकरण के दौरान, आप एक मिल जाएगा AttributeError
।
निम्नलिखित पंक्ति को इसमें संलग्न करें a.py
:
print b.x
फिर, आउटपुट है:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
File "a.py", line 4, in <module>
import b
File "/home/shlomme/tmp/x/b.py", line 2, in <module>
import a
File "/home/shlomme/tmp/x/a.py", line 7, in <module>
print b.x
AttributeError: 'module' object has no attribute 'x'
इसका कारण यह है कि मॉड्यूल आयात पर निष्पादित किए जाते हैं और समय b.x
पर एक्सेस किए जाने पर, लाइन x = 3
को अभी तक निष्पादित नहीं किया गया है, जो केवल उसके बाद होगा b out
।
__name__
बजाय इसका इस्तेमाल करते हैं तो यह जवाब बहुत फायदा पहुंचाएगा 'a'
। शुरुआत में, मैं पूरी तरह से उलझन में था कि एक फाइल को दो बार क्यों निष्पादित किया जाएगा।
जैसा कि अन्य उत्तर बताते हैं कि यह पैटर्न अजगर में स्वीकार्य है:
def dostuff(self):
from foo import bar
...
जब फ़ाइल को अन्य मॉड्यूल द्वारा आयात किया जाता है तो आयात विवरण के निष्पादन से बचना होगा। केवल अगर कोई तार्किक परिपत्र निर्भरता है, तो यह विफल हो जाएगा।
अधिकांश परिपत्र आयात वास्तव में तार्किक परिपत्र आयात नहीं ImportError
हैं, बल्कि इस तरह से त्रुटियों को बढ़ाते हैंimport()
से पूरी फ़ाइल के शीर्ष स्तर के बयानों का मूल्यांकन किया जाता है।
ImportErrors
यदि आप सकारात्मक रूप से शीर्ष पर अपने आयात चाहते हैं तो इनसे लगभग हमेशा बचा जा सकता है :
इस परिपत्र आयात पर विचार करें:
# profiles/serializers.py
from images.serializers import SimplifiedImageSerializer
class SimplifiedProfileSerializer(serializers.Serializer):
name = serializers.CharField()
class ProfileSerializer(SimplifiedProfileSerializer):
recent_images = SimplifiedImageSerializer(many=True)
# images/serializers.py
from profiles.serializers import SimplifiedProfileSerializer
class SimplifiedImageSerializer(serializers.Serializer):
title = serializers.CharField()
class ImageSerializer(SimplifiedImageSerializer):
profile = SimplifiedProfileSerializer()
डेविड बेज़लेज़ से उत्कृष्ट टॉक मॉड्यूल और पैकेज: लाइव और लेट डाई! -1:54:00
अजगर 2015 , यहाँ अजगर में परिपत्र आयात से निपटने का एक तरीका है:
try:
from images.serializers import SimplifiedImageSerializer
except ImportError:
import sys
SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']
यह आयात करने की कोशिश करता है SimplifiedImageSerializer
और अगर ImportError
उठाया जाता है, क्योंकि यह पहले से ही आयात किया गया है, तो यह इसे आयातक से खींच लेगा।
PS: आपको डेविड बेज़ले की आवाज़ में इस पूरी पोस्ट को पढ़ना होगा।
मुझे यहाँ एक उदाहरण मिला जिसने मुझे मारा!
foo.py
import bar
class gX(object):
g = 10
bar.py
from foo import gX
o = gX()
main.py
import foo
import bar
print "all done"
कमांड लाइन पर: $ अजगर main.py
Traceback (most recent call last):
File "m.py", line 1, in <module>
import foo
File "/home/xolve/foo.py", line 1, in <module>
import bar
File "/home/xolve/bar.py", line 1, in <module>
from foo import gX
ImportError: cannot import name gX
import bar
में foo.py
करने के लिए अंत
bar
और foo
दोनों का उपयोग करना चाहिए gX
, 'साफ' समाधान डाल करने के लिए है gX
एक और मॉड्यूल में और दोनों foo
और bar
आयात कि मॉड्यूल। (इस अर्थ में सबसे साफ है कि कोई छिपी हुई शब्दार्थ निर्भरता नहीं हैं।)
bar
यह भी gX
फू में नहीं मिल सकता है । परिपत्र आयात अपने आप ठीक है, लेकिन यह सिर्फ इतना gX
है कि इसे आयात किए जाने पर परिभाषित नहीं किया गया है।
मॉड्यूल थिंकपैड:
import b
print("This is from module a")
मॉड्यूल b.py
import a
print("This is from module b")
आउटपुट "मॉड्यूल" चल रहा है:
>>>
'This is from module a'
'This is from module b'
'This is from module a'
>>>
यह 3 लाइनों का उत्पादन करता है, जबकि इसे परिपत्र आयात के कारण इनफिनिटिव का उत्पादन करना था। "मॉड्यूल" को चलाने के दौरान लाइन से लाइन क्या होती है यहां सूचीबद्ध है:
import b
। इसलिए यह मॉड्यूल बी का दौरा करेगाimport a
। इसलिए यह मॉड्यूल ए का दौरा करेगाimport b
लेकिन ध्यान दें कि इस लाइन को अब फिर से निष्पादित नहीं किया जाएगा , क्योंकि अजगर में हर फाइल सिर्फ एक बार के लिए एक आयात लाइन निष्पादित करती है, यह कोई फर्क नहीं पड़ता कि इसे कहां या कब निष्पादित किया जाता है। इसलिए यह अगली पंक्ति में जाएगा और प्रिंट करेगा "This is from module a"
।"This is from module b"
"This is from module a"
और कार्यक्रम समाप्त हो जाएगा।मैं यहां अजगर के जवाब से पूरी तरह सहमत हूं। लेकिन मैंने कुछ कोडों पर ठोकर खाई है जो परिपत्र आयात के साथ त्रुटिपूर्ण थे और यूनिट परीक्षणों को जोड़ने की कोशिश करते समय मुद्दों का कारण बने। तो जल्दी से सब कुछ बदलने के बिना इसे पैच करें आप डायनेमिक आयात करके समस्या को हल कर सकते हैं।
# Hack to import something without circular import issue
def load_module(name):
"""Load module using imp.find_module"""
names = name.split(".")
path = None
for name in names:
f, path, info = imp.find_module(name, path)
path = [path]
return imp.load_module(name, f, path[0], info)
constants = load_module("app.constants")
फिर से, यह एक स्थायी समाधान नहीं है, लेकिन किसी ऐसे व्यक्ति की मदद कर सकता है जो बहुत अधिक कोड को बदले बिना आयात त्रुटि को ठीक करना चाहता है।
चीयर्स!
यहाँ बहुत सारे शानदार उत्तर हैं। जबकि आमतौर पर समस्या का त्वरित समाधान होता है, जिनमें से कुछ दूसरों की तुलना में अधिक पायथोनिक महसूस करते हैं, यदि आपके पास कुछ रिफैक्टरिंग करने की लक्जरी है, तो एक और दृष्टिकोण आपके कोड के संगठन का विश्लेषण करना है, और परिपत्र निर्भरता को दूर करने का प्रयास करना है। उदाहरण के लिए, आपके पास हो सकता है:
एक फ़ाइल को दर्ज करें
from b import B
class A:
@staticmethod
def save_result(result):
print('save the result')
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
फ़ाइल
from a import A
class B:
@staticmethod
def do_something_b_ish(param):
A.save_result(B.use_param_like_b_would(param))
इस स्थिति में, एक स्थिर विधि को एक अलग फ़ाइल में ले जाना, कहते हैं c.py
:
फ़ाइल c.py
def save_result(result):
print('save the result')
save_result
ए से विधि को हटाने की अनुमति देगा , और इस प्रकार बी में ए से आयात को हटाने की अनुमति देगा:
फ़ाइल पुनर्प्राप्त फ़ाइल
from b import B
from c import save_result
class A:
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
फ़ाइल b.py को पुनःप्राप्त
from c import save_result
class B:
@staticmethod
def do_something_b_ish(param):
save_result(B.use_param_like_b_would(param))
सारांश में, यदि आपके पास एक उपकरण है (उदाहरण pylint या PyCharm) जो उन तरीकों पर रिपोर्ट करता है जो स्थिर हो सकते हैं, तो बस staticmethod
उन पर एक डेकोरेटर फेंकना चेतावनी को चुप करने का सबसे अच्छा तरीका नहीं हो सकता है। भले ही विधि वर्ग से संबंधित लगती है, लेकिन इसे अलग करना बेहतर हो सकता है, खासकर यदि आपके पास कई निकटता से संबंधित मॉड्यूल हैं जिनकी समान कार्यक्षमता की आवश्यकता हो सकती है और आप DRY सिद्धांतों का अभ्यास करना चाहते हैं।
परिपत्र आयात भ्रामक हो सकता है क्योंकि आयात दो चीजें करता है:
पूर्व केवल एक बार किया जाता है, जबकि बाद में प्रत्येक आयात विवरण। सर्कुलर आयात स्थिति बनाता है जब आयात मॉड्यूल आंशिक रूप से निष्पादित कोड के साथ आयातित एक का उपयोग करता है। परिणाम में यह आयात विवरण के बाद निर्मित वस्तुओं को नहीं देखेगा। नीचे दिए गए कोड नमूने इसे प्रदर्शित करते हैं।
सर्कुलर आयात हर कीमत पर टाले जाने वाली अंतिम बुराई नहीं है। फ्लास्क जैसी कुछ रूपरेखाओं में वे काफी स्वाभाविक हैं और उन्हें समाप्त करने के लिए आपके कोड को ट्विक करना कोड को बेहतर नहीं बनाता है।
main.py
print 'import b'
import b
print 'a in globals() {}'.format('a' in globals())
print 'import a'
import a
print 'a in globals() {}'.format('a' in globals())
if __name__ == '__main__':
print 'imports done'
print 'b has y {}, a is b.a {}'.format(hasattr(b, 'y'), a is b.a)
b.by
print "b in, __name__ = {}".format(__name__)
x = 3
print 'b imports a'
import a
y = 5
print "b out"
a.py
print 'a in, __name__ = {}'.format(__name__)
print 'a imports b'
import b
print 'b has x {}'.format(hasattr(b, 'x'))
print 'b has y {}'.format(hasattr(b, 'y'))
print "a out"
टिप्पणियों के साथ अजगर मेनफ्रेम आउटपुट
import b
b in, __name__ = b # b code execution started
b imports a
a in, __name__ = a # a code execution started
a imports b # b code execution is already in progress
b has x True
b has y False # b defines y after a import,
a out
b out
a in globals() False # import only adds a to main global symbol table
import a
a in globals() True
imports done
b has y True, a is b.a True # all b objects are available
मैंने निम्नलिखित तरीके से समस्या को हल किया, और यह बिना किसी त्रुटि के अच्छी तरह से काम करता है। दो फ़ाइलों पर विचार करें a.py
और b.py
।
मैंने a.py
इसे जोड़ा और यह काम किया।
if __name__ == "__main__":
main ()
import b
y = 2
def main():
print ("a out")
print (b.x)
if __name__ == "__main__":
main ()
import a
print ("b out")
x = 3 + a.y
मुझे जो आउटपुट मिलता है
>>> b out
>>> a out
>>> 5
ठीक है, मुझे लगता है कि मेरे पास एक बहुत अच्छा समाधान है। मान लें कि आपके पास फ़ाइल a
और फ़ाइल है b
। आप एक है def
या एक class
फ़ाइल में b
है कि आप मॉड्यूल में उपयोग करना चाहते हैं a
, लेकिन आप कुछ और ही है, या तो एक def
, class
या फ़ाइल से चर a
है कि आप अपने परिभाषा या फाइल में कक्षा में की जरूरत है b
। फ़ाइल a
में फ़ंक्शन या क्लास को कॉल करने के बाद , a
फ़ाइल में b
, लेकिन फ़ाइल से फ़ंक्शन या क्लास को कॉल करने से पहले आप क्या कर सकते हैंb
आपको फ़ाइल की आवश्यकता होती है a
, import b
फिर कहते हैं , और यहाँ मुख्य भाग है फ़ाइल में सभी परिभाषाओं या कक्षाओं में b
जिनकी आवश्यकता हैdef
याclass
फ़ाइल सेa
(चलो इसे कहते हैं CLASS
), आप कहते हैंfrom a import CLASS
यह काम करता है क्योंकि आप फ़ाइल में b
किसी भी आयात विवरण को निष्पादित करने के बिना पायथन आयात कर सकते हैं b
, और इस प्रकार आप किसी भी परिपत्र आयात को हटा सकते हैं।
उदाहरण के लिए:
class A(object):
def __init__(self, name):
self.name = name
CLASS = A("me")
import b
go = B(6)
go.dostuff
class B(object):
def __init__(self, number):
self.number = number
def dostuff(self):
from a import CLASS
print "Hello " + CLASS.name + ", " + str(number) + " is an interesting number."
देखा।
from a import CLASS
वास्तव में ऑरेकल में सभी कोड निष्पादित करना नहीं छोड़ता है। यह वास्तव में होता है: (1) ऑरेकल का सभी कोड एक विशेष मॉड्यूल "__main__" के रूप में चलता है। (2) पर import b
, बी-थोरो में शीर्ष-स्तरीय कोड चलता है (वर्ग बी को परिभाषित करता है) और फिर "__m____" पर नियंत्रण रखता है। (३) "__main__" अंततः नियंत्रण को पास करता है go.dostuff()
। (4) जब डस्टफ़ () आता है import a
, तो यह सभी कोड को फिर से थिंकपैड में चलाता है , इस बार मॉड्यूल "ए" के रूप में; तब यह नए मॉड्यूल "a" से CLASS ऑब्जेक्ट को आयात करता है। तो वास्तव में, यह उतनी ही अच्छी तरह से काम करेगा अगर आप import a
कहीं भी बी-बीकॉम में उपयोग करते हैं।