AttributeError: partially initialized module 'calculator' has no attribute 'select' (most likely due to a circular import)

AttributeError: partially initialized module 'calculator' has no attribute 'select' (most likely due to a circular import)

我正在做一个小项目,这样我可以更好地学习 python,该项目有 4 个文件(我可以在一个文件中完成,但很好),1 个作为主要文件,1 个作为工具 1,另一个作为工具2,另一个作为工具3.

我必须在另外 3 个中导入 main,在 main 中导入另外 3 个,这会创建一个循环导入。我找不到解决方法。任何帮助表示赞赏

代码:

main.py

import calculator
import texteditor
import textchecker

def start():
 print("Operations:")
 print("1) Calculator")
 print("2) Text Editor")
 print("3) Text Checker")
 choice1 = input("Select operation: ")
 if choice1 == "1":
     calculator.select()
 elif choice1 == "2":
     texteditor.texthub()
 elif choice1 == "3":
     textchecker.textchub
     
start()

calculator.py

import main


def select():
 while True:
  print("Type the number of the operation you want in 'Select a calculation: '")
  print("Calculations:")
  print("1) Add")
  print("2) Subtract")
  print("3) Multiply")
  print("4) Divide")
  print("5) Back To Hub")
  global calcinput
  calcinput = input("Select a calculation: ")


  if calcinput == "1":
   global num1
   global num2
   num1 = int(input("First Number: "))
   num2 = int(input("Second Number: "))
  elif calcinput == "2":  
   num1 = int(input("First Number: "))
   num2 = int(input("Second Number: "))  
  elif calcinput == "3":  
   num1 = int(input("First Number: "))
   num2 = int(input("Second Number: "))
  elif calcinput == "4":  
   num1 = int(input("First Number: "))
   num2 = int(input("Second Number: "))
  elif calcinput == "5":
    main.start()
  cont = input("Would you like to continue (Yes/No): ")
  if cont == "Yes":
      continue
  elif cont == "No":
       main.start()
  else:
      input("Invalid input. Try again (Yes/No): ")
    
  if calcinput == "1":
        print(num1 + num2)
  elif calcinput == "2":
        print(num1 - num2)
  elif calcinput == "3":
        print(num1 * num2)
  elif calcinput == "4":
        print(num1 / num2)

  else:
        print("Invalid Input!")

textchecker.py

import main


def textchub():
 while True:

    print("Text Checkers:")
    print("1) LowerCase")
    print("2) UpperCase")
    print("3) Alphabetical")
    print("4) Numerical")
    print("5) AlNum (Alphabetical/Numerical")
    print("6) Back to hub")
    ci = input("Choose a checker (Number): ")

    if ci == "1" and "2" and "3" and "4" and "5":
        cia = input("Paste Text: ")

    elif ci == "6":
        main.start()
    
    if ci == "1":
        if cia.islower() == False:
         print("Your text is not lowercase.")
        elif cia.islower() == True:
         print("Your text is lowercase.")

    elif ci == "2":
        if cia.isupper() == False:
            print("Your text is not uppercase")
        if cia.isupper() == True:
            print("Your text is uppercase.")

    elif ci == "3":
        if cia.isalpha() == False:
            print("Your text is not only alphabetical")
        if cia.isalpha() == True:
            print("Your text is only alphabetical.")
    
    elif ci == "4":
        if cia.isnumeric() == False:
            print("Your text is not only numeric")
        if cia.isnumeric() == True:
            print("Your text is only numeric.")

    elif ci == "5":
        if cia.isalnum() == False:
            print("Your text is not only AlphabeticalNumerical")
        if cia.isalnum() == True:
            print("Your text is only AlphabeticalNumerical.")

    tcc = input("Would you like to continue Yes/No? ")
    
    if tcc == "Yes":
     continue

    elif tcc == "No":
     main.start

texteditor.py

import main

def texthub():
 while True:
    print("Editors:")
    print("1) UpperCase Text (Every letter will be uppercase)")
    print("2) LowerCase Text (Every letter will be lowercase)")
    print("3) UpperCase Starting Letter (Every starting letter of every word will be uppercase)")
    print("4) Back To Hub")
    te = input("Select editor 1, 2, 3 or 4: ")
    if te == "1":
        t1 = str(input("Paste Text: "))
    elif te == "2":
        t1 = str(input("Paste Text: "))
    elif te == "3":
        t1 = str(input("Paste Text: "))
    elif te == "4":
        main.start()
    else:
        print("Invalid Input")
    
    if te == "1":
        print()
        print("Here Is Your Text In UpperCase: " + t1.upper())
    elif te == "2":
        print()
        print("Here Is Your Text In LowerCase: " + t1.lower())
    elif te == "3":
        print()
        print("Here Is Your Text In Title Form: " + t1.title())

    if te == "1":
     tec = input("Would you like to edit another text Yes/No? ")
    if te == "2":
     tec = input("Would you like to edit another text Yes/No? ")
    if te == "3":
     tec = input("Would you like to edit another text Yes/No? ")
    if tec == "Yes":
        continue
    elif tec == "No":
        main.start()

error/traceback:

Traceback (most recent call last):
  File "f:\Coding\Microsoft VS Code\CODES\Projects\Multi Tool\main.py", line 1, in <module>
    import calculator
  File "f:\Coding\Microsoft VS Code\CODES\Projects\Multi Tool\calculator.py", line 1, in <module>
    import main
  File "f:\Coding\Microsoft VS Code\CODES\Projects\Multi Tool\main.py", line 18, in <module>
    start()
  File "f:\Coding\Microsoft VS Code\CODES\Projects\Multi Tool\main.py", line 12, in start
    calculator.select()
AttributeError: partially initialized module 'calculator' has no attribute 'select' (most likely due to a circular import)

您的代码几乎是正确的。 __name__ 是你的朋友。

根据Official Python3 Documentation,存在一些“内置相关只读属性”。

您会注意到,如果您对 main.py 进行小幅修改,它会正常工作(见下文)。

import calculator
import texteditor
import textchecker

def start():
 print("Operations:")
 print("1) Calculator")
 print("2) Text Editor")
 print("3) Text Checker")
 choice1 = input("Select operation: ")
 if choice1 == "1":
     calculator.select()
 elif choice1 == "2":
     texteditor.texthub()
 elif choice1 == "3":
     textchecker.textchub

if __name__=='__main__':     
 # protect the "start()" with a __name__==__main__ guard
 start()

为简单起见,请记住:导入模块时,__name_____main___ 不同,因此不会执行这些行。

唯一一次 __name__==__main__ 产生 true 是当你从命令行 运行 自己时,即 >python3 main.py.

编辑:如另一个答案中所述,这不能解决循环导入问题。这是架构方面的有效观察,但请记住 Python 是一种非常灵活和解释性的语言,没有任何正式阻止您从 main.py 导入的内容。请注意通过内置属性 (__name__) 辨别“谁在导入你”的力量,并继续获取此问题范围之外的设计最佳实践。

您正在从 calculator.py、textchecker.py 和 texteditor.py 导入 main。同时还在 main 中导入那些。所以,当它试图解决这个问题时:

in main.py:
--> load in calculator
in calculator.py
--> load in main
in main.py:
--> load in calculator
... you see what goes wrong.

您的问题有 2 个解决方案:

  1. 我认为最好的解决方案
    在除 main 之外的所有其他文件中,将 main.start() 替换为 return None。我认为您的程序将按您的预期继续工作。并从这些文件中删除导入。
  2. 如果你想让你的程序运行像现在一样精确(不是很好的做法)
    切换导入定义和函数的顺序
def start(): ... 
# ecapsulate everything in a while here, and add an else: return None 
# every other input when choosing will break the loop and stop the program

import ...

然后在其余文件中:

from main import start

但我不认为这是理想的,因为您将嵌套函数框架,这会占用大量内存。

PS:也看看添加其他答案并添加 __name__ == "__main__"

一般建议:从 main 导入通常不是一个好主意。尝试设计计算器,...请记住,您不知道它将如何使用,只是最基本的功能(在这种情况下会提示一些计算问题)。那么在主要情况下,您可以在不依赖用例的情况下调用这些函数。假设您想要计算器的第二个接口,..那您打算怎么办?