我使用了一些封闭的Python模块:我可以通过API调用方法,但我无法访问实现。我知道这个模块基本上包含了一些C ++代码。
因此返回值类型之一是SwigPythonObject
。我如何在以后使用此对象,假设我没有来自模块分发者或文档的任何其他帮助?
我想以某种方式将他转换为"常规" python对象并在调试器中观察他的内部成员结构。
目前我在调试器中看到的是:
{SwigPythonObject} _<hexa number>_p_unsigned_char
答案 0 :(得分:3)
你要问的语义有点不清楚,但基本上你似乎有一个指向你希望使用的SWIG unsigned char
的指针。稍微猜测一下,你可能会遇到3个案例:
在这个特定的实例中,由于没有任何打包或对齐担心所有三种情况,我们实际上可以为所有上述情况编写一些内容,这些情况使用ctypes来读取SWIG直接引用到Python的内存,并执行SWIG代理。 (请注意,如果我们看到的类型比指向单个内置类型或数组的指针更复杂,那么我们在这里做不了多少)
首先在C - test.h中编写一些代码来练习我们正在处理的内容:
inline unsigned char *test_str() {
static unsigned char data[] = "HELLO WORLD";
return data;
}
inline unsigned char *test_byte() {
static unsigned char val = 66;
return &val;
}
接下来是一个包含此内容的最小SWIG模块:
%module test
%{
#include "test.h"
%}
%include "test.h"
我们可以在ipython中查看它,并看到它被包装(类似地) 你观察到了什么:
In [1]: import test
In [2]: test.test_byte()
Out[2]: <Swig Object of type 'unsigned char *' at 0x7fc2851cbde0>
In [3]: test.test_str()
Out[3]: <Swig Object of type 'unsigned char *' at 0x7fc2851cbe70>
In [4]: hex(int(test.test_str()))
Out[4]: '0x7f905b0e72cd'
我们在每种情况下使用的是调用int(x)
的事实,其中x是我们未知的SWIG无符号字符指针,它给出了指针作为整数指向的地址的值。将其与ctype的from_address
静态方法相结合,我们可以构造ctypes实例来访问SWIG直接知道的内存。 (注意:调用int()
返回的地址与字符串表示中的地址不匹配,因为前者是指向的数据的实际地址,但后者是SWIG 代理的地址< / em> object)
可能最简单的换行是固定长度的情况 - 我们可以使用正确大小的*
上的c_ubyte
运算符创建一个ctypes类型,然后调用from_address
。
对于以null结尾的字符串情况,我们确实有两个选择:使用libc strlen函数来计算字符串长度,然后构造匹配的ctypes类型,或者只使用Python中的char循环char直到我们命中一个空。我在下面的例子中选择了后者,因为它更简单。我可能通过使用生成器和itertools.count()
跟踪位置来过度复杂化。
最后,对于指向单字节情况的指针,我基本上重用了现有的ctypes类型,我必须创建一个1字节的数组并读取其中的值。可能有一种方法可以使用ctypes.POINTER(ctypes.c_ubyte)
然后.contents
从地址构造一个类型,但是我无法快速看到它,所以使用1字节数组技巧对我来说是微不足道的。
所有这些结合起来给我以下Python代码:
import ctypes
import test
import itertools
# Case 2
def swig_to_str(s):
base = int(s)
ty = ctypes.c_ubyte*1
def impl():
for x in itertools.count():
v=ty.from_address(base+x)[0]
if not v: return
yield chr(v)
return ''.join(impl())
# Case 1
def swig_to_byte(b):
ty=ctypes.c_ubyte*1
v=ty.from_address(int(b))
return v[0]
# Case 3
def swig_to_fixed_len(s, l):
ty=ctypes.c_ubyte*l
return ''.join(chr(x) for x in ty.from_address(int(s)))
t=test.test_str()
print(t)
print(swig_to_str(t))
print(swig_to_fixed_len(t,5))
u=test.test_byte()
print(u)
print(swig_to_byte(u))
这与Python 2.7的结果一样(应该花费很少的努力使其正确3):
swig3.0 -python -Wall test.i
gcc -std=gnu99 -Wall test_wrap.c -o _test.so -shared -I/usr/include/python2.7/ -fPIC
python run.py
<Swig Object of type 'unsigned char *' at 0x7f4a57581cf0>
HELLO WORLD
HELLO
<Swig Object of type 'unsigned char *' at 0x7f4a57581de0>
66