#python #class #oop
#python #класс #ооп
Вопрос:
Я новичок в python. Я пишу тестовое приложение для другого аналитического инструмента. Этот инструмент выводит различные типы файлов, которые мы называем «артефактами». Каждый тип артефакта представляет собой некоторый файл данных.
Я создал родительский класс с именем Artifact, который имеет функции load() и compare() .
Итак, допустим, у меня есть два типа артефактов: куб и отчет. У каждого есть связанный класс куба и отчета с функциями, которые знают, как считывать соответствующие данные и сравнивать их друг с другом (один куб с другим кубом и один отчет с другим отчетом).
Реализация этого мне понятна.
Вот мой вопрос: я бы хотел, чтобы пользователи могли реализовывать свои собственные новые артефакты, о которых я сейчас не знаю, и иметь возможность загружать их через конфигурационный файл.
Новым дочерним элементом артефакта должен быть файл .py, но я бы не хотел изменять код основного тестового приложения. Поэтому я бы хотел, чтобы пользователи указывали в файле конфигурации использовать существующие артефакты куба и отчета, а также их вновь определенный артефакт. Для всех артефактов выполните load() и compare()
Могу ли я сделать это без явного импорта нового класса и без указания явного вызова для него?
Могу ли я просто написать
for c in Artifact classes:
c.load()
c.compare()
? (это явно упрощено, я надеюсь, это понятно)
Комментарии:
1. Итак, по сути, вы хотите ссылаться на классы (которые наследуются от
Artifact
) на основе пользовательского ввода? Что такоеmy_class = ./CustomArtifact.py
? И ВАШ код должен был бы работать с этим классом, а не наоборот?2. Не описывайте свой код, покажите его нам!
3. Вы хотите загружать модули динамически; ознакомьтесь с
importlib
модулем.4. @CollinHeist — Да, это идея.
Ответ №1:
Самый простой способ сделать это — добавить подпакет в ваш проект, где новые процессоры артефактов регистрируются как новый файл .py. Добавьте импорт __init__.py
, и он загрузится автоматически.
myproject
__init__.py
artifacts.py
artifactsdb
__init__.py
cube.py
report.py
artifacts.py
class Artifacts:
def load(self):
pass
def compare(self):
pass
def enum_artifacts():
for art in Artifacts.__subclasses__():
art().load()
art().compare()
artifactsdb/init.py
from .cube import cube
from .report import report
artifacts/cube.py
from ..artifacts import Artifacts
class cube(Artifacts):
pass
Комментарии:
1. Хм .. хорошая идея, но, поскольку вы их написали
compare
, andload
не являются методами класса, аart
infor art in Artifacts.__subclasses__
— это класс, а не экземпляр. Просто создайтеobj = art()
и вызовите методы наobj
2. @Pynchia — Хм, OP не дает четкого определения того, что
load
иcompare
должно быть, поэтому я просто набросал что-то неопределенное. Например, как код должен выбирать, какой подкласс использовать? Какое-то правило об именах файлов? Универсальный загрузчик, который затем выбирает подтипы? Попробуйте их все, пока один не выйдет из строя? Я не знаю, поэтому просто набросал его. Я забыл вызвать__subclass__
пример. Я провел тестирование, но, похоже, пропустил несколько битов и ошибок, пока собирал их вместе.3. Спасибо вам обоим. Я думаю, что в целом понимаю это предложение, но мне нужно будет попытаться реализовать это, чтобы справиться с этим. Мой python еще недостаточно силен, чтобы просто визуализировать это. Но это очень полезное предложение.
Ответ №2:
Конфигурационный файл может быть модулем python, который импортирует новые классы артефактов. Если ваши пользователи могут писать свои собственные классы python, у них не должно возникнуть проблем с редактированием такого конфигурационного файла:
- в userconfig.py:
# import user artifact classes:
from myartifact import NewArtifact
# add user artifacts to the list "user_artifacts"
user_artifacts = [
NewArtifact
]
- в вашем основном коде:
import userconfig
for c in userconfig.user_artifacts:
# load and compare