我正在创建一个Python模块,将不同语言/框架提供的API映射到Python.理想情况下,我希望将其作为单个根包提供,该包公开辅助方法,并将该其他框架中的所有命名空间映射到Python包/模块.为方便起见,我们以CLR为例:
import clr.System.Data
import clr.System.Windows.Forms
Run Code Online (Sandbox Code Playgroud)
这clr是一个神奇的顶层包,它暴露了CLR命名空间System.Data和System.Windows.Forms子包/子模块(据我所知,一个包只是一个带有子模块/包的模块;它在其中有其他类型的成员仍然有效).
我已经阅读了PEP-302并编写了一个简单的原型程序,通过安装自定义meta_path钩子实现了类似的效果.该clr模块本身是一个适当的Python模块其中,导入时,套__path__ = [](使其成为一个包,以便import甚至试图为子模块在所有查找),并注册该钩.钩子本身拦截包的全名开始的任何包加载,使用"clr."动态创建新模块imp.new_module(),将其注册sys.modules,并使用pixie dust和rainbows用原始API中的类和方法填充它.这是代码:
import sys
import imp
class MyLoader:
def load_module(self, fullname):
try:
return sys.modules[fullname]
except KeyError:
pass
print("--- load ---")
print(fullname)
m = imp.new_module(fullname)
m.__file__ = "clr:" + fullname
m.__path__ = []
m.__loader__ = self
m.speak = lambda: print("I'm " + fullname)
sys.modules.setdefault(fullname, m)
return m
class MyFinder:
def …Run Code Online (Sandbox Code Playgroud) 我在哪里可以找到PEP 302中描述的"新导入挂钩"的示例实现?
我想以最顺利兼容的方式实现自定义查找器和加载器.换句话说,实现应该在python 2.x和3.x中工作.
使用不推荐使用的模块imp,我可以编写一个自定义导入钩子,在Python导入/执行之前动态修改模块的源代码.给定源代码作为source下面命名的字符串,创建模块所需的基本代码如下:
module = imp.new_module(name)
sys.modules[name] = module
exec(source, module.__dict__)
Run Code Online (Sandbox Code Playgroud)
由于imp被弃用,我想做类似的事情importlib.[编辑:还有其他imp方法需要替换来构建自定义导入钩子 - 所以我要找的答案不仅仅是替换上面的代码.]
但是,我还没弄清楚如何做到这一点.将导入库文件有一个功能,从"规范"创建模块,其中,据我所知,是包括自己的装填重新定义它们,以便能够从字符串创建模块没有明显的方式对象.
我创建了一个最小的例子来证明这一点; 有关详细信息,请参阅自述文件.
我正在我的 python 代码中创建一个运行时模块,类似于
string_code = """
import existing_module
a = "my_string"
existing_module.register(a)
"""
mod = ModuleType("mymodule")
sys.modules["mymodule"] = mod
exec(string_code, mod.__dict__)
Run Code Online (Sandbox Code Playgroud)
在现有的模块中,我有代码检查调用者是否是一个模块
def register(a: str):
caller = inspect.stack()[1]
caller_module = inspect.getmodule(caller[0])
assert caller_module is not None
Run Code Online (Sandbox Code Playgroud)
由于我从运行时模块调用现有模块,因此我预计 caller_module 不是 None 。然而,我确实符合这个断言。不知道为什么。
有人可以帮忙吗?
几个小时后,我发现了应用程序中的错误原因.我的应用程序的源代码结构如下:
main/
__init__.py
folderA/
__init__.py
fileA.py
fileB.py
Run Code Online (Sandbox Code Playgroud)
真的,还有大约50个文件.但那不是重点.在main/__init__.py,我有这个代码:from folderA.fileA import *
在folderA/__init__.py我有这个代码:
sys.path.append(pathToFolderA)
Run Code Online (Sandbox Code Playgroud)
在folderA/fileB.py我有这个代码:
from fileA import *
Run Code Online (Sandbox Code Playgroud)
问题是fileA被导入两次.但是,我只想导入一次.
解决这个问题(我ATLEAST)最显而易见的方法是改变从某些路径path到folderA.path
但我觉得Python首先应该没有这个错误.还有哪些其他解决方法不需要每个文件知道它的绝对位置?