【发布时间】:2019-10-17 09:53:45
【问题描述】:
简介
我是一名大学学习编程的学生。我的课程侧重于 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
│
└─
文件摘要
root 中的 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 和 status 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 引擎(有时我对它们之间的概念感到困惑),所以任何与我的代码的任何部分有关的建议将不胜感激。
【问题讨论】:
-
"我知道应该尽可能避免循环引用,但是按照我目前理解 Python OOP 的方式,我需要将 settings_notebook 导入到 settings_frame 中才能构建它,但同时我需要将 settings_frame 导入 settings_notebook 以扩展它(settings_notebook 应该是 settings_frame 的子级)”是的,这就是问题所在。解决此问题的“愚蠢”方法是将这两个模块合并为一个。这可能是一个有争议的观点,但怪物模块可能是较小的邪恶。您还可以将导入移动到底部。
-
python 类定义是动态执行的。类型在运行时解析。这就是为什么 python 在类定义中不能很好地处理循环依赖的原因。您可以将类定义视为围绕调用类对象构造函数 metaclass
type('MyClass', (object,), {'__init__': lambda self: print("I'm a MyClass instance")})()的语法糖
标签: python oop inheritance