簡體   English   中英

從boost python調用具有可變數量的輸入參數的Python函數

[英]calling a Python function with variable number of input arguments from boost python

是否可以從boost :: python內部調用具有可變數量的輸入參數的python函數:

在python中,我定義了一個函數

def py_fn1(a):
    return 2 * a

def py_fn2(a, b):
    return a+b

def call_fn_py(fn, *args):
    return fn(*args)

a = call_fn_py(py_fn1, 15)  # returns 30
b = call_fn_py(py_fn2, 10, 11)  # returns 21

根據評論給出結果。 我想使用Boost python在C ++中實現call_fn(fn,* args)。 到目前為止,我有:

using namespace boost::python;
object call_fn(object fn, tuple arg_in)
{
return fn(arg_in);
}


BOOST_PYTHON_MODULE(python_addins)
{
    using namespace boost::python;
def("call_fn", &call_fn);
}

但是然后做類似的事情:

import python_addins

d = python_addins.call_fn(py_fn1, (5,))  # returns (5,5)

這不是我所追求的。 如何編寫call_fn使其表現得像call_fn_py?

謝謝馬克

可以使用可變數量的參數來調用python函數。 有兩種方法:

  • 通過創建一組call_fn函數來模擬可變數量的參數。
  • 利用python將多個對象打包和解包到元組的能力。

對於通用C ++編程,第一種方法相當普遍。 它需要創建一組重載函數,這些重載函數根據參數的數量而有所不同: call_fn( fn )call_fn( fn, A1 )call_fn( fn, A1, ...An) 可以使用C ++ 11可變參數模板函數減少樣板代碼的數量。 但是,在定義包裝器時,必須指定模板函數的確切類型。 因此,這種方法將基於包裝了哪些模板實例而對參數的數量有所限制。

#include <boost/python.hpp>

using boost::python;
object call_fn1( object fn, object a1 )
{
  return fn( a1 );
}
object call_fn2( object fn, object a1, object a2 )
{
  return fn( a1, a2 );
}
object call_fn3( object fn, object a1, object a2, object a3 )
{
  return fn( a1, a2, a3 );
}

BOOST_PYTHON_MODULE(example)
{
  def( "call_fn", &call_fn1 );
  def( "call_fn", &call_fn2 );
  def( "call_fn", &call_fn3 );
}

這是一個演示:

>>> def py_fn1( a ): return 2 * a
... 
>>> def py_fn2( a, b ): return a + b
... 
>>> def call_fn_py( fn, *args ):
...     from example import call_fn
...     return call_fn( fn, *args )
... 
>>> call_fn_py( py_fn1, 15 ) 
30
>>> call_fn_py( py_fn2, 10, 11 )
21

第二種方法利用元組。 它要求調用者將參數打包到一個元組中,並且調用函數將參數打包。 但是,由於在python中進行元組打包和拆包更容易,因此可以在python中對example.call_fn進行修補,以便函數參數由助手函數裝飾,該函數在委派之前解壓縮參數。

在C ++中,創建一個call_fn函數,該函數接受單個boost::python::tuple參數。

#include <boost/python.hpp>

using namespace boost::python;
object call_fn( object fn, tuple args )
{
  return fn( args );
}

BOOST_PYTHON_MODULE(example)
{
  def( "call_fn", &call_fn );
}

現在,創建example_ext.py ,它將修補example.call_fn

import example

def patch_call_fn():
    # Store handle to unpatched call_fn.
    original = example.call_fn

    # Helper function to create a closure that unpacks arguments
    # before delegating to the user function.
    def unpack_args( fn ):
        def wrapper( args ):
            return fn( *args )
        return wrapper

    # The patched function that will wrap the user function.
    def call_fn( fn, *args ):
        return original( unpack_args( fn ), args )

    return call_fn

# Patch example.
example.call_fn = call_fn = patch_call_fn()

可以使用相同的演示,所需的唯一更改是需要導入example_ext而不是example

>>> def py_fn1( a ): return 2 * a
... 
>>> def py_fn2( a, b ): return a + b
... 
>>> def call_fn_py( fn, *args ):
...     from example_ext import call_fn
...     return call_fn( fn, *args )
... 
>>> call_fn_py( py_fn1, 15 ) 
30
>>> call_fn_py( py_fn2, 10, 11 )
21

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM