介绍
我是大学学习编程的学生。我的课程侧重于Java,C#和C ++,因此我对OOP有一定的经验。目前,我正忙于合作社,要求是使用Python和tkinter(我正在学习这两者)来创建GUI。
我的问题专门与Python OOP和跨多个目录中的多个文件的继承有关,我根本无法弄清楚(已经3天了)
如果您不想遍历多行缩短的文件和代码示例,则可以在此处找到实际的代码:
https://github.com/bkleynhans/Landsat-Buoy-Calibration.git
然后转到页面底部以获取问题的要点。
除非您安装了ModTran(这是一种昂贵的许可软件),否则您将无法运行校准系统。但是,GUI应该可以完全正常运行,唯一的非标准要求是tkcalendar。
我做了什么
我已经研究了以下链接的线程以及其他成员所包含的链接。
ImportError: cannot import name
ImportError: Cannot import name X
以及
https://www.digitalocean.com/community/tutorials/understanding-class-inheritance-in-python-3
https://www.python-course.eu/python3_inheritance.php
https://chrisyeh96.github.io/2017/08/08/definitive-guide-python-imports.html
不幸的是,无论是因为我不够了解,还是因为我很慢,我似乎都无法将它们与我的问题联系起来。
资料夹结构
我的文件夹结构如下:
Z:.
│
│ tarca_gui
│
└───gui
│
│ __init__.py
│ tarca_gui.py
│
│
└───forms
│
│ input_notebook.py
│ status_frame.py
│ settings_frame.py
│ example_date_picker_supplied.py
│ settings_notebook.py
│ input_frame.py
│ help_menu.py
│ header_frame.py
│ progress_bar.py
│ __init__.py
│ menu_bar.py
│ example_date_picker.py
│ output_frame.py
│
└─
文件摘要
根目录中的tarca_gui只是一个bash脚本,它会更改为工作目录并执行gui
cd ~/Landsat-Buoy-Calibration/gui
python3 tarca_gui.py
将文件及其代码放在这里会很混乱,但是我将粘贴标题和结构。上面介绍部分中有一个指向该项目的GitHub链接。
必需的非标准库:
tkcalendar-https://pypi.org/project/tkcalendar/
tarca_gui.py-从linux终端启动程序,并使用tkinter构建接口。所有其他文件均基于以下结构派生
基础类
tarca_gui.py
from tkinter import *
from tkinter import messagebox
import inspect
import sys
import os
import pdb
class Tarca_Gui:
def __init__(self, master):
# Import gui paths
from forms import progress_bar
from forms import menu_bar
from forms import header_frame
from forms import input_frame
from forms import output_frame
from forms import status_frame
# Create the root Tkinter object
master.title('CIS Top Of Atmosphere Radiance Calibration System')
master.geometry('800x600')
master.resizable(False, False)
#master.configure(background = '#FFFFFF')
master.option_add('*tearOff', False)
# Create the Progressbar window - accessed via master.progressbar_window.progress_bar
progress_bar.Progress_Bar(master)
# Create the Menubar - accessed via master.menu_bar
menu_bar.Menu_Bar(master)
# Create the Header - accessed via master.header_frame
header_frame.Header_Frame(master)
# Create the Input Frame - accessed via master.
input_frame.Input_Frame(master)
# Create the Input Frame - accessed via master.
output_frame.Output_Frame(master)
# Create the Input Frame - accessed via master.
status_frame.Status_Frame(master)
# Calculate fully qualified path to location of program execution
def get_module_path():
filename = inspect.getfile(inspect.currentframe())
path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
return path, filename
# Set environment variables to locate current execution path
def set_path_variables():
path, filename = get_module_path()
# find the Calibration program path
path_index = path.rfind('/')
# append gui paths
sys.path.append(path[:path_index])
sys.path.append(path)
sys.path.append(path + "/forms")
def on_closing(root):
if messagebox.askyesno("Quit", "Do you really wish to quit?"):
root.destroy()
def main():
set_path_variables()
root = Tk()
root.protocol("WM_DELETE_WINDOW", lambda: on_closing(root))
tarca_gui = Tarca_Gui(root)
root.mainloop()
if __name__ == "__main__": main()
progress_bar,menu_bar,header_frame,input_frame,output_frame和状态帧均源自(扩展)targa_gui
派生类的摘要
progress_bar.py扩展了tarca_gui.py
from tkinter import *
from tkinter import ttk
import tarca_gui
class Progress_Bar(tarca_gui.Tarca_Gui):
def __init__(self, master):
menu_bar.py扩展了tarca_gui.py
from tkinter import *
from tkinter import ttk
import tarca_gui
import help_menu
from gui.forms import settings_frame
class Menu_Bar(tarca_gui.Tarca_Gui):
def __init__(self, master):
header_frame.py扩展了tarca_gui.py
from tkinter import *
from tkinter import ttk
from forms import input_frame
class Header_Frame(input_frame.Input_Frame):
def __init__(self, master):
input_frame.py扩展了tarca_gui.py
from tkinter import *
from tkinter import ttk
import tarca_gui
from gui.forms import input_notebook
class Input_Frame(tarca_gui.Tarca_Gui):
def __init__(self, master):
output_frame.py扩展了tarca_gui.py
from tkinter import *
from tkinter import ttk
import tarca_gui
class Output_Frame(tarca_gui.Tarca_Gui):
def __init__(self, master):
status_frame.py扩展了tarca_gui.py
from tkinter import *
from tkinter import ttk
import tarca_gui
class Status_Frame(tarca_gui.Tarca_Gui):
def __init__(self, master):
其余类:help_menu,settings_frame,settings_notebook,header_frame和input_notebook源自(扩展)其他类
header_frame.py扩展了input_frame.py
from tkinter import *
from tkinter import ttk
from forms import input_frame.py
import pdb
class Header_Frame(input_frame.Input_Frame):
def __init__(self, master):
input_notebook.py扩展了input_frame.py
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from gui.forms import input_frame
from tkcalendar import Calendar, DateEntry
from datetime import date
class Input_Notebook(input_frame.Input_Frame):
def __init__(self, master):
help_menu.py扩展了menu_bar.py
from tkinter import *
from tkinter import ttk
import time
import threading
import menu_bar
class Help_Menu(menu_bar.Menu_Bar):
def __init__(self, master):
settings_frame.py扩展了settings_notebook.py
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from gui.forms import menu_bar
from gui.forms import settings_notebook
class Settings_Frame(menu_bar.Menu_Bar):
def __init__(self, master):
settings_notebook.py扩展了settings_frame.py
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from gui.forms import settings_frame
class Settings_Notebook(settings_frame.Settings_Frame):
def __init__(self, master):
问题与疑问
首先,通过您可以在基类中查看的功能启动gui时,会更新PYTHONPATH。
其次,我了解到,目前这些类并不是全部以相同的方式导入,在寻找问题的过程中它们已经并且已经更改,并且在解决问题后将对其进行标准化。
问题
在尝试将Settings_Frame导入settings_notebook.py之前,整个GUI都可以正常工作
收到错误
% ./tarca_gui
Traceback (most recent call last):
File "tarca_gui.py", line 104, in <module>
if __name__ == "__main__": main()
File "tarca_gui.py", line 100, in main
tarca_gui = Tarca_Gui(root)
File "tarca_gui.py", line 31, in __init__
from forms import menu_bar
File "/cis/otherstu/bxk8027/Landsat-Buoy-Calibration/gui/forms/menu_bar.py", line 20, in <module>
import help_menu
File "/cis/otherstu/bxk8027/Landsat-Buoy-Calibration/gui/forms/help_menu.py", line 21, in <module>
import menu_bar
File "/cis/otherstu/bxk8027/Landsat-Buoy-Calibration/gui/forms/menu_bar.py", line 21, in <module>
from gui.forms import settings_frame
File "/cis/otherstu/bxk8027/Landsat-Buoy-Calibration/gui/forms/settings_frame.py", line 21, in <module>
from gui.forms import settings_notebook
File "/cis/otherstu/bxk8027/Landsat-Buoy-Calibration/gui/forms/settings_notebook.py", line 25, in <module>
class Settings_Notebook(settings_frame.Settings_Frame):
AttributeError: module 'gui.forms.settings_frame' has no attribute 'Settings_Frame'
发现
我相信这是由于循环导入引起的,因为settings_frame导入settings_notebook,反之亦然。
混乱
我了解应尽可能避免使用循环引用,但是,按照我目前了解Python OOP的方式,我需要将settings_notebook导入settings_frame以进行构造,但同时我也需要将settings_frame导入settings_notebook以便对其进行扩展(settings_notebook应该是settings_frame的子级)
问题
我不知道我在做什么错。
它与导入相关,还是我构建类的方式?
如果我对类结构(带有导入项)的理解不正确,请解释我做错了什么,以便我可以学习而不会再犯同样的错误。
任何其他有关的建议将不胜感激。
结论
如果您已经做到了这一点,首先,非常感谢。
如前所述,我在大学里同时学习C ++,C#,Java,Python,HTML,CSS,JavaScript,PHP,SQL,Unity和Unreal引擎(有时我对它们之间的概念感到困惑),因此有关的任何建议我的代码的任何部分将不胜感激。
最佳答案
这段代码确实很难解开,但是我认为问题的根源在于您试图使用继承在类之间共享数据。那不是继承的目的。
当B从A继承时,并不意味着B共享A的数据,这意味着B是A的精确副本,但具有一些增强功能。实际上,您有两个A-原始A和一个具有某些其他功能的新A。
例如,您有一个名为Tarca_Gui
的类。这似乎是主要课程。它具有状态栏,菜单栏等。当您从Tarca_Gui
继承时,该新类还具有状态栏,菜单栏等。这两个类不共享任何数据。
代替继承,您需要使用组合。区别在于,继承Menu_Bar
是Tarca_Gui
,但是您真正想要的是Tarca_Gui
具有Menu_Bar
。
因为您没有提供minimal reproducible example,所以我无法修复您的代码,但是您需要做的第一件事是从每个类的定义中删除Tarca_Gui
。然后,将Tarca_Gui
的实例传递给其他各种对象。
换一种说法:
class Tarca_Gui():
def __init__(self, master):
...
self.menu_bar = Menu_Bar(self)
self.header_frame.Header_Frame(self)
self.input_frame = Input_Frame(self)
self.output_frame = Output_Frame(self)
self.status_frame = Status_Frame(self)
...
class Menu_Bar():
def __init__(self, tarca_gui):
self.tarca_gui = tarca_gui
...
class Progress_Bar():
def __init__(self, tarca_gui):
self.tarca_gui = tarca_gui
...
class Header_Frame():
def __init__(self, tarca_gui):
self.tarca_gui = tarca_gui
...
... and so on ...
然后,在每个这些对象中,如果它们需要由
Tarca_Gui
管理的内容,则可以使用self.tarca_gui
进行引用。例如,如果您需要访问master
小部件,则可以使用self.tarca_gui.master
。同样,
Menu_Bar
或Input_Frame
或Settings_Frame
都不应继承任何内容。有关继承与组合的更多信息,请参见Difference between Inheritance and Composition
关于python - 在多个文件和目录中使用Python OOP时,有助于理解分层继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56400317/