通过全名从模块实例化 python class
Instantiating a python class from a module by full name
我需要创建 python class 的实例并将其存储在 C# 变量中。该过程的输入数据是完整的模块名称和 class 名称。我正在尝试使用以下方法:
// Here's a sample input:
var moduleName = "sp.content.abilities.torpedo"
var className = "AbilityTorpedo"
// Here's my module loading and class instaitiation
var moduleScope = ScriptEngine.ImportModule(moduleName);
var scriptClass = moduleScope.GetVariable(className);
return ScriptEngine.Operations.CreateInstance(scriptClass);
我的文件夹结构如下所示,"Scripts" 目录被添加为 IronPython 的搜索路径之一(torpedo.py
确实包含 AbilityTorpedo
class) :
Scripts
│ .editorconfig
│ __main__.py
│
└───sp
│ __init__.py
│
└───content
│ __init__.py
│
└───abilities
torpedo.py
__init__.py
当 运行 列出的实例化方法时,moduleScope.GetVariable(className);
行失败并出现以下异常:
'ObjectDictionaryExpando' object has no attribute 'AbilityTorpedo'
调试时,我注意到 ImportModule 操作返回了从名称的第一部分加载的模块,同时还加载了整个模块层次结构(例如,标记为 content
的模块红色)
有没有合适的方法让我通过全名加载模块,而不是遍历范围以找到我需要的 class?
我已经设法编写了一个扩展 class,它将提供与常规 python 的 "from X import Y" 类似的功能。最后我不得不使用默认的 ImportModule 来导入模块层次结构的最根并向下遍历结构以找到必要的模块:
private static PythonModule TraverseDown(PythonModule module, string moduleName)
{
return (PythonModule) module.Get__dict__()[moduleName];
}
private static PythonModule TraverseToTarget(ScriptScope scope, string moduleName)
{
// The root of the module was already imported by the engine's import module call.
var moduleNameParts = moduleName.Split('.').Skip(count: 1).ToList();
var rootModule = scope.GetVariable<PythonModule>(moduleNameParts.First());
return moduleNameParts.Skip(count: 1).Aggregate(rootModule, TraverseDown);
}
public static dynamic ImportFromModule(this ScriptEngine engine, string moduleName, string targetImport)
{
var rootModuleScope = engine.ImportModule(moduleName);
var targetModule = TraverseToTarget(rootModuleScope, moduleName);
return targetModule.Get__dict__()[targetImport];
}
以下是应该如何使用此扩展程序:
// Here's a sample input:
var moduleName = "sp.content.abilities.torpedo"
var className = "AbilityTorpedo"
// Here's my module loading and class instaitiation
var moduleScope = ScriptEngine.ImportFromModule(moduleName, className);
return ScriptEngine.Operations.CreateInstance(scriptClass);
我需要创建 python class 的实例并将其存储在 C# 变量中。该过程的输入数据是完整的模块名称和 class 名称。我正在尝试使用以下方法:
// Here's a sample input:
var moduleName = "sp.content.abilities.torpedo"
var className = "AbilityTorpedo"
// Here's my module loading and class instaitiation
var moduleScope = ScriptEngine.ImportModule(moduleName);
var scriptClass = moduleScope.GetVariable(className);
return ScriptEngine.Operations.CreateInstance(scriptClass);
我的文件夹结构如下所示,"Scripts" 目录被添加为 IronPython 的搜索路径之一(torpedo.py
确实包含 AbilityTorpedo
class) :
Scripts
│ .editorconfig
│ __main__.py
│
└───sp
│ __init__.py
│
└───content
│ __init__.py
│
└───abilities
torpedo.py
__init__.py
当 运行 列出的实例化方法时,moduleScope.GetVariable(className);
行失败并出现以下异常:
'ObjectDictionaryExpando' object has no attribute 'AbilityTorpedo'
调试时,我注意到 ImportModule 操作返回了从名称的第一部分加载的模块,同时还加载了整个模块层次结构(例如,标记为 content
的模块红色)
有没有合适的方法让我通过全名加载模块,而不是遍历范围以找到我需要的 class?
我已经设法编写了一个扩展 class,它将提供与常规 python 的 "from X import Y" 类似的功能。最后我不得不使用默认的 ImportModule 来导入模块层次结构的最根并向下遍历结构以找到必要的模块:
private static PythonModule TraverseDown(PythonModule module, string moduleName)
{
return (PythonModule) module.Get__dict__()[moduleName];
}
private static PythonModule TraverseToTarget(ScriptScope scope, string moduleName)
{
// The root of the module was already imported by the engine's import module call.
var moduleNameParts = moduleName.Split('.').Skip(count: 1).ToList();
var rootModule = scope.GetVariable<PythonModule>(moduleNameParts.First());
return moduleNameParts.Skip(count: 1).Aggregate(rootModule, TraverseDown);
}
public static dynamic ImportFromModule(this ScriptEngine engine, string moduleName, string targetImport)
{
var rootModuleScope = engine.ImportModule(moduleName);
var targetModule = TraverseToTarget(rootModuleScope, moduleName);
return targetModule.Get__dict__()[targetImport];
}
以下是应该如何使用此扩展程序:
// Here's a sample input:
var moduleName = "sp.content.abilities.torpedo"
var className = "AbilityTorpedo"
// Here's my module loading and class instaitiation
var moduleScope = ScriptEngine.ImportFromModule(moduleName, className);
return ScriptEngine.Operations.CreateInstance(scriptClass);