การนำเข้าแบบวงกลม (หรือวงจร) นำเข้าใน Python


353

จะเกิดอะไรขึ้นถ้าโมดูลสองโมดูลนำเข้าซึ่งกันและกัน

เพื่อสรุปปัญหาสิ่งที่เกี่ยวกับวงจรนำเข้าในงูหลาม?



1
เช่นเดียวกับการอ้างอิงดูเหมือนว่าอนุญาตการนำเข้าแบบวงกลมใน python 3.5 (และอาจมากกว่า) แต่ไม่ใช่ 3.4 (และอาจจะตะโกน)
Charlie Parker

4
ฉันใช้ python 3.7.2 และฉันยังมีข้อผิดพลาดรันไทม์เนื่องจากการอ้างอิงแบบวงกลม
Richard Whitehead

คำตอบ:


282

มีการพูดคุยที่ดีในเรื่องนี้ที่comp.lang.pythonเมื่อปีที่แล้ว มันตอบคำถามของคุณอย่างละเอียด

การนำเข้าค่อนข้างตรงไปตรงมาจริงๆ เพียงจำสิ่งต่อไปนี้:

'import' และ 'from xxx import yyy' เป็นคำสั่งที่เรียกใช้งานได้ พวกเขาดำเนินการเมื่อโปรแกรมที่รันอยู่ถึงบรรทัดนั้น

หากโมดูลไม่ได้อยู่ใน sys.modules ดังนั้นการนำเข้าจะสร้างรายการโมดูลใหม่ใน sys.modules แล้วประมวลผลรหัสในโมดูล มันจะไม่ส่งคืนการควบคุมไปยังโมดูลการโทรจนกว่าการดำเนินการเสร็จสิ้น

หากโมดูลมีอยู่ใน sys.modules การอิมพอร์ตจะส่งคืนโมดูลนั้นไม่ว่าจะดำเนินการเสร็จสิ้นหรือไม่ นั่นคือเหตุผลที่การนำเข้าแบบวนกลับอาจส่งคืนโมดูลซึ่งดูเหมือนว่าว่างเปล่าบางส่วน

ในที่สุดสคริปต์เรียกใช้ทำงานในโมดูลชื่อ __main__ การนำเข้าสคริปต์ภายใต้ชื่อของตัวเองจะสร้างโมดูลใหม่ที่ไม่เกี่ยวข้องกับ __main__

นำมารวมกันและคุณไม่ควรประหลาดใจเมื่อนำเข้าโมดูล


13
@meawoppl คุณช่วยขยายความคิดเห็นนี้ได้ไหม พวกเขาเปลี่ยนไปโดยเฉพาะอย่างไร?
Dan Schien

3
ณ ตอนนี้การอ้างอิงเดียวกับการนำเข้าแบบวงกลมใน python3 "มีอะไรใหม่?" หน้าคือใน 3.5 หนึ่ง มันบอกว่า "สนับสนุนการนำเข้าแบบวงกลมที่เกี่ยวข้องกับการนำเข้าแบบสัมพันธ์" @meawoppl คุณพบสิ่งอื่นใดที่ไม่ปรากฏในหน้าเหล่านี้หรือไม่
zezollo

4
พวกเขา def ไม่รองรับใน 3.0-3.4 หรืออย่างน้อยความหมายของความสำเร็จนั้นแตกต่างกัน นี่คือบทสรุปที่ฉันพบว่า dos ไม่ได้พูดถึงการเปลี่ยนแปลง 3.5 gist.github.com/datagrok/40bf84d5870c41a77dc6
meawoppl

โปรดคุณสามารถขยายใน "สุดท้ายสคริปต์การดำเนินการรันในโมดูลชื่อmainการนำเข้าสคริปต์ภายใต้ชื่อของตัวเองจะสร้างโมดูลใหม่ที่ไม่เกี่ยวข้องกับmain " เพื่อช่วยให้ว่าไฟล์เป็น a.py และเมื่อมันทำงานเป็นจุดเริ่มต้นที่หลัก itsbthe หลักตอนนี้ถ้ามันมีรหัสเช่นจากการนำเข้าตัวแปรบาง จากนั้นไฟล์เดียวกัน 'a.py' จะถูกโหลดในตารางโมดูล sys หรือไม่ ดังนั้นหมายความว่าถ้ามันมีคำสั่งพิมพ์แล้วมันจะทำงานสองครั้ง? หนึ่งครั้งสำหรับไฟล์หลักและอีกครั้งเมื่อพบการนำเข้า
ตัวแปร

คำตอบนี้มีอายุ 10 ปีและฉันต้องการอัปเดตที่ทันสมัยเพื่อให้แน่ใจว่ามันยังคงถูกต้องใน Python รุ่นต่าง ๆ , 2.x หรือ 3.x
Fallenreaper

296

ถ้าคุณทำimport fooข้างในbarและimport barข้างในfooมันก็ใช้ได้ดี เมื่อเวลาที่สิ่งใดทำงานจริงโมดูลทั้งสองจะถูกโหลดอย่างเต็มที่และจะมีการอ้างอิงถึงกันและกัน

ปัญหาคือเมื่อแทนคุณทำและfrom foo import abc from bar import xyzเพราะตอนนี้แต่ละโมดูลต้องการโมดูลอื่นที่จะนำเข้าแล้ว (เพื่อให้ชื่อที่เรากำลังนำเข้าอยู่) ก่อนที่จะสามารถนำเข้า


27
ดูเหมือนว่าfrom foo import *และfrom bar import *จะทำงานได้ดี
Akavall

1
ตรวจสอบการแก้ไขโพสต์ด้านบนโดยใช้ a.py/b.py เขาไม่ได้ใช้from x import yและยังได้รับข้อผิดพลาดในการนำเข้าแบบวงกลม
Greg Ennis

2
สิ่งนี้ไม่เป็นความจริงทั้งหมด เช่นเดียวกับการนำเข้า * จากหากคุณพยายามเข้าถึงองค์ประกอบในการนำเข้าแบบวงกลมที่ระดับบนสุดดังนั้นก่อนที่สคริปต์จะดำเนินการเสร็จสิ้นคุณจะมีปัญหาเดียวกัน ตัวอย่างเช่นหากคุณกำลังตั้งค่าแพคเกจทั่วโลกในหนึ่งแพคเกจจากที่อื่นและพวกเขาทั้งสองรวมกัน ฉันกำลังทำสิ่งนี้เพื่อสร้างโรงงานเลอะเทอะสำหรับวัตถุในคลาสพื้นฐานซึ่งวัตถุนั้นอาจเป็นหนึ่งในคลาสย่อยจำนวนหนึ่งและการใช้รหัสไม่จำเป็นต้องระวังว่ามันกำลังสร้างอะไรอยู่
AaronM

3
@Akavall ไม่จริง ซึ่งจะนำเข้าเฉพาะชื่อที่พร้อมใช้งานเมื่อเรียกใช้importคำสั่ง ดังนั้นมันจะไม่เกิดข้อผิดพลาด แต่คุณอาจไม่ได้รับตัวแปรทั้งหมดที่คุณคาดหวัง
2559

3
หมายเหตุถ้าคุณทำ from foo import *และfrom bar import *ทุกอย่างที่ดำเนินการในfooอยู่ในช่วงเริ่มต้นbarและbarยังไม่ได้กำหนดฟังก์ชั่นจริงใน...
Martian2049

100

การนำเข้าแบบวงกลมสิ้นสุดลง แต่คุณต้องระวังไม่ให้ใช้โมดูลที่นำเข้าแบบวนซ้ำระหว่างการเริ่มต้นโมดูล

พิจารณาไฟล์ต่อไปนี้:

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

หากคุณรัน a.py คุณจะได้รับสิ่งต่อไปนี้:

$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out

ในการนำเข้าที่สองของ b.py (ในที่สองa in), Python interpreter ไม่ได้นำเข้าbอีกครั้งเพราะมันมีอยู่แล้วในโมดูล dict

ถ้าคุณพยายามที่จะเข้าถึงb.xจากในระหว่างการเตรียมโมดูลคุณจะได้รับaAttributeError

ต่อท้ายบรรทัดต่อไปนี้เพื่อ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เท่านั้น


14
สิ่งนี้อธิบายปัญหาได้อย่างมาก แต่วิธีการแก้ปัญหาเป็นอย่างไร เราจะนำเข้าและพิมพ์ x อย่างถูกต้องได้อย่างไร? โซลูชันอื่นข้างต้นไม่ได้ผลสำหรับฉัน
เมห์เม็ต

ผมคิดว่าคำตอบนี้จะได้รับประโยชน์มากขึ้นหากคุณใช้แทน__name__ 'a'ในตอนแรกฉันสับสนอย่างมากว่าทำไมไฟล์จะถูกดำเนินการสองครั้ง
Bergi

30

ตามที่คำตอบอื่น ๆ อธิบายถึงรูปแบบนี้เป็นที่ยอมรับในหลาม:

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)

แอพ B

# images/serializers.py

from profiles.serializers import SimplifiedProfileSerializer

class SimplifiedImageSerializer(serializers.Serializer):
    title = serializers.CharField()

class ImageSerializer(SimplifiedImageSerializer):
    profile = SimplifiedProfileSerializer()

จาก David Beazleys โมดูลการพูดคุยที่ยอดเยี่ยมและแพ็คเกจ: สดและปล่อยให้ตาย! - PyCon 2015 , 1:54:00นี่คือวิธีการจัดการกับการนำเข้าวงกลมหลาม:

try:
    from images.serializers import SimplifiedImageSerializer
except ImportError:
    import sys
    SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']

การดำเนินการนี้จะพยายามนำเข้าSimplifiedImageSerializerและหากImportErrorมีการยกระดับเนื่องจากมีการนำเข้าแล้วจะเป็นการดึงจาก importcache

PS: คุณต้องอ่านโพสต์ทั้งหมดนี้ด้วยเสียงของ David Beazley


9
ImportError จะไม่เพิ่มขึ้นหากโมดูลได้ถูกนำเข้าแล้ว โมดูลสามารถนำเข้าได้หลายครั้งตามที่คุณต้องการเช่น "import a; import a;" ก็โอเค
Yuras

9

ฉันได้ตัวอย่างที่นี่ที่ทำให้ฉัน!

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"

ที่บรรทัดคำสั่ง: $ python 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

2
คุณแก้ไขได้อย่างไร ฉันพยายามที่จะเข้าใจการนำเข้าวงกลมเพื่อแก้ไขปัญหาของตัวเองที่มีลักษณะมากคล้ายกับสิ่งที่คุณทำ ...
c089

12
เอ่อ ... ฉันคิดว่าฉันคงแก้ปัญหาของฉันด้วยการแฮ็กที่น่าเกลียดนี้อย่างไม่น่าเชื่อ {{{ถ้าไม่ใช่ 'foo.bar' ใน sys.modules: จากแถบการนำเข้า foo อื่น: bar = sys.modules ['foo.bar']}}} โดยส่วนตัวฉันคิดว่าการนำเข้าแบบวงกลมเป็นสัญญาณเตือนขนาดใหญ่ที่มีรหัสไม่ดี ออกแบบ ...
c089

5
@ c089 หรือคุณก็สามารถย้ายimport barในfoo.pyที่ปลาย
warvariuc

5
หากbarและfooต้องใช้ทั้งสองgXวิธีโซลูชัน 'cleanest' จะต้องใส่gXในโมดูลอื่นและมีทั้งfooและbarนำเข้าโมดูลนั้น (สะอาดที่สุดในแง่ที่ว่าไม่มีการอ้างอิงความหมายแฝง)
Tim Wilder

2
ทิมมีจุดดี โดยทั่วไปเป็นเพราะbarไม่สามารถหาได้gXใน foo การนำเข้าแบบวงกลมนั้นใช้ได้ด้วยตัวเอง แต่ก็gXไม่ได้ถูกกำหนดเมื่อนำเข้า
Martian2049

9

โมดูล a.py:

import b
print("This is from module a")

โมดูล b.py

import a
print("This is from module b")

กำลังเรียกใช้ "Module a" จะส่งออก:

>>> 
'This is from module a'
'This is from module b'
'This is from module a'
>>> 

มันออกมา 3 บรรทัดในขณะที่มันควรจะส่งออก infinitival เพราะการนำเข้าแบบวงกลม จะเกิดอะไรขึ้นทีละบรรทัดขณะที่เรียกใช้ "โมดูล a" อยู่ที่นี่

  1. import bบรรทัดแรกคือ ดังนั้นมันจะไปที่โมดูล b
  2. import aบรรทัดแรกที่โมดูลข ดังนั้นมันจะไปที่โมดูล
  3. บรรทัดแรกที่โมดูล a คือimport bแต่โปรดทราบว่าบรรทัดนี้จะไม่ถูกดำเนินการอีกต่อไปเพราะทุกไฟล์ในไพ ธ อนรันบรรทัดการนำเข้าเพียงครั้งเดียวจึงไม่สำคัญว่าจะดำเนินการที่ไหนหรือเมื่อใด "This is from module a"จึงจะส่งผ่านไปยังบรรทัดถัดไปและพิมพ์
  4. หลังจากเสร็จสิ้นการเยี่ยมชมโมดูลทั้งหมด a จากโมดูล b เรายังคงอยู่ที่โมดูล b ดังนั้นบรรทัดถัดไปจะพิมพ์"This is from module b"
  5. บรรทัดโมดูล b ถูกดำเนินการอย่างสมบูรณ์ ดังนั้นเราจะกลับไปโมดูลที่เราเริ่มโมดูลข
  6. บรรทัดการนำเข้า b ถูกดำเนินการแล้วและจะไม่ถูกดำเนินการอีกครั้ง บรรทัดถัดไปจะพิมพ์"This is from module a"และโปรแกรมจะเสร็จสิ้น

4

ฉันเห็นด้วยกับคำตอบของ pythone อย่างสมบูรณ์ แต่ฉันได้สะดุดกับรหัสบางอย่างที่มีข้อบกพร่องด้วยการนำเข้าแบบวงกลมและทำให้เกิดปัญหาเมื่อพยายามเพิ่มการทดสอบหน่วย ดังนั้นการแก้ไขอย่างรวดเร็วโดยไม่เปลี่ยนแปลงทุกสิ่งคุณสามารถแก้ไขปัญหาได้ด้วยการนำเข้าแบบไดนามิก

# 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")

นี่ไม่ใช่การแก้ไขแบบถาวร แต่อาจช่วยคนที่ต้องการแก้ไขข้อผิดพลาดในการนำเข้าโดยไม่ต้องเปลี่ยนรหัสมากเกินไป

ไชโย!


3

มีคำตอบที่ดีมากมายที่นี่ ในขณะที่มักจะมีวิธีแก้ปัญหาอย่างรวดเร็ว แต่บางคนก็รู้สึกว่ามันเป็นระบบที่เรียบง่ายกว่าคนอื่น ๆ หากคุณมีความหรูหราในการปรับโครงสร้างบางส่วนอีกวิธีหนึ่งคือการวิเคราะห์องค์กรของรหัสของคุณและพยายามลบการพึ่งพาแบบวงกลม ตัวอย่างเช่นคุณอาจพบว่าคุณมี:

ไฟล์ a.py

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)

ไฟล์ b.py

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เมธอดออกจาก A และอนุญาตให้ลบการนำเข้า A จาก a ใน b:

refileored ไฟล์ a.py

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)

refactored File 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


2

การนำเข้าแบบวงกลมอาจสร้างความสับสนเนื่องจากการนำเข้าทำสองสิ่ง:

  1. มันรันรหัสโมดูลที่นำเข้า
  2. เพิ่มโมดูลที่อิมพอร์ตเข้าเพื่ออิมพอร์ตตารางสัญลักษณ์โกลบอลของโมดูล

อดีตทำเพียงครั้งเดียวในขณะที่หลังในแต่ละคำสั่งนำเข้า การนำเข้าแบบวงกลมจะสร้างสถานการณ์เมื่อนำเข้าโมดูลใช้การนำเข้าด้วยรหัสที่ดำเนินการบางส่วน ดังนั้นมันจะไม่เห็นวัตถุที่สร้างขึ้นหลังจากคำสั่งนำเข้า ตัวอย่างรหัสด้านล่างแสดงให้เห็นถึงมัน

การนำเข้าแบบวงกลมไม่ใช่สิ่งชั่วร้ายที่สุดที่ควรหลีกเลี่ยงในทุกกรณี ในบางเฟรมเวิร์กเช่น Flask มันค่อนข้างเป็นธรรมชาติและปรับแต่งโค้ดของคุณเพื่อกำจัดมันไม่ได้ทำให้โค้ดดีขึ้น

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"

หลาม main.py เอาต์พุตพร้อมความคิดเห็น

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

1

ฉันแก้ไขปัญหาด้วยวิธีต่อไปนี้และทำงานได้ดีโดยไม่มีข้อผิดพลาด พิจารณาสองไฟล์และa.pyb.py

ฉันเพิ่มสิ่งนี้ลงไปa.pyและใช้งานได้

if __name__ == "__main__":
        main ()

a.py:

import b
y = 2
def main():
    print ("a out")
    print (b.x)

if __name__ == "__main__":
    main ()

b.py:

import a
print ("b out")
x = 3 + a.y

ผลลัพธ์ที่ฉันได้รับคือ

>>> b out 
>>> a out 
>>> 5

0

โอเคฉันคิดว่าฉันมีทางออกที่ยอดเยี่ยม สมมติว่าคุณมีไฟล์และแฟ้ม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โดยไม่ต้องใช้ Python ในการดำเนินการคำสั่งการนำเข้าใด ๆ ในไฟล์bและทำให้คุณหลีกเลี่ยงการนำเข้าแบบวงกลมใด ๆ

ตัวอย่างเช่น:

ไฟล์ a:

class A(object):

     def __init__(self, name):

         self.name = name

CLASS = A("me")

import b

go = B(6)

go.dostuff

ไฟล์ b:

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."

voila


from a import CLASSไม่ได้ข้ามการเรียกใช้งานโค้ดทั้งหมดใน a.py นี่คือสิ่งที่เกิดขึ้นจริง: (1) โค้ดทั้งหมดใน a.py ถูกเรียกใช้เป็นโมดูลพิเศษ "__main__" (2) ที่import bโค้ดระดับบนสุดใน b.py เริ่มทำงาน (กำหนดคลาส B) จากนั้นการควบคุมจะกลับไปที่ "__main__" (3) "__main__" go.dostuff()ในที่สุดก็ผ่านการควบคุม (4) เมื่อ dostuff () มาถึงimport aมันรันโค้ดทั้งหมดใน a.py อีกครั้งคราวนี้เป็นโมดูล "a"; จากนั้นจะนำเข้าวัตถุคลาสจากโมดูลใหม่ "a" ดังนั้นจริง ๆ แล้วมันจะทำงานได้ดีเท่า ๆ กันหากคุณใช้import aที่ใดก็ได้ใน b.py
Matthias Fripp
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.