簡體   English   中英

動態導入存儲在各個模塊中的已注冊子類

[英]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 簡單導入的行為完全相同 有誰知道如何解決這個問題?

我們非常歡迎所有幫助,對上述代碼的其他批評也是如此。 非常感謝你。

我設法使用pkgutilimportlibpathlib解決了這個問題,如下所示:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM