【问题标题】:Returning arguments in SWIG/Python在 SWIG/Python 中返回参数
【发布时间】:2023-03-16 11:52:01
【问题描述】:

根据 Swig 文档和 @Flexo 在 SWIG in typemap works, but argout does not 的精彩解释,argout 类型映射将引用参数转换为 Python 中的返回值。

我有一个场景,我传递了一个dict,然后将其转换为typemap(in) 中的unordered_map,然后将其填充到C++ 库中。单步执行代码,我可以看到映射从 C++ 返回后发生了变化,所以我想知道为什么不能将 unordered_map 原位转换为已传递的 dict。还是现在有可能而我只是忽略了一些东西?

谢谢!

【问题讨论】:

    标签: python swig typemaps


    【解决方案1】:

    我对你到底在问什么有点困惑,但我的理解是:

    • 您有一个“in”类型映射,可以将 Python dict 转换为 C++ unordered_map 以获取某些函数参数。
    • 该函数然后修改unordered_map
    • 函数完成后,您希望将 Python dict 更新为当前的 unordered_map,但在此步骤中遇到了问题。
    • 既然您知道如何将dict 转换为unordered_map,我假设您基本上知道如何使用Python C-API 将unordered_map 转换回dict,但不知何故不确定放置代码的 SWIG 类型映射。

    因此,在这些假设下,我会尽力提供帮助:

    • “argout 类型映射将引用参数转换为 Python 中的返回值”。并非如此,尽管它主要用于此目的。 "argout" typemap 只是提供代码来处理一些函数参数(内部称为$1),这些函数参数在调用 C++ 函数之后插入到包装器代码中。将此与“in”类型映射进行比较,该类型映射提供代码以将提供的 Python 参数 $input 转换为 C++ 参数 $1,这显然是在调用 C++ 函数之前插入到包装代码中

    • 原始传递的 Python dict 可以在“argout”类型映射中引用为 $input,修改后的 unordered_map$1(请参阅上面链接的 SWIG 文档)。

    • 因此,您需要做的就是为与您已有的“in”类型映射相同的参数签名编写一个“argout”类型映射,然后插入代码(使用 Python C-API)进行更新Python dict ($input) 的内容反映了unordered_map ($1) 的内容。

    • 请注意,这与“argout”类型映射的经典使用不同,后者通常会将 $1 转换回新的 Python dict 并将其附加到 Python 返回对象,您可以参考发给$result

    我希望这会有所帮助。如果您在某个时间点仍然卡住,请编辑您的问题以明确您在哪个时间点遇到了问题。

    【讨论】:

    • 非常感谢,m7thon!倒数第二颗子弹是我遗漏的那块。从提供的 Swig 示例中,我认为您的最后一个项目符号是传回数据的唯一可能方式(通过使用返回值)。
    • @wr m7thon 对这个答案很满意。您必须注意并下定决心的一件事是 Python 开发人员(即绑定的用户)期望的行为。理想情况下,您希望采取最不混乱的路线。对我来说,通常在 Python 中是为了使输入参数不可变,因为与 C++ 不同,您不能通过 const/not reference 轻松推断(例如)行为将是什么。这几乎只剩下返回一个值而不是一个选项,这通常是有意义的,因为在精心设计的接口中,return val 没有被用来指示成功/失败。
    【解决方案2】:

    我很清楚用户已经解决了他的问题,但这里有一个解决方案。可能会引入一些输入验证以避免输入字典的非字符串值。

    头文件

    // File: test.h
    #pragma once
    
    #include <iostream>
    #include <string>
    #include <unordered_map>
    
    void method(std::unordered_map<std::string, std::string>* inout) {
    
      for( const auto& n : (*inout) ) {
        std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n";
      }
    
      (*inout)["BLACK"] = "#000000";
    };
    

    接口文件

    // File : dictmap.i
    %module dictmap
    
    %{
      #include "test.h"
    %}
    
    %include "typemaps.i"
    
    %typemap(in) std::unordered_map<std::string, std::string>* (std::unordered_map<std::string, std::string> temp) {
    
      PyObject *key, *value;
      Py_ssize_t pos = 0;
    
      $1 = &temp;
    
      temp = std::unordered_map<std::string, std::string>();
      while (PyDict_Next($input, &pos, &key, &value)) {
        (*$1)[PyString_AsString(key)] = std::string(PyString_AsString(value));
      }
    }
    
    %typemap(argout) std::unordered_map<std::string, std::string>* {
     $result = PyDict_New();
     for( const auto& n : *$1) {
       PyDict_SetItemString($result, n.first.c_str(),
                PyString_FromString(n.second.c_str()));
     }
    }
    %include "test.h"
    

    测试

    import dictmap
    out = dictmap.method({'WHITE' : '#FFFFFF'})
    

    输出是更新的字典

    In[2]: out
    Out[3] : {'BLACK': '#000000', 'WHITE': '#FFFFFF'}
    

    【讨论】:

    • 请注意,在使用 python3 时,您可能会发现PyString_AsString 一直返回一个空指针。您可能需要使用PyUnicode_AsUTF8 代替PyString_AsString
    猜你喜欢
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多