【问题标题】:Instantiating a python class from a module by full name通过全名从模块实例化python类
【发布时间】:2019-12-08 10:26:02
【问题描述】:

我需要创建一个 python 类的实例并将其存储在 C# 变量中。进程的输入数据是完整的模块名称和类名称。我正在尝试使用以下方法:

// 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 类):

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 标记为红色的模块)@987654321 @

有没有合适的方法让我通过全名加载模块,而不是遍历范围来查找我需要的类?

【问题讨论】:

    标签: c# .net module ironpython python-module


    【解决方案1】:

    我已经设法编写了一个扩展类,它可以提供与常规 python 的“从 X 导入 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);
    

    【讨论】:

      猜你喜欢
      • 2014-11-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-18
      • 2016-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多