[英]Dynamic importing of registered subclasses stored in various modules
請考慮以下派生腳本結構:
import abc
class BaseMeta(abc.ABCMeta):
__registry__ = {}
def __init__(cls, name, bases, namespace):
if bases:
BaseMeta.__registry__.update({ cls.__name__: cls })
# other modifications of namespaces
super().__init__(name, bases, namespace)
class Base(metaclass = BaseMeta):
pass # Various abstract properties and methods
class Derived0(Base): pass
class Derived1(Base): pass
# ...
class DerivedN(Base): pass
上面的代碼改編自這個答案; 我不能使用__subclass__
因為我需要跟蹤直接和間接子類。 雖然我現在可以繞過這個要求,但為了向前兼容,我想保留它。
我想使用Base.__registry__
中的__getattr__()
動態分派這些子類。 因為這些子類可以增長到幾百個 SLOC,並且可以依賴幾十個文件,主要是 SQL 模式,所以我想將它們組織成包,例如
__main__.py
gui # Irrelevant package
db # Irrelevant package
# [...] Other irrelevant packages
relevant
__init__.py # Contains Base
derived0
__init__.py # Contains Derived0 and related machinery
derived1
__init__.py # Contains Derived1 and relevant machinery and imports module-xxx.py
module-xxx.py
schema_main.sql
copy-query-.xxx.sql
# [...]
# [...]
問題是我們也需要動態導入。 我知道的唯一解決方案是使用pkgutil
遍歷包並exec(compile())
緩沖區。 然而,這會弄亂命名空間。
我相信這個問題有點類似於這個問題,它看起來像解決此類問題的代碼一樣慣用,但我不知道結果是否與從父 package 簡單導入的行為完全相同? 有誰知道如何解決這個問題?
我們非常歡迎所有幫助,對上述代碼的其他批評也是如此。 非常感謝你。
我設法使用pkgutil
、 importlib
和pathlib
解決了這個問題,如下所示:
import abc
import importlib
import pathlib
import pkgutil
class BaseMeta(abc.ABCMeta):
__registry__ = {}
def __init__(cls, name, bases, namespace):
if bases:
BaseMeta.__registry__.update({ cls.__name__: cls })
# other modifications of namespaces
super().__init__(name, bases, namespace)
class Base(metaclass = BaseMeta):
pass # Various abstract properties and methods
# Subclasses have now been moved to their respective subpackages
for parent_FF, name, _ in pkgutil.walk_packages(__path__):
importlib.machinery.SourceFileLoader(
name,
(pathlib.Path(parent_FF.path) / name / "__init__.py").as_posix()).load_module()
因為 Python 處理路徑的方式是高度非標准化的,所以我不知道有任何更優雅的解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.