我目前正在为Python 2.7开发一组抽象模块,我将以python软件包的形式提供:
class MyView extends Polymer.Element{
static get is() {return 'my-view';}
static get properties() {
return{
data:{
type: String,
value: 'default',
observer: 'dataChanged',
},
};
}
storeData() {
this.data = 'stored';
}
dataChanged(data, oldData) {
console.log('dataChanged:', data, oldData);
// TODO: Skip default dataChanged when data is stored.
}
}
然后,将在完全不同的一组软件包中实现这些模块:
myabstractpkg
- abstract
- core
- logging
- ...
- nodes
- ...
但是,在运行时,我希望能够始终在使用已实现模块的工具中进行这样的导入:
myimppkg
- implementation
- core
- logging
- ...
- nodes
- ...
通过这种方式,开发人员始终从“虚拟” api模块导入,然后由该模块确定实际指向导入程序的位置。
我知道我可以通过修改模块字典将其合并到一起:
from myabstractpkg.api import nodes
from myabstractpkg.api.core.logging import Logger
或者为from myimppkg import implementation
sys.modules["myabstractpkg.api"] = implementation
中__init__.py
中的所有内容进行巧妙的导入,但这对我来说有点脆弱。
我想知道你们是否对实现此目标的最佳方法有一些建议。在整个重新映射模块方面,我可能会走得很糟,因此,如果你们有任何更智能,更Python化的解决方案,那么对于我的API抽象,实现,使用方法,我希望能听到它们。
答案 0 :(得分:1)
我相信,最好利用entry_points
中的setuptools
capabilities为您服务。因此,在您的一种具体实现的setup.py中,您将像这样定义entry_points
:
setup(
name="concrete_extension"
entry_points={
"abstract_pkg_extensions": [
"concrete = concrete_extension"
]
}
}
然后,您可以在抽象包中包含一个扩展模块,其功能如下:
import pkg_resources
import os
import sys
from . import default
extensions = { "default": default }
extensions.update({e.name: e.load() for e in
pkg_resources.iter_entry_points("my_pkg_extensions")})
current_implementation_name = None
current_implementation = None
def set_implementation(name):
global current_implementation_name, current_implementation
try:
current_implementation = extensions[name]
current_implementation_name = name
# allow imports like from foo.current_implementation.bar import baz
sys.modules["{}.current_implementation".format(__name__)] = current_implementation
# here is where you would do any additional stuff
# -- e.g. --
# from . import logger
# logger.Logger = current_implementation.Logger
except KeyError:
raise NotImplementedError("No implementation for: {}".format(name))
set_implementation(os.environ.get("CURRENT_IMPLEMENTATION_NAME", "default"))
然后,您可以使用ext.current_implementation
访问当前实现,并在导入之前在程序环境中设置实现,或者可以在导入任何子模块之前在代码中显式调用set_implementation
使用ext.current_implementation
。
有关sys.modules
条目及其详细工作方式的更多信息,请参见this question。