Обзор
Чтобы решить эту проблему, нужно, чтобы все мои страницы наследовали от базового класса, чтобы я мог использовать функцию __ подклассов __ , чтобы получить список всех подклассов за один раз они были импортированы. Для их импорта я бы использовал python glob модуль для поиска файлов и importlib модуль для импорта файлов по их путям.
Пример структуры файла
Например, давайте начнем с этой простой структуры папок:
.
├── main.py
└── pages
├── PageOne.py
├── PageTwo.py
├── __init__.py
└── basepage.py
__ init __. Py пусто, но позволяет нам рассматривать pages
как модуль.
basepage.py определяет класс BasePage
, от которого наследуются все другие страницы. Это не должно быть много, так как каждая страница будет отвечать за все внутри страницы. Это может выглядеть примерно так:
import tkinter as tk
class BasePage(tk.Frame):
def __init__(self, master, controller):
self.master = master
self.controller = controller
super().__init__(master)
PageOne.py и PageTwo.py содержат страницы. У них похожая структура. Например, PageOne.py может выглядеть примерно так:
import tkinter as tk
from .basepage import BasePage
class PageOne(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label = tk.Label(self, text="This is page one")
label.pack(padx=20, pady=20)
Страница два идентична, за исключением того, что в очевидных местах написано «два» вместо «один». Обратите внимание, как эта страница наследуется от BasePage
. Это важно, как вы увидите через минуту.
Получение списка файлов для импорта
Вы можете использовать модуль glob
, чтобы получить список всех файлов в " страниц "подкаталога. Это будет выглядеть примерно так:
import glob
for filename in glob.glob("./pages/*.py"):
...
Если в вашей фактической папке есть файлы, которые являются страницами, а файлы - нет, вы можете использовать соглашение об именах, чтобы импортировать только файлы подкачки. Например, вы можете изменить шаблон на ".pages/Page*.py"
.
Импорт файла по имени файла
Python importlib Модуль имеет функции, которые позволяют нам импортировать файлы по имени файла.
Например, учитывая имя файла в filename
, мы можем импортировать этот файл следующим образом:
import importlib.util
from pathlib import Path
path = Path(filename)
module_name = f"pages.{path.stem}"
spec = importlib.util.spec_from_file_location(module_name, path)
spec.loader.exec_module(module)
Если мы передадим что-то вроде ./pages/PageOne.py
, он загрузит модуль под имя pages.PageOne
.
Получение классов страниц
После того, как мы импортировали одну или несколько страниц, здесь мы используем класс BasePage
. Помните, как каждая страница наследуется от этого класса? Мы можем использовать метод подклассов __ подклассов __ , чтобы получить список всех подклассов.
Собрав все это вместе, вот функция, которая импортирует все файлы, соответствующие "Page * .py" в подпапке "pages", а затем возвращает классы:
def get_pages(self):
for filename in glob.glob("./pages/*.py"):
path = Path(filename)
module_name = f"pages.{path.stem}"
print(f"module name: {module_name}")
spec = importlib.util.spec_from_file_location(module_name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return BasePage.__subclasses__()
Создание экземпляров страницы
На данный момент создание экземпляров страницы довольно просто. Ваша основная программа может сделать что-то вроде этого:
self.frames = {}
for page_class in self.get_pages():
page = page_class(parent=page_container, controller=self)
page_name = page_class.__name__
self.frames[page_name] = page
page.grid(row=0, column=0, sticky="nsew")