Golang库的Python封装实现与应用

Golang库的Python封装实现与应用 我正在尝试在我的Python项目中使用一个Go库。为此,我需要一个与参数类型等效的ctypes。例如,对于字符串变量来说相当直接,网上有很多例子。

我简单地使用(在我的Python代码中):

class GoString(Structure):
    _fields_ = [("p", c_char_p), ("n", c_longlong)]

cmd_str = b"issue"
cmd = GoString(cmd_str, len(cmd_str))

但是,对于一个类型为map[string]string的变量,我还没弄明白。有没有人已经将map[string]string变量映射到Python ctypes结构体了?

谢谢!


更多关于Golang库的Python封装实现与应用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

感谢您建议的解决方案!那我就采用这个方法了……谢谢!

更多关于Golang库的Python封装实现与应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我正在尝试在我的Python项目中使用一个Go库。

我猜是编译成.so文件并通过ctypes访问?

但是,对于一个map[string]string类型的变量,我没能搞定。有没有人已经将map[string]string变量映射到Python ctypes结构体?

map是一个相当复杂的类型——它在Go源码的runtime/map.go中定义。

我认为我不会尝试直接从Python使用它,我会在Go中编写一个包装器,并为给定的map暴露一些方法,比如Keys、Values、Get、Set,然后你就可以从Python调用这些方法。

对于在Python中通过ctypes处理Go的map[string]string类型,确实比基础类型复杂。由于Go的map在C ABI层面是一个指向runtime.hmap结构的指针,无法直接映射到简单的ctypes结构。以下是两种可行的解决方案:

方案一:通过C桥接函数转换(推荐)

在Go侧创建辅助函数,将map转换为C兼容类型:

// wrapper.go
package main

import "C"
import "strings"

//export ConvertMapToPairs
func ConvertMapToPairs(m map[string]string) *C.char {
    var pairs []string
    for k, v := range m {
        pairs = append(pairs, k+"="+v)
    }
    return C.CString(strings.Join(pairs, "|"))
}

//export FreeString
func FreeString(s *C.char) {
    C.free(unsafe.Pointer(s))
}

编译为共享库:

go build -buildmode=c-shared -o libwrapper.so wrapper.go

Python侧解析:

from ctypes import CDLL, c_char_p, c_void_p
import ctypes

lib = CDLL('./libwrapper.so')

lib.ConvertMapToPairs.argtypes = [c_void_p]
lib.ConvertMapToPairs.restype = c_char_p
lib.FreeString.argtypes = [c_char_p]

def go_map_to_python(go_map_ptr):
    """转换Go map到Python dict"""
    result_ptr = lib.ConvertMapToPairs(go_map_ptr)
    if not result_ptr:
        return {}
    
    result_str = result_ptr.decode('utf-8')
    lib.FreeString(result_ptr)
    
    if not result_str:
        return {}
    
    result = {}
    pairs = result_str.split('|')
    for pair in pairs:
        if '=' in pair:
            k, v = pair.split('=', 1)
            result[k] = v
    return result

方案二:序列化为JSON传递

更通用的方法是使用JSON作为中间格式:

// wrapper.go
package main

import "C"
import "encoding/json"

//export MapToJSON
func MapToJSON(m map[string]string) *C.char {
    jsonData, err := json.Marshal(m)
    if err != nil {
        return nil
    }
    return C.CString(string(jsonData))
}

Python侧:

import json
from ctypes import CDLL, c_char_p, c_void_p

lib = CDLL('./libwrapper.so')
lib.MapToJSON.argtypes = [c_void_p]
lib.MapToJSON.restype = c_char_p

def go_map_to_dict(go_map_ptr):
    json_ptr = lib.MapToJSON(go_map_ptr)
    if not json_ptr:
        return {}
    
    json_str = json_ptr.decode('utf-8')
    lib.FreeString(json_ptr)
    return json.loads(json_str)

方案三:直接传递指针并在Go侧处理

如果需要在Go函数中直接使用map,可以传递指针并在Go侧转换:

// wrapper.go
package main

import "C"

//export ProcessMap
func ProcessMap(m unsafe.Pointer) {
    // 将unsafe.Pointer转换回map
    goMap := *(*map[string]string)(m)
    // 处理map...
}

Python侧只需要传递指针:

# 假设你已经有一个Go map的指针
map_ptr = c_void_p(some_address)
lib.ProcessMap(map_ptr)

完整示例:调用带map参数的Go函数

// lib.go
package main

import "C"
import "encoding/json"

//export ProcessData
func ProcessData(input *C.char, config map[string]string) *C.char {
    // 处理逻辑
    result := map[string]interface{}{
        "input": C.GoString(input),
        "config": config,
        "processed": true,
    }
    
    jsonData, _ := json.Marshal(result)
    return C.CString(string(jsonData))
}

func main() {}
# python_client.py
import ctypes
import json

class GoString(ctypes.Structure):
    _fields_ = [("p", ctypes.c_char_p), ("n", ctypes.c_longlong)]

# 加载库
lib = ctypes.CDLL('./lib.so')

# 准备map参数
config_data = {"key1": "value1", "key2": "value2"}
config_json = json.dumps(config_data).encode('utf-8')

# 调用函数
input_str = b"test input"
result_ptr = lib.ProcessData(
    input_str,
    config_json
)

result_str = ctypes.string_at(result_ptr).decode('utf-8')
result = json.loads(result_str)
print(result)

选择哪种方案取决于具体需求:方案一适合简单键值对,方案二适合复杂数据结构,方案三适合性能敏感场景。JSON方案通常是最通用和可维护的选择。

回到顶部