1 介绍
1.1 定义与概念
01.go-python3简介
a.基本定义
go-python3是Go语言调用CPython3的C API绑定库,允许在Go程序中直接执行Python代码和调用Python函数。
b.项目来源
由DataDog公司开源维护,GitHub地址:github.com/DataDog/go-python3。
02.核心概念
a.CGO桥接
通过CGO技术实现Go与CPython C API的互操作。
b.CPython C API
CPython提供的C语言接口,用于嵌入Python解释器或扩展Python功能。
c.引用计数
Python对象使用引用计数进行内存管理,需要手动调用IncRef和DecRef。
03.应用场景
a.代码复用
复用现有的Python库和算法,避免重复造轮子。
b.性能互补
Go负责高性能并发,Python负责科学计算和机器学习。
c.快速原型
利用Python的快速开发特性进行算法验证。
1.2 核心特性
01.直接调用CPython API
a.原生绑定
直接映射CPython的C API函数,保持API的一致性。
b.完整功能
支持对象操作、模块导入、异常处理等全部CPython功能。
c.示例代码
a.功能说明
展示基本的CPython API调用流程。
b.代码示例
---
package main
import (
python3 "github.com/DataDog/go-python3"
)
func main() {
// 初始化Python解释器
python3.Py_Initialize()
defer python3.Py_Finalize()
// 执行Python代码
python3.PyRun_SimpleString("print('Hello from Python!')")
// 计算表达式
result := python3.PyRun_SimpleString("result = 2 + 3")
if result != 0 {
panic("Python执行失败")
}
}
---
02.类型系统映射
a.基本类型
支持int、float、string、bool等基本类型的双向转换。
b.复杂类型
支持list、dict、tuple等复杂数据结构。
c.自定义对象
可以操作Python自定义类和对象。
03.内存管理
a.引用计数机制
所有PyObject需要手动管理引用计数。
b.IncRef与DecRef
IncRef增加引用,DecRef减少引用,引用为0时自动释放。
c.内存安全
正确使用引用计数可避免内存泄漏和悬空指针。
1.3 优缺点分析
01.主要优势
a.性能优势
直接调用C API,性能接近原生CPython。
b.库生态
可以使用Python丰富的第三方库生态(NumPy、Pandas、TensorFlow等)。
c.开发效率
Go负责系统编程,Python负责数据处理,各取所长。
d.零序列化
数据在内存中直接传递,无需JSON/Protocol Buffers等序列化。
02.主要限制
a.CGO开销
CGO调用存在性能开销,频繁调用会影响性能。
b.GIL限制
受Python全局解释器锁(GIL)限制,无法实现真正的并行计算。
c.内存管理复杂
需要手动管理Python对象引用计数,容易出错。
d.调试困难
跨语言调试比单语言调试更复杂。
03.适用场景
a.适合使用
需要调用特定Python库、算法验证、数据科学任务。
b.不适合使用
对性能要求极高的场景、需要高并发的计算密集型任务。
1.4 使用场景
01.机器学习集成
a.模型训练
使用Python训练模型,Go进行推理服务。
b.数据预处理
利用Pandas进行数据清洗和特征工程。
c.代码示例
a.功能说明
在Go中调用sklearn训练模型。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 训练简单模型
python3.PyRun_SimpleString(`
from sklearn.linear_model import LinearRegression
import numpy as np
X = np.array([[1], [2], [3], [4], [5]])
y = np.array([2, 4, 6, 8, 10])
model = LinearRegression()
model.fit(X, y)
print(f"Coefficient: {model.coef_[0]}")
print(f"Intercept: {model.intercept_}")
`)
}
---
02.科学计算
a.数值计算
使用NumPy进行高性能数值计算。
b.数据可视化
调用matplotlib生成图表。
c.信号处理
使用SciPy进行信号处理和分析。
03.脚本自动化
a.任务调度
Go编写调度器,Python执行具体任务。
b.数据采集
利用Python丰富的爬虫库进行数据采集。
c.文本处理
使用Python的正则表达式和NLP库处理文本。
1.5 架构设计
01.系统架构
a.分层结构
Go应用层 → go-python3绑定层 → CPython C API → Python解释器。
b.调用流程
Go函数 → CGO调用 → C API → Python代码执行 → 结果返回。
02.内存模型
a.Go内存
Go对象由Go GC管理。
b.Python内存
Python对象由引用计数和GC管理。
c.边界管理
跨语言传递时需要显式转换和引用计数管理。
03.并发模型
a.Go协程
使用goroutine实现并发。
b.GIL约束
同一时刻只有一个线程执行Python代码。
c.并发策略
a.功能说明
通过多进程或异步IO绕过GIL限制。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"sync"
python3 "github.com/DataDog/go-python3"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
gilState := python3.PyGILState_Ensure()
defer python3.PyGILState_Release(gilState)
code := fmt.Sprintf(`print("Worker %d executing")`, id)
python3.PyRun_SimpleString(code)
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}
---
1.6 与CPython集成
01.嵌入式Python
a.解释器嵌入
将Python解释器嵌入到Go应用中。
b.生命周期
Py_Initialize初始化,Py_Finalize终止。
c.初始化示例
a.功能说明
正确初始化和终止Python解释器。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
// 检查是否已初始化
if !python3.Py_IsInitialized() {
python3.Py_Initialize()
}
// 获取Python版本
version := python3.Py_GetVersion()
fmt.Printf("Python版本: %s\n", version)
// 执行代码
python3.PyRun_SimpleString("import sys")
python3.PyRun_SimpleString("print(sys.version)")
// 终止解释器
python3.Py_Finalize()
}
---
02.模块系统
a.标准库
可以导入所有Python标准库模块。
b.第三方库
支持pip安装的第三方库。
c.导入示例
a.功能说明
导入并使用Python模块。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 导入json模块
jsonModule := python3.PyImport_ImportModule("json")
if jsonModule == nil {
python3.PyErr_Print()
return
}
defer jsonModule.DecRef()
// 获取dumps函数
dumps := python3.PyObject_GetAttrString(jsonModule, "dumps")
if dumps == nil {
python3.PyErr_Print()
return
}
defer dumps.DecRef()
// 创建Python字典
dict := python3.PyDict_New()
defer dict.DecRef()
python3.PyDict_SetItemString(dict, "key", python3.PyUnicode_FromString("value"))
// 调用dumps
args := python3.PyTuple_New(1)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, dict)
dict.IncRef()
result := dumps.CallObject(args)
defer result.DecRef()
jsonStr := python3.PyUnicode_AsUTF8(result)
fmt.Printf("JSON: %s\n", jsonStr)
}
---
03.C API映射
a.函数映射
每个CPython C API函数都有对应的Go函数。
b.类型映射
PyObject、PyTypeObject等类型映射为Go类型。
1.7 GIL机制
01.GIL概念
a.全局解释器锁
CPython使用GIL确保同一时刻只有一个线程执行Python字节码。
b.锁的作用
保护Python解释器内部数据结构的线程安全。
c.性能影响
限制了多线程Python程序的并行执行能力。
02.GIL管理API
a.PyGILState_Ensure
在Go线程中获取GIL,确保可以安全调用Python API。
b.PyGILState_Release
释放GIL,允许其他线程执行Python代码。
c.使用示例
a.功能说明
在多线程环境中正确管理GIL。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"sync"
python3 "github.com/DataDog/go-python3"
)
func pythonTask(taskID int, wg *sync.WaitGroup) {
defer wg.Done()
// 锁定OS线程
runtime.LockOSThread()
defer runtime.UnlockOSThread()
// 获取GIL
gilState := python3.PyGILState_Ensure()
defer python3.PyGILState_Release(gilState)
// 执行Python代码
code := fmt.Sprintf(`
import time
start = time.time()
sum([i**2 for i in range(1000)])
elapsed = time.time() - start
print(f"Task {%d} completed in {{elapsed:.4f}}s")
`, taskID)
python3.PyRun_SimpleString(code)
}
func main() {
// 初始化解释器
python3.Py_Initialize()
defer python3.Py_Finalize()
var wg sync.WaitGroup
numTasks := 4
for i := 0; i < numTasks; i++ {
wg.Add(1)
go pythonTask(i, &wg)
}
wg.Wait()
fmt.Println("所有任务完成")
}
---
03.性能优化
a.减少GIL竞争
尽量减少频繁获取和释放GIL的操作。
b.批量处理
将多个小任务合并成一个大任务,减少GIL切换。
c.使用子解释器
每个子解释器有独立的状态,但仍共享GIL。
2 基础使用
2.1 初始化与终止
01.Py_Initialize
a.功能说明
初始化Python解释器,必须在调用其他Python API之前执行。
b.初始化示例
a.功能说明
基本的解释器初始化和终止流程。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
// 初始化Python解释器
python3.Py_Initialize()
// 检查是否成功初始化
if python3.Py_IsInitialized() {
fmt.Println("Python解释器初始化成功")
}
// 执行简单的Python代码
python3.PyRun_SimpleString("print('Hello from Python')")
// 终止Python解释器
python3.Py_Finalize()
}
---
02.Py_Finalize
a.功能说明
终止Python解释器,释放所有资源。
b.注意事项
Finalize后不能再调用Python API,除非重新Initialize。
c.使用defer
建议使用defer确保解释器正确终止。
03.Py_IsInitialized
a.功能说明
检查Python解释器是否已初始化。
b.检查示例
a.功能说明
避免重复初始化解释器。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func ensureInitialized() {
if !python3.Py_IsInitialized() {
python3.Py_Initialize()
fmt.Println("解释器已初始化")
} else {
fmt.Println("解释器已经初始化过了")
}
}
func main() {
ensureInitialized()
ensureInitialized() // 第二次调用不会重复初始化
defer python3.Py_Finalize()
python3.PyRun_SimpleString("print('Running Python code')")
}
---
04.初始化配置
a.Py_SetProgramName
设置Python程序名称。
b.Py_SetPythonHome
设置Python的HOME目录。
2.2 执行Python代码
01.PyRun_SimpleString
a.功能说明
执行简单的Python字符串代码。
b.返回值
成功返回0,失败返回-1。
c.执行示例
a.功能说明
执行Python代码并处理返回值。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 执行简单语句
ret := python3.PyRun_SimpleString("x = 100")
if ret != 0 {
fmt.Println("执行失败")
return
}
// 执行计算
python3.PyRun_SimpleString("y = x * 2")
// 打印结果
python3.PyRun_SimpleString("print(f'x={x}, y={y}')")
// 执行复杂代码块
code := `
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
for i in range(10):
print(f"fib({i}) = {fibonacci(i)}")
`
python3.PyRun_SimpleString(code)
}
---
02.PyRun_SimpleFile
a.功能说明
从文件执行Python代码。
b.文件参数
需要传入*FILE指针和文件名。
03.执行表达式
a.计算表达式
使用PyRun_String计算表达式并返回结果。
b.表达式示例
a.功能说明
计算Python表达式并获取结果。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 获取__main__模块
mainModule := python3.PyImport_AddModule("__main__")
mainDict := python3.PyModule_GetDict(mainModule)
// 计算表达式
expr := "2 ** 10 + 5 * 3"
result := python3.PyRun_String(expr, python3.Py_eval_input, mainDict, mainDict)
if result == nil {
python3.PyErr_Print()
return
}
defer result.DecRef()
// 转换为Go类型
value := python3.PyLong_AsLong(result)
fmt.Printf("表达式 '%s' 的结果: %d\n", expr, value)
}
---
2.3 调用Python函数
01.获取函数对象
a.PyObject_GetAttrString
从模块或对象获取属性(包括函数)。
b.函数调用流程
获取模块 → 获取函数 → 构造参数 → 调用函数 → 处理返回值。
02.构造参数
a.PyTuple_New
创建参数元组,Python函数参数以tuple形式传递。
b.PyTuple_SetItem
设置元组中的参数值。
c.参数示例
a.功能说明
构造并传递多个参数给Python函数。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 定义Python函数
python3.PyRun_SimpleString(`
def add(a, b):
return a + b
def greet(name, age):
return f"Hello {name}, you are {age} years old"
`)
mainModule := python3.PyImport_AddModule("__main__")
// 调用add函数
addFunc := python3.PyObject_GetAttrString(mainModule, "add")
defer addFunc.DecRef()
args := python3.PyTuple_New(2)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, python3.PyLong_FromGoInt(10))
python3.PyTuple_SetItem(args, 1, python3.PyLong_FromGoInt(20))
result := addFunc.CallObject(args)
defer result.DecRef()
fmt.Printf("add(10, 20) = %d\n", python3.PyLong_AsLong(result))
// 调用greet函数
greetFunc := python3.PyObject_GetAttrString(mainModule, "greet")
defer greetFunc.DecRef()
greetArgs := python3.PyTuple_New(2)
defer greetArgs.DecRef()
python3.PyTuple_SetItem(greetArgs, 0, python3.PyUnicode_FromString("Alice"))
python3.PyTuple_SetItem(greetArgs, 1, python3.PyLong_FromGoInt(25))
greetResult := greetFunc.CallObject(greetArgs)
defer greetResult.DecRef()
fmt.Println(python3.PyUnicode_AsUTF8(greetResult))
}
---
03.调用方式
a.CallObject
使用位置参数调用函数。
b.Call
同时支持位置参数和关键字参数。
c.CallMethod
直接调用对象的方法。
2.4 导入模块
01.PyImport_ImportModule
a.功能说明
导入Python模块,返回模块对象。
b.模块名称
使用Python模块的完整名称(如"os.path")。
c.导入示例
a.功能说明
导入标准库模块并调用其函数。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 导入math模块
mathModule := python3.PyImport_ImportModule("math")
if mathModule == nil {
python3.PyErr_Print()
return
}
defer mathModule.DecRef()
// 获取sqrt函数
sqrtFunc := python3.PyObject_GetAttrString(mathModule, "sqrt")
if sqrtFunc == nil {
python3.PyErr_Print()
return
}
defer sqrtFunc.DecRef()
// 调用sqrt(16)
args := python3.PyTuple_New(1)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, python3.PyFloat_FromDouble(16.0))
result := sqrtFunc.CallObject(args)
defer result.DecRef()
value := python3.PyFloat_AsDouble(result)
fmt.Printf("sqrt(16) = %.2f\n", value)
// 获取常量pi
pi := python3.PyObject_GetAttrString(mathModule, "pi")
defer pi.DecRef()
fmt.Printf("pi = %.6f\n", python3.PyFloat_AsDouble(pi))
}
---
02.PyImport_AddModule
a.功能说明
获取已导入的模块,如__main__。
b.__main__模块
主模块,PyRun_SimpleString执行的代码都在此模块中。
03.导入自定义模块
a.sys.path
Python模块搜索路径。
b.添加路径
通过修改sys.path添加自定义模块路径。
c.自定义模块示例
a.功能说明
导入自定义路径的Python模块。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 添加模块搜索路径
python3.PyRun_SimpleString(`
import sys
sys.path.insert(0, '/path/to/modules')
`)
// 导入自定义模块
customModule := python3.PyImport_ImportModule("mymodule")
if customModule == nil {
fmt.Println("导入失败")
python3.PyErr_Print()
return
}
defer customModule.DecRef()
fmt.Println("自定义模块导入成功")
}
---
2.5 类型转换
01.整数转换
a.PyLong_FromGoInt
将Go int转换为Python int对象。
b.PyLong_AsLong
将Python int转换为Go int。
c.整数示例
a.功能说明
Go和Python整数的双向转换。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// Go → Python
goInt := 42
pyInt := python3.PyLong_FromGoInt(goInt)
defer pyInt.DecRef()
// Python → Go
backToGo := python3.PyLong_AsLong(pyInt)
fmt.Printf("原始值: %d, 转换后: %d\n", goInt, backToGo)
// 处理大整数
python3.PyRun_SimpleString("big_num = 2 ** 100")
mainModule := python3.PyImport_AddModule("__main__")
bigNum := python3.PyObject_GetAttrString(mainModule, "big_num")
defer bigNum.DecRef()
// PyLong_AsLong对于大整数会溢出,使用字符串转换
bigNumStr := python3.PyObject_Str(bigNum)
defer bigNumStr.DecRef()
fmt.Printf("大整数: %s\n", python3.PyUnicode_AsUTF8(bigNumStr))
}
---
02.浮点数转换
a.PyFloat_FromDouble
将Go float64转换为Python float。
b.PyFloat_AsDouble
将Python float转换为Go float64。
03.字符串转换
a.PyUnicode_FromString
将Go string转换为Python str。
b.PyUnicode_AsUTF8
将Python str转换为Go string。
c.字符串示例
a.功能说明
Go和Python字符串的双向转换。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// Go → Python
goStr := "Hello, 世界"
pyStr := python3.PyUnicode_FromString(goStr)
defer pyStr.DecRef()
// Python处理
python3.PyRun_SimpleString("result = None")
mainModule := python3.PyImport_AddModule("__main__")
mainDict := python3.PyModule_GetDict(mainModule)
python3.PyDict_SetItemString(mainDict, "input_str", pyStr)
python3.PyRun_SimpleString("result = input_str.upper()")
// Python → Go
result := python3.PyObject_GetAttrString(mainModule, "result")
defer result.DecRef()
backToGo := python3.PyUnicode_AsUTF8(result)
fmt.Printf("原始: %s\n转换: %s\n", goStr, backToGo)
}
---
04.布尔值转换
a.Py_True和Py_False
Python的True和False单例对象。
b.PyBool_FromLong
从整数创建布尔值(0为False,非0为True)。
2.6 返回值处理
01.检查返回值
a.NULL检查
Python API调用失败时返回NULL。
b.错误处理
返回NULL时应该使用PyErr_Print打印错误。
c.检查示例
a.功能说明
正确处理Python函数调用的返回值和错误。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func safeDivide(a, b int) (float64, error) {
python3.PyRun_SimpleString(`
def divide(x, y):
return x / y
`)
mainModule := python3.PyImport_AddModule("__main__")
divideFunc := python3.PyObject_GetAttrString(mainModule, "divide")
if divideFunc == nil {
return 0, fmt.Errorf("获取函数失败")
}
defer divideFunc.DecRef()
args := python3.PyTuple_New(2)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, python3.PyLong_FromGoInt(a))
python3.PyTuple_SetItem(args, 1, python3.PyLong_FromGoInt(b))
result := divideFunc.CallObject(args)
if result == nil {
python3.PyErr_Print()
return 0, fmt.Errorf("除法调用失败")
}
defer result.DecRef()
return python3.PyFloat_AsDouble(result), nil
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 正常调用
if result, err := safeDivide(10, 2); err == nil {
fmt.Printf("10 / 2 = %.2f\n", result)
} else {
fmt.Printf("错误: %v\n", err)
}
// 除零错误
if result, err := safeDivide(10, 0); err == nil {
fmt.Printf("10 / 0 = %.2f\n", result)
} else {
fmt.Printf("错误: %v\n", err)
}
}
---
02.引用计数管理
a.DecRef规则
所有返回的PyObject都需要DecRef。
b.IncRef时机
当需要延长对象生命周期时调用IncRef。
c.引用管理示例
a.功能说明
正确管理Python对象的引用计数。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 创建对象
pyInt := python3.PyLong_FromGoInt(100)
fmt.Printf("创建对象,引用计数: %d\n", pyInt.RefCnt())
// 增加引用
pyInt.IncRef()
fmt.Printf("IncRef后,引用计数: %d\n", pyInt.RefCnt())
// 减少引用
pyInt.DecRef()
fmt.Printf("第一次DecRef后,引用计数: %d\n", pyInt.RefCnt())
// 最终释放
pyInt.DecRef()
fmt.Println("对象已释放")
}
---
03.类型检查
a.PyLong_Check
检查对象是否为整数类型。
b.PyFloat_Check
检查对象是否为浮点数类型。
c.PyUnicode_Check
检查对象是否为字符串类型。
3 数据交互
3.1 基本类型转换
01.整数类型
a.Go int到Python int
使用PyLong_FromGoInt和PyLong_FromLong。
b.Python int到Go int
使用PyLong_AsLong和PyLong_AsLongLong。
c.整数转换示例
a.功能说明
演示各种整数类型的转换。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// int8到Python
var i8 int8 = 127
pyInt8 := python3.PyLong_FromLong(int(i8))
defer pyInt8.DecRef()
// int32到Python
var i32 int32 = 2147483647
pyInt32 := python3.PyLong_FromLong(int(i32))
defer pyInt32.DecRef()
// int64到Python
var i64 int64 = 9223372036854775807
pyInt64 := python3.PyLong_FromLongLong(i64)
defer pyInt64.DecRef()
// Python到Go
python3.PyRun_SimpleString("x = 12345")
mainModule := python3.PyImport_AddModule("__main__")
pyX := python3.PyObject_GetAttrString(mainModule, "x")
defer pyX.DecRef()
goX := python3.PyLong_AsLong(pyX)
fmt.Printf("Python x = %d\n", goX)
}
---
02.浮点类型
a.Go float到Python float
使用PyFloat_FromDouble。
b.Python float到Go float
使用PyFloat_AsDouble。
c.浮点转换示例
a.功能说明
浮点数的双向转换和精度处理。
b.代码示例
---
package main
import (
"fmt"
"math"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// Go → Python
goFloat := 3.141592653589793
pyFloat := python3.PyFloat_FromDouble(goFloat)
defer pyFloat.DecRef()
// 在Python中计算
mainModule := python3.PyImport_AddModule("__main__")
mainDict := python3.PyModule_GetDict(mainModule)
python3.PyDict_SetItemString(mainDict, "pi", pyFloat)
python3.PyRun_SimpleString("result = pi * 2")
// Python → Go
pyResult := python3.PyObject_GetAttrString(mainModule, "result")
defer pyResult.DecRef()
goResult := python3.PyFloat_AsDouble(pyResult)
fmt.Printf("2π = %.15f\n", goResult)
// 特殊值处理
pyInf := python3.PyFloat_FromDouble(math.Inf(1))
defer pyInf.DecRef()
fmt.Printf("Infinity: %v\n", math.IsInf(python3.PyFloat_AsDouble(pyInf), 1))
}
---
03.布尔类型
a.Py_True和Py_False
Python的布尔单例对象。
b.布尔检查
使用PyObject_IsTrue判断对象真值。
3.2 复杂类型转换
01.列表类型
a.PyList_New
创建指定大小的Python列表。
b.PyList_SetItem
设置列表元素(不增加引用计数)。
c.PyList_GetItem
获取列表元素(返回借用引用)。
d.列表示例
a.功能说明
创建和操作Python列表。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 创建列表
pyList := python3.PyList_New(5)
defer pyList.DecRef()
// 填充数据
for i := 0; i < 5; i++ {
python3.PyList_SetItem(pyList, i, python3.PyLong_FromGoInt(i*10))
}
// 获取列表大小
size := python3.PyList_Size(pyList)
fmt.Printf("列表大小: %d\n", size)
// 读取元素
fmt.Print("列表内容: [")
for i := 0; i < size; i++ {
item := python3.PyList_GetItem(pyList, i)
if i > 0 {
fmt.Print(", ")
}
fmt.Print(python3.PyLong_AsLong(item))
}
fmt.Println("]")
// 追加元素
python3.PyList_Append(pyList, python3.PyLong_FromGoInt(50))
fmt.Printf("追加后大小: %d\n", python3.PyList_Size(pyList))
}
---
02.字典类型
a.PyDict_New
创建空字典。
b.PyDict_SetItemString
设置字典键值对(键为字符串)。
c.PyDict_GetItemString
获取字典值(返回借用引用)。
d.字典示例
a.功能说明
创建和操作Python字典。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 创建字典
pyDict := python3.PyDict_New()
defer pyDict.DecRef()
// 添加键值对
python3.PyDict_SetItemString(pyDict, "name", python3.PyUnicode_FromString("Alice"))
python3.PyDict_SetItemString(pyDict, "age", python3.PyLong_FromGoInt(30))
python3.PyDict_SetItemString(pyDict, "score", python3.PyFloat_FromDouble(95.5))
// 读取值
name := python3.PyDict_GetItemString(pyDict, "name")
age := python3.PyDict_GetItemString(pyDict, "age")
score := python3.PyDict_GetItemString(pyDict, "score")
fmt.Printf("Name: %s\n", python3.PyUnicode_AsUTF8(name))
fmt.Printf("Age: %d\n", python3.PyLong_AsLong(age))
fmt.Printf("Score: %.1f\n", python3.PyFloat_AsDouble(score))
// 遍历字典
keys := python3.PyDict_Keys(pyDict)
defer keys.DecRef()
size := python3.PyList_Size(keys)
fmt.Println("\n字典所有键:")
for i := 0; i < size; i++ {
key := python3.PyList_GetItem(keys, i)
fmt.Printf(" %s\n", python3.PyUnicode_AsUTF8(key))
}
}
---
03.元组类型
a.PyTuple_New
创建指定大小的元组。
b.不可变性
元组创建后不能修改大小。
3.3 Go到Python
01.切片转列表
a.遍历切片
遍历Go切片,逐个添加到Python列表。
b.切片示例
a.功能说明
将Go切片转换为Python列表。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func goSliceToPyList(slice []int) *python3.PyObject {
pyList := python3.PyList_New(len(slice))
for i, v := range slice {
python3.PyList_SetItem(pyList, i, python3.PyLong_FromGoInt(v))
}
return pyList
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
goSlice := []int{10, 20, 30, 40, 50}
pyList := goSliceToPyList(goSlice)
defer pyList.DecRef()
// 在Python中处理
python3.PyRun_SimpleString(`
def sum_list(lst):
return sum(lst)
def avg_list(lst):
return sum(lst) / len(lst) if lst else 0
`)
mainModule := python3.PyImport_AddModule("__main__")
sumFunc := python3.PyObject_GetAttrString(mainModule, "sum_list")
defer sumFunc.DecRef()
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, pyList)
pyList.IncRef()
result := sumFunc.CallObject(args)
defer result.DecRef()
defer args.DecRef()
fmt.Printf("Go切片: %v\n", goSlice)
fmt.Printf("Python计算总和: %d\n", python3.PyLong_AsLong(result))
}
---
02.map转字典
a.遍历map
遍历Go map,添加键值对到Python字典。
b.map示例
a.功能说明
将Go map转换为Python字典。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func goMapToPyDict(m map[string]interface{}) *python3.PyObject {
pyDict := python3.PyDict_New()
for k, v := range m {
var pyValue *python3.PyObject
switch val := v.(type) {
case int:
pyValue = python3.PyLong_FromGoInt(val)
case float64:
pyValue = python3.PyFloat_FromDouble(val)
case string:
pyValue = python3.PyUnicode_FromString(val)
default:
continue
}
python3.PyDict_SetItemString(pyDict, k, pyValue)
}
return pyDict
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
goMap := map[string]interface{}{
"name": "Bob",
"age": 25,
"score": 88.5,
}
pyDict := goMapToPyDict(goMap)
defer pyDict.DecRef()
// 在Python中使用
mainModule := python3.PyImport_AddModule("__main__")
mainDict := python3.PyModule_GetDict(mainModule)
python3.PyDict_SetItemString(mainDict, "data", pyDict)
python3.PyRun_SimpleString(`
print(f"姓名: {data['name']}")
print(f"年龄: {data['age']}")
print(f"分数: {data['score']}")
`)
}
---
03.struct转字典
a.反射遍历
使用反射遍历struct字段。
b.标签支持
支持struct tag自定义字段名。
3.4 Python到Go
01.列表转切片
a.获取列表大小
使用PyList_Size获取元素个数。
b.遍历转换
遍历Python列表,转换每个元素到Go类型。
c.列表转切片示例
a.功能说明
将Python列表转换为Go切片。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func pyListToGoSlice(pyList *python3.PyObject) []int {
size := python3.PyList_Size(pyList)
slice := make([]int, size)
for i := 0; i < size; i++ {
item := python3.PyList_GetItem(pyList, i)
slice[i] = python3.PyLong_AsLong(item)
}
return slice
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 在Python中创建列表
python3.PyRun_SimpleString(`
result_list = [x**2 for x in range(10)]
`)
mainModule := python3.PyImport_AddModule("__main__")
pyList := python3.PyObject_GetAttrString(mainModule, "result_list")
defer pyList.DecRef()
// 转换为Go切片
goSlice := pyListToGoSlice(pyList)
fmt.Printf("Go切片: %v\n", goSlice)
fmt.Printf("长度: %d\n", len(goSlice))
}
---
02.字典转map
a.获取键列表
使用PyDict_Keys获取所有键。
b.遍历转换
遍历键,获取对应值并转换。
c.字典转map示例
a.功能说明
将Python字典转换为Go map。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func pyDictToGoMap(pyDict *python3.PyObject) map[string]interface{} {
goMap := make(map[string]interface{})
keys := python3.PyDict_Keys(pyDict)
defer keys.DecRef()
size := python3.PyList_Size(keys)
for i := 0; i < size; i++ {
key := python3.PyList_GetItem(keys, i)
keyStr := python3.PyUnicode_AsUTF8(key)
value := python3.PyDict_GetItem(pyDict, key)
if python3.PyLong_Check(value) {
goMap[keyStr] = python3.PyLong_AsLong(value)
} else if python3.PyFloat_Check(value) {
goMap[keyStr] = python3.PyFloat_AsDouble(value)
} else if python3.PyUnicode_Check(value) {
goMap[keyStr] = python3.PyUnicode_AsUTF8(value)
}
}
return goMap
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// Python创建字典
python3.PyRun_SimpleString(`
person = {
'name': 'Charlie',
'age': 35,
'height': 175.5
}
`)
mainModule := python3.PyImport_AddModule("__main__")
pyDict := python3.PyObject_GetAttrString(mainModule, "person")
defer pyDict.DecRef()
// 转换为Go map
goMap := pyDictToGoMap(pyDict)
fmt.Printf("Go map: %+v\n", goMap)
}
---
03.元组转数组
a.固定大小
元组大小固定,适合转换为数组。
b.PyTuple_GetItem
获取元组指定位置的元素。
3.5 内存管理
01.所有权规则
a.新建引用
PyXXX_New等创建函数返回新引用,需要DecRef。
b.借用引用
PyList_GetItem、PyDict_GetItem等返回借用引用,不需要DecRef。
c.所有权示例
a.功能说明
演示新引用和借用引用的区别。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 新引用 - 需要DecRef
pyInt := python3.PyLong_FromGoInt(42)
fmt.Printf("新引用,初始计数: %d\n", pyInt.RefCnt())
pyInt.DecRef()
// 借用引用 - 不需要DecRef
pyList := python3.PyList_New(3)
defer pyList.DecRef()
python3.PyList_SetItem(pyList, 0, python3.PyLong_FromGoInt(1))
python3.PyList_SetItem(pyList, 1, python3.PyLong_FromGoInt(2))
python3.PyList_SetItem(pyList, 2, python3.PyLong_FromGoInt(3))
// GetItem返回借用引用
item := python3.PyList_GetItem(pyList, 0)
fmt.Printf("借用引用: %d\n", python3.PyLong_AsLong(item))
// 不需要item.DecRef()
// 如果需要保留借用引用,需要IncRef
item.IncRef()
fmt.Printf("IncRef后计数: %d\n", item.RefCnt())
item.DecRef()
}
---
02.循环引用
a.GC处理
Python GC可以处理循环引用。
b.手动打破
在Go侧及时DecRef避免循环引用。
03.内存泄漏检测
a.引用计数追踪
记录所有IncRef和DecRef调用。
b.检测示例
a.功能说明
使用Python gc模块检测内存泄漏。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import gc
import sys
def get_object_count():
gc.collect()
return len(gc.get_objects())
initial_count = get_object_count()
print(f"初始对象数: {initial_count}")
`)
mainModule := python3.PyImport_AddModule("__main__")
getCount := python3.PyObject_GetAttrString(mainModule, "get_object_count")
defer getCount.DecRef()
emptyArgs := python3.PyTuple_New(0)
defer emptyArgs.DecRef()
// 创建一些对象
for i := 0; i < 100; i++ {
obj := python3.PyLong_FromGoInt(i)
obj.DecRef()
}
// 检查对象数量
count := getCount.CallObject(emptyArgs)
defer count.DecRef()
finalCount := python3.PyLong_AsLong(count)
fmt.Printf("最终对象数: %d\n", finalCount)
}
---
3.6 引用计数
01.IncRef和DecRef
a.IncRef
增加对象引用计数,延长对象生命周期。
b.DecRef
减少对象引用计数,计数为0时释放对象。
c.引用示例
a.功能说明
正确使用IncRef和DecRef管理对象。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 创建对象
obj := python3.PyUnicode_FromString("Hello")
fmt.Printf("创建后引用计数: %d\n", obj.RefCnt())
// 增加引用
obj.IncRef()
fmt.Printf("IncRef后引用计数: %d\n", obj.RefCnt())
obj.IncRef()
fmt.Printf("再次IncRef后引用计数: %d\n", obj.RefCnt())
// 减少引用
obj.DecRef()
fmt.Printf("第一次DecRef后引用计数: %d\n", obj.RefCnt())
obj.DecRef()
fmt.Printf("第二次DecRef后引用计数: %d\n", obj.RefCnt())
obj.DecRef()
fmt.Println("对象已释放")
}
---
02.SetItem特殊情况
a.PyList_SetItem
会窃取引用,不需要对设置的对象DecRef。
b.PyDict_SetItem
不窃取引用,需要对设置的对象DecRef。
c.SetItem示例
a.功能说明
演示SetItem的引用计数行为。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// PyList_SetItem窃取引用
pyList := python3.PyList_New(2)
defer pyList.DecRef()
item1 := python3.PyLong_FromGoInt(100)
fmt.Printf("item1引用计数: %d\n", item1.RefCnt())
python3.PyList_SetItem(pyList, 0, item1)
// 不需要item1.DecRef(),SetItem已窃取引用
// PyDict_SetItem不窃取引用
pyDict := python3.PyDict_New()
defer pyDict.DecRef()
key := python3.PyUnicode_FromString("key")
value := python3.PyLong_FromGoInt(200)
fmt.Printf("value引用计数: %d\n", value.RefCnt())
python3.PyDict_SetItem(pyDict, key, value)
fmt.Printf("SetItem后value引用计数: %d\n", value.RefCnt())
// 需要手动DecRef
key.DecRef()
value.DecRef()
}
---
03.常见错误
a.忘记DecRef
导致内存泄漏,Python对象无法释放。
b.重复DecRef
导致崩溃或未定义行为。
c.使用已释放对象
导致访问野指针,程序崩溃。
4 模块与对象
4.1 模块导入
01.导入标准库
a.PyImport_ImportModule
导入Python标准库模块。
b.错误处理
导入失败返回NULL,需检查并打印错误。
c.导入示例
a.功能说明
导入并使用多个标准库模块。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 导入os模块
osModule := python3.PyImport_ImportModule("os")
if osModule == nil {
python3.PyErr_Print()
return
}
defer osModule.DecRef()
// 获取getcwd函数
getcwd := python3.PyObject_GetAttrString(osModule, "getcwd")
defer getcwd.DecRef()
emptyArgs := python3.PyTuple_New(0)
defer emptyArgs.DecRef()
cwd := getcwd.CallObject(emptyArgs)
defer cwd.DecRef()
fmt.Printf("当前目录: %s\n", python3.PyUnicode_AsUTF8(cwd))
// 导入sys模块
sysModule := python3.PyImport_ImportModule("sys")
if sysModule == nil {
python3.PyErr_Print()
return
}
defer sysModule.DecRef()
version := python3.PyObject_GetAttrString(sysModule, "version")
defer version.DecRef()
fmt.Printf("Python版本: %s\n", python3.PyUnicode_AsUTF8(version))
}
---
02.导入第三方库
a.pip安装
需要先用pip安装第三方库。
b.环境变量
确保PYTHONPATH设置正确。
03.模块重载
a.importlib.reload
重新加载已导入的模块。
b.重载示例
a.功能说明
重新加载Python模块。
b.代码示例
---
package main
import (
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import importlib
import math
print(f"math.pi = {math.pi}")
# 模拟修改模块后重载
importlib.reload(math)
print(f"重载后 math.pi = {math.pi}")
`)
}
---
4.2 对象操作
01.创建对象实例
a.获取类对象
从模块获取类定义。
b.调用类创建实例
像调用函数一样调用类对象。
c.实例创建示例
a.功能说明
创建Python类的实例对象。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
// 定义Python类
python3.PyRun_SimpleString(`
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, I'm {self.name}, {self.age} years old"
def birthday(self):
self.age += 1
return self.age
`)
mainModule := python3.PyImport_AddModule("__main__")
personClass := python3.PyObject_GetAttrString(mainModule, "Person")
defer personClass.DecRef()
// 创建实例
args := python3.PyTuple_New(2)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, python3.PyUnicode_FromString("Alice"))
python3.PyTuple_SetItem(args, 1, python3.PyLong_FromGoInt(25))
personObj := personClass.CallObject(args)
defer personObj.DecRef()
// 调用方法
greetMethod := python3.PyObject_GetAttrString(personObj, "greet")
defer greetMethod.DecRef()
emptyArgs := python3.PyTuple_New(0)
defer emptyArgs.DecRef()
greeting := greetMethod.CallObject(emptyArgs)
defer greeting.DecRef()
fmt.Println(python3.PyUnicode_AsUTF8(greeting))
}
---
02.对象类型检查
a.PyObject_Type
获取对象的类型。
b.PyObject_IsInstance
检查对象是否为特定类的实例。
03.对象比较
a.PyObject_RichCompare
比较两个Python对象。
b.比较运算符
支持<、<=、==、!=、>、>=等运算符。
4.3 属性访问
01.获取属性
a.PyObject_GetAttrString
通过字符串名称获取对象属性。
b.PyObject_GetAttr
通过Python对象获取属性。
c.属性获取示例
a.功能说明
获取和修改Python对象的属性。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
class Car:
def __init__(self, brand, year):
self.brand = brand
self.year = year
self.mileage = 0
def drive(self, km):
self.mileage += km
car = Car("Toyota", 2020)
`)
mainModule := python3.PyImport_AddModule("__main__")
car := python3.PyObject_GetAttrString(mainModule, "car")
defer car.DecRef()
// 获取属性
brand := python3.PyObject_GetAttrString(car, "brand")
defer brand.DecRef()
fmt.Printf("品牌: %s\n", python3.PyUnicode_AsUTF8(brand))
year := python3.PyObject_GetAttrString(car, "year")
defer year.DecRef()
fmt.Printf("年份: %d\n", python3.PyLong_AsLong(year))
// 修改属性
newMileage := python3.PyLong_FromGoInt(5000)
python3.PyObject_SetAttrString(car, "mileage", newMileage)
newMileage.DecRef()
mileage := python3.PyObject_GetAttrString(car, "mileage")
defer mileage.DecRef()
fmt.Printf("里程: %d km\n", python3.PyLong_AsLong(mileage))
}
---
02.设置属性
a.PyObject_SetAttrString
设置对象属性值。
b.动态添加
可以动态添加新属性到对象。
03.删除属性
a.PyObject_DelAttrString
删除对象的指定属性。
b.属性检查
使用PyObject_HasAttrString检查属性是否存在。
4.4 方法调用
01.调用实例方法
a.获取方法对象
使用GetAttrString获取方法。
b.传递参数
使用tuple传递方法参数。
c.方法调用示例
a.功能说明
调用Python对象的实例方法。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
class Calculator:
def __init__(self):
self.result = 0
def add(self, x, y):
self.result = x + y
return self.result
def multiply(self, x, y):
self.result = x * y
return self.result
def get_result(self):
return self.result
calc = Calculator()
`)
mainModule := python3.PyImport_AddModule("__main__")
calc := python3.PyObject_GetAttrString(mainModule, "calc")
defer calc.DecRef()
// 调用add方法
addMethod := python3.PyObject_GetAttrString(calc, "add")
defer addMethod.DecRef()
args := python3.PyTuple_New(2)
python3.PyTuple_SetItem(args, 0, python3.PyLong_FromGoInt(10))
python3.PyTuple_SetItem(args, 1, python3.PyLong_FromGoInt(20))
result := addMethod.CallObject(args)
defer result.DecRef()
defer args.DecRef()
fmt.Printf("10 + 20 = %d\n", python3.PyLong_AsLong(result))
// 调用multiply方法
multiplyMethod := python3.PyObject_GetAttrString(calc, "multiply")
defer multiplyMethod.DecRef()
args2 := python3.PyTuple_New(2)
python3.PyTuple_SetItem(args2, 0, python3.PyLong_FromGoInt(5))
python3.PyTuple_SetItem(args2, 1, python3.PyLong_FromGoInt(6))
result2 := multiplyMethod.CallObject(args2)
defer result2.DecRef()
defer args2.DecRef()
fmt.Printf("5 * 6 = %d\n", python3.PyLong_AsLong(result2))
}
---
02.调用静态方法
a.静态方法定义
使用@staticmethod装饰器。
b.无需实例
可以直接从类调用静态方法。
03.调用类方法
a.类方法定义
使用@classmethod装饰器。
b.接收类对象
第一个参数自动为类对象。
4.5 异常处理
01.检查异常
a.PyErr_Occurred
检查是否发生异常。
b.返回NULL
发生异常时API返回NULL。
c.异常检查示例
a.功能说明
检测和处理Python异常。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func safeDivide(a, b int) {
python3.PyRun_SimpleString(fmt.Sprintf(`
try:
result = %d / %d
print(f"结果: {result}")
except ZeroDivisionError as e:
print(f"除零错误: {e}")
except Exception as e:
print(f"其他错误: {e}")
`, a, b))
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
safeDivide(10, 2)
safeDivide(10, 0)
}
---
02.打印异常
a.PyErr_Print
打印异常信息到stderr并清除异常状态。
b.PyErr_Clear
仅清除异常状态,不打印。
c.异常打印示例
a.功能说明
正确处理和打印Python异常信息。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func callPythonFunc(funcName string) {
mainModule := python3.PyImport_AddModule("__main__")
fn := python3.PyObject_GetAttrString(mainModule, funcName)
if fn == nil {
fmt.Printf("函数 '%s' 不存在\n", funcName)
if python3.PyErr_Occurred() != nil {
python3.PyErr_Print()
}
return
}
defer fn.DecRef()
args := python3.PyTuple_New(0)
defer args.DecRef()
result := fn.CallObject(args)
if result == nil {
fmt.Printf("调用 '%s' 时发生异常:\n", funcName)
python3.PyErr_Print()
return
}
defer result.DecRef()
fmt.Printf("'%s' 执行成功\n", funcName)
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
def good_func():
return "OK"
def bad_func():
raise ValueError("Something went wrong")
`)
callPythonFunc("good_func")
callPythonFunc("bad_func")
callPythonFunc("nonexistent_func")
}
---
03.获取异常信息
a.PyErr_Fetch
获取异常类型、值和traceback。
b.PyErr_NormalizeException
规范化异常对象。
5 高级特性
5.1 多线程处理
01.多线程基础
a.GIL限制
同一时刻只有一个线程执行Python代码。
b.runtime.LockOSThread
将goroutine绑定到OS线程。
02.多线程示例
a.功能说明
在多个goroutine中并发调用Python。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"sync"
python3 "github.com/DataDog/go-python3"
)
func pythonWorker(id int, wg *sync.WaitGroup) {
defer wg.Done()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
gilState := python3.PyGILState_Ensure()
defer python3.PyGILState_Release(gilState)
code := fmt.Sprintf(`
import time
start = time.time()
result = sum([i**2 for i in range(100000)])
elapsed = time.time() - start
print(f"Worker {%d}: result={result}, time={elapsed:.4f}s")
`, id)
python3.PyRun_SimpleString(code)
}
func main() {
runtime.LockOSThread()
python3.Py_Initialize()
defer python3.Py_Finalize()
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go pythonWorker(i, &wg)
}
wg.Wait()
fmt.Println("所有worker完成")
}
---
03.线程同步
a.使用channel
通过Go channel协调多个Python调用。
b.使用mutex
保护共享的Python对象。
5.2 GIL管理
01.PyGILState_Ensure
a.功能说明
在当前线程获取GIL,确保可以调用Python API。
b.返回值
返回GIL状态,需要传递给Release。
02.PyGILState_Release
a.功能说明
释放之前获取的GIL。
b.参数
需要传入Ensure返回的状态值。
03.GIL管理示例
a.功能说明
正确的GIL获取和释放流程。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"time"
python3 "github.com/DataDog/go-python3"
)
func longRunningTask(taskID int) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
gilState := python3.PyGILState_Ensure()
python3.PyRun_SimpleString(fmt.Sprintf(`
print("Task %d: 获取GIL")
import time
time.sleep(0.1)
print("Task %d: Python计算中...")
result = sum(range(1000000))
print(f"Task {%d}: 完成,结果={result}")
`, taskID, taskID, taskID))
python3.PyGILState_Release(gilState)
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
done := make(chan bool)
for i := 0; i < 3; i++ {
taskID := i
go func() {
longRunningTask(taskID)
done <- true
}()
time.Sleep(10 * time.Millisecond)
}
for i := 0; i < 3; i++ {
<-done
}
fmt.Println("所有任务完成")
}
---
04.释放GIL执行Go代码
a.PyEval_SaveThread
释放GIL,允许其他线程执行。
b.PyEval_RestoreThread
重新获取GIL。
5.3 回调函数
01.Go回调Python
a.定义回调
在Python中定义回调函数,从Go调用。
b.传递回调
a.功能说明
将Go函数包装后传递给Python作为回调。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
def process_data(data, callback):
result = data * 2
return callback(result)
def my_callback(value):
return value + 100
`)
mainModule := python3.PyImport_AddModule("__main__")
processFunc := python3.PyObject_GetAttrString(mainModule, "process_data")
defer processFunc.DecRef()
callbackFunc := python3.PyObject_GetAttrString(mainModule, "my_callback")
defer callbackFunc.DecRef()
args := python3.PyTuple_New(2)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, python3.PyLong_FromGoInt(50))
python3.PyTuple_SetItem(args, 1, callbackFunc)
callbackFunc.IncRef()
result := processFunc.CallObject(args)
defer result.DecRef()
fmt.Printf("回调结果: %d\n", python3.PyLong_AsLong(result))
}
---
02.闭包回调
a.捕获变量
Python闭包可以捕获外部变量。
b.闭包示例
a.功能说明
使用闭包实现带状态的回调函数。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
def create_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
def apply_n_times(func, n):
results = []
for _ in range(n):
results.append(func())
return results
`)
mainModule := python3.PyImport_AddModule("__main__")
createCounter := python3.PyObject_GetAttrString(mainModule, "create_counter")
defer createCounter.DecRef()
emptyArgs := python3.PyTuple_New(0)
defer emptyArgs.DecRef()
counter := createCounter.CallObject(emptyArgs)
defer counter.DecRef()
applyFunc := python3.PyObject_GetAttrString(mainModule, "apply_n_times")
defer applyFunc.DecRef()
args := python3.PyTuple_New(2)
defer args.DecRef()
python3.PyTuple_SetItem(args, 0, counter)
counter.IncRef()
python3.PyTuple_SetItem(args, 1, python3.PyLong_FromGoInt(5))
results := applyFunc.CallObject(args)
defer results.DecRef()
size := python3.PyList_Size(results)
fmt.Print("计数结果: [")
for i := 0; i < size; i++ {
item := python3.PyList_GetItem(results, i)
if i > 0 {
fmt.Print(", ")
}
fmt.Print(python3.PyLong_AsLong(item))
}
fmt.Println("]")
}
---
03.异步回调
a.延迟执行
回调函数可以在异步操作完成后执行。
b.事件处理
使用回调实现事件驱动编程模式。
5.4 子解释器
01.子解释器概念
a.隔离环境
子解释器提供独立的Python执行环境。
b.资源隔离
每个子解释器有独立的模块、全局变量。
02.创建子解释器
a.Py_NewInterpreter
创建新的子解释器实例。
b.子解释器示例
a.功能说明
创建独立的子解释器执行不同代码。
b.代码示例
---
package main
import (
"fmt"
"runtime"
python3 "github.com/DataDog/go-python3"
)
func main() {
runtime.LockOSThread()
python3.Py_Initialize()
defer python3.Py_Finalize()
mainState := python3.PyEval_SaveThread()
python3.PyEval_RestoreThread(mainState)
python3.PyRun_SimpleString("main_var = 'main'")
python3.PyRun_SimpleString("print(f'主解释器: {main_var}')")
subState := python3.Py_NewInterpreter()
if subState == nil {
fmt.Println("创建子解释器失败")
return
}
python3.PyRun_SimpleString("sub_var = 'sub'")
python3.PyRun_SimpleString("print(f'子解释器: {sub_var}')")
python3.Py_EndInterpreter(subState)
python3.PyRun_SimpleString("print(f'返回主解释器: {main_var}')")
}
---
03.子解释器通信
a.数据传递
通过序列化在不同解释器间传递数据。
b.通信示例
a.功能说明
使用pickle在子解释器间传递对象。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import pickle
def serialize_data(data):
return pickle.dumps(data)
def deserialize_data(data_bytes):
return pickle.loads(data_bytes)
shared_data = {'key': 'value', 'number': 42}
serialized = serialize_data(shared_data)
print(f"序列化数据: {len(serialized)} bytes")
restored = deserialize_data(serialized)
print(f"反序列化数据: {restored}")
`)
fmt.Println("子解释器通信完成")
}
---
04.子解释器限制
a.GIL共享
所有子解释器共享同一个GIL。
b.扩展模块
部分C扩展模块可能不支持子解释器。
5.5 性能优化
01.减少对象创建
a.对象复用
重复使用Python对象减少创建销毁开销。
b.复用示例
a.功能说明
缓存常用对象避免重复创建。
b.代码示例
---
package main
import (
"fmt"
"time"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
def add(a, b):
return a + b
`)
mainModule := python3.PyImport_AddModule("__main__")
addFunc := python3.PyObject_GetAttrString(mainModule, "add")
defer addFunc.DecRef()
emptyKwargs := python3.PyDict_New()
defer emptyKwargs.DecRef()
start := time.Now()
for i := 0; i < 10000; i++ {
args := python3.PyTuple_New(2)
python3.PyTuple_SetItem(args, 0, python3.PyLong_FromGoInt(i))
python3.PyTuple_SetItem(args, 1, python3.PyLong_FromGoInt(i+1))
result := addFunc.Call(args, emptyKwargs)
result.DecRef()
args.DecRef()
}
fmt.Printf("10000次调用耗时: %v\n", time.Since(start))
}
---
02.批量处理
a.减少调用次数
批量处理数据减少Go-Python边界跨越。
b.批量示例
a.功能说明
一次传递多个数据进行批量计算。
b.代码示例
---
package main
import (
"fmt"
"time"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
def process_batch(numbers):
return [n * 2 for n in numbers]
def process_single(n):
return n * 2
`)
mainModule := python3.PyImport_AddModule("__main__")
processBatch := python3.PyObject_GetAttrString(mainModule, "process_batch")
defer processBatch.DecRef()
pyList := python3.PyList_New(1000)
for i := 0; i < 1000; i++ {
python3.PyList_SetItem(pyList, i, python3.PyLong_FromGoInt(i))
}
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, pyList)
start := time.Now()
result := processBatch.CallObject(args)
fmt.Printf("批量处理1000个数耗时: %v\n", time.Since(start))
result.DecRef()
args.DecRef()
}
---
03.使用C扩展
a.NumPy优化
使用NumPy等C扩展库提升计算性能。
b.避免纯Python循环
将密集计算移至C扩展或Go实现。
6 实战应用
6.1 安装配置
01.环境要求
a.Python版本
需要Python 3.x(推荐3.7+)。
b.CGO支持
必须启用CGO编译支持。
02.安装go-python3
a.获取依赖
使用go get命令获取库。
b.安装示例
a.功能说明
通过go get安装go-python3库。
b.代码示例
---
go get -u github.com/DataDog/go-python3
---
c.pkg-config配置
确保pkg-config能找到python3。
d.配置示例
a.功能说明
验证pkg-config配置是否正确。
b.代码示例
---
pkg-config --cflags --libs python3
pkg-config --modversion python3
---
03.编译配置
a.CGO_ENABLED
设置CGO_ENABLED=1启用CGO。
b.编译示例
a.功能说明
正确编译使用go-python3的程序。
b.代码示例
---
CGO_ENABLED=1 go build main.go
---
04.常见问题
a.找不到Python
设置PKG_CONFIG_PATH指向python3.pc文件。
b.链接错误
检查Python开发包是否已安装。
c.解决示例
a.功能说明
排查和解决常见安装问题。
b.代码示例
---
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
export CGO_CFLAGS="-I/usr/include/python3.9"
export CGO_LDFLAGS="-L/usr/lib -lpython3.9"
go build
---
6.2 调用NumPy
01.NumPy简介
a.科学计算
NumPy提供高性能数组和数学函数。
b.C扩展
NumPy底层使用C实现,性能优异。
02.调用NumPy数组
a.导入NumPy
使用PyImport_ImportModule导入numpy。
b.数组操作
a.功能说明
创建NumPy数组并执行计算。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
numpy := python3.PyImport_ImportModule("numpy")
if numpy == nil {
python3.PyErr_Print()
return
}
defer numpy.DecRef()
arrayFunc := python3.PyObject_GetAttrString(numpy, "array")
defer arrayFunc.DecRef()
pyList := python3.PyList_New(5)
for i := 0; i < 5; i++ {
python3.PyList_SetItem(pyList, i, python3.PyLong_FromGoInt(i*10))
}
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, pyList)
npArray := arrayFunc.CallObject(args)
defer npArray.DecRef()
defer args.DecRef()
meanFunc := python3.PyObject_GetAttrString(npArray, "mean")
defer meanFunc.DecRef()
emptyArgs := python3.PyTuple_New(0)
defer emptyArgs.DecRef()
meanResult := meanFunc.CallObject(emptyArgs)
defer meanResult.DecRef()
fmt.Printf("NumPy数组均值: %.2f\n", python3.PyFloat_AsDouble(meanResult))
}
---
03.矩阵运算
a.矩阵乘法
使用np.dot进行矩阵运算。
b.矩阵示例
a.功能说明
执行NumPy矩阵乘法运算。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import numpy as np
def matrix_multiply(a, b):
arr_a = np.array(a)
arr_b = np.array(b)
result = np.dot(arr_a, arr_b)
return result.tolist()
`)
mainModule := python3.PyImport_AddModule("__main__")
matMul := python3.PyObject_GetAttrString(mainModule, "matrix_multiply")
defer matMul.DecRef()
matA := python3.PyList_New(2)
rowA1 := python3.PyList_New(2)
python3.PyList_SetItem(rowA1, 0, python3.PyLong_FromGoInt(1))
python3.PyList_SetItem(rowA1, 1, python3.PyLong_FromGoInt(2))
rowA2 := python3.PyList_New(2)
python3.PyList_SetItem(rowA2, 0, python3.PyLong_FromGoInt(3))
python3.PyList_SetItem(rowA2, 1, python3.PyLong_FromGoInt(4))
python3.PyList_SetItem(matA, 0, rowA1)
python3.PyList_SetItem(matA, 1, rowA2)
matB := python3.PyList_New(2)
rowB1 := python3.PyList_New(2)
python3.PyList_SetItem(rowB1, 0, python3.PyLong_FromGoInt(5))
python3.PyList_SetItem(rowB1, 1, python3.PyLong_FromGoInt(6))
rowB2 := python3.PyList_New(2)
python3.PyList_SetItem(rowB2, 0, python3.PyLong_FromGoInt(7))
python3.PyList_SetItem(rowB2, 1, python3.PyLong_FromGoInt(8))
python3.PyList_SetItem(matB, 0, rowB1)
python3.PyList_SetItem(matB, 1, rowB2)
args := python3.PyTuple_New(2)
python3.PyTuple_SetItem(args, 0, matA)
python3.PyTuple_SetItem(args, 1, matB)
result := matMul.CallObject(args)
defer result.DecRef()
defer args.DecRef()
fmt.Println("矩阵乘法结果:")
size := python3.PyList_Size(result)
for i := 0; i < size; i++ {
row := python3.PyList_GetItem(result, i)
rowSize := python3.PyList_Size(row)
for j := 0; j < rowSize; j++ {
item := python3.PyList_GetItem(row, j)
fmt.Printf("%d ", python3.PyLong_AsLong(item))
}
fmt.Println()
}
}
---
04.性能优化
a.避免转换
尽量在Python侧完成批量计算。
b.使用视图
NumPy视图避免数据复制。
6.3 机器学习库
01.调用scikit-learn
a.模型训练
使用sklearn训练机器学习模型。
b.训练示例
a.功能说明
训练简单线性回归模型。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
from sklearn.linear_model import LinearRegression
import numpy as np
def train_model(X_data, y_data):
model = LinearRegression()
X = np.array(X_data).reshape(-1, 1)
y = np.array(y_data)
model.fit(X, y)
return model.coef_[0], model.intercept_
def predict(coef, intercept, X_data):
X = np.array(X_data).reshape(-1, 1)
return (X * coef + intercept).tolist()
`)
mainModule := python3.PyImport_AddModule("__main__")
trainFunc := python3.PyObject_GetAttrString(mainModule, "train_model")
defer trainFunc.DecRef()
X := python3.PyList_New(5)
y := python3.PyList_New(5)
for i := 0; i < 5; i++ {
python3.PyList_SetItem(X, i, python3.PyFloat_FromDouble(float64(i)))
python3.PyList_SetItem(y, i, python3.PyFloat_FromDouble(float64(i*2+1)))
}
args := python3.PyTuple_New(2)
python3.PyTuple_SetItem(args, 0, X)
python3.PyTuple_SetItem(args, 1, y)
result := trainFunc.CallObject(args)
defer result.DecRef()
defer args.DecRef()
coef := python3.PyTuple_GetItem(result, 0)
intercept := python3.PyTuple_GetItem(result, 1)
fmt.Printf("训练完成 - 系数: %.2f, 截距: %.2f\n",
python3.PyFloat_AsDouble(coef),
python3.PyFloat_AsDouble(intercept))
}
---
02.调用TensorFlow
a.模型加载
加载预训练的TensorFlow模型。
b.推理示例
a.功能说明
使用TensorFlow进行模型推理。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import numpy as np
def simple_nn_predict(input_data):
# 模拟简单神经网络预测
data = np.array(input_data)
weights = np.array([0.5, 0.3, 0.2])
result = np.dot(data, weights)
return float(result)
`)
mainModule := python3.PyImport_AddModule("__main__")
predictFunc := python3.PyObject_GetAttrString(mainModule, "simple_nn_predict")
defer predictFunc.DecRef()
inputData := python3.PyList_New(3)
python3.PyList_SetItem(inputData, 0, python3.PyFloat_FromDouble(1.0))
python3.PyList_SetItem(inputData, 1, python3.PyFloat_FromDouble(2.0))
python3.PyList_SetItem(inputData, 2, python3.PyFloat_FromDouble(3.0))
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, inputData)
result := predictFunc.CallObject(args)
defer result.DecRef()
defer args.DecRef()
fmt.Printf("神经网络预测结果: %.4f\n", python3.PyFloat_AsDouble(result))
}
---
03.批量推理
a.批量处理
一次传递多个样本进行批量推理。
b.性能优化
批量推理减少Python调用次数,提升性能。
6.4 数据处理
01.Pandas数据分析
a.DataFrame操作
使用Pandas进行数据分析和处理。
b.DataFrame示例
a.功能说明
创建并操作Pandas DataFrame。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import pandas as pd
def create_dataframe(data_dict):
df = pd.DataFrame(data_dict)
return df
def analyze_dataframe(df):
stats = {
'mean': df.mean().to_dict(),
'max': df.max().to_dict(),
'min': df.min().to_dict()
}
return stats
`)
mainModule := python3.PyImport_AddModule("__main__")
createDF := python3.PyObject_GetAttrString(mainModule, "create_dataframe")
defer createDF.DecRef()
dataDict := python3.PyDict_New()
ageList := python3.PyList_New(5)
for i := 0; i < 5; i++ {
python3.PyList_SetItem(ageList, i, python3.PyLong_FromGoInt(20+i*5))
}
python3.PyDict_SetItemString(dataDict, "age", ageList)
scoreList := python3.PyList_New(5)
scores := []int{85, 90, 88, 92, 87}
for i, s := range scores {
python3.PyList_SetItem(scoreList, i, python3.PyLong_FromGoInt(s))
}
python3.PyDict_SetItemString(dataDict, "score", scoreList)
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, dataDict)
df := createDF.CallObject(args)
defer df.DecRef()
defer args.DecRef()
analyzeFunc := python3.PyObject_GetAttrString(mainModule, "analyze_dataframe")
defer analyzeFunc.DecRef()
analyzeArgs := python3.PyTuple_New(1)
python3.PyTuple_SetItem(analyzeArgs, 0, df)
df.IncRef()
stats := analyzeFunc.CallObject(analyzeArgs)
defer stats.DecRef()
defer analyzeArgs.DecRef()
fmt.Println("DataFrame统计分析完成")
}
---
02.数据清洗
a.缺失值处理
使用fillna、dropna处理缺失数据。
b.清洗示例
a.功能说明
清洗包含缺失值的数据。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import pandas as pd
import numpy as np
def clean_data(data_list):
df = pd.DataFrame(data_list, columns=['value'])
df_cleaned = df.fillna(df['value'].mean())
return df_cleaned['value'].tolist()
`)
mainModule := python3.PyImport_AddModule("__main__")
cleanFunc := python3.PyObject_GetAttrString(mainModule, "clean_data")
defer cleanFunc.DecRef()
dataList := python3.PyList_New(6)
values := []float64{1.0, 2.0, -1.0, 4.0, 5.0, -1.0}
for i, v := range values {
if v < 0 {
python3.PyList_SetItem(dataList, i, python3.Py_None)
} else {
python3.PyList_SetItem(dataList, i, python3.PyFloat_FromDouble(v))
}
}
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, dataList)
result := cleanFunc.CallObject(args)
defer result.DecRef()
defer args.DecRef()
fmt.Print("清洗后数据: [")
size := python3.PyList_Size(result)
for i := 0; i < size; i++ {
if i > 0 {
fmt.Print(", ")
}
item := python3.PyList_GetItem(result, i)
fmt.Printf("%.2f", python3.PyFloat_AsDouble(item))
}
fmt.Println("]")
}
---
03.数据转换
a.格式转换
CSV、JSON、Excel等格式互转。
b.聚合计算
groupby分组统计数据。
6.5 脚本执行
01.执行Python脚本文件
a.PyRun_SimpleFile
从文件执行Python脚本。
b.文件执行示例
a.功能说明
读取并执行外部Python脚本文件。
b.代码示例
---
package main
import (
"fmt"
"os"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
scriptContent := `
def greet(name):
return f"Hello, {name}!"
def calculate(a, b):
return a + b
result = greet("World")
print(result)
sum_result = calculate(10, 20)
print(f"Sum: {sum_result}")
`
tmpFile, err := os.CreateTemp("", "script*.py")
if err != nil {
fmt.Printf("创建临时文件失败: %v\n", err)
return
}
defer os.Remove(tmpFile.Name())
_, err = tmpFile.WriteString(scriptContent)
if err != nil {
fmt.Printf("写入文件失败: %v\n", err)
return
}
tmpFile.Close()
file, err := os.Open(tmpFile.Name())
if err != nil {
fmt.Printf("打开文件失败: %v\n", err)
return
}
defer file.Close()
python3.PyRun_SimpleFile(file, tmpFile.Name())
fmt.Println("脚本执行完成")
}
---
02.动态脚本执行
a.运行时生成
根据条件动态生成并执行Python代码。
b.动态执行示例
a.功能说明
动态生成Python代码并执行。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func executeDynamicScript(operation string, a, b int) {
var script string
switch operation {
case "add":
script = fmt.Sprintf("result = %d + %d", a, b)
case "multiply":
script = fmt.Sprintf("result = %d * %d", a, b)
case "power":
script = fmt.Sprintf("result = %d ** %d", a, b)
default:
script = "result = 0"
}
python3.PyRun_SimpleString(script)
mainModule := python3.PyImport_AddModule("__main__")
resultObj := python3.PyObject_GetAttrString(mainModule, "result")
defer resultObj.DecRef()
result := python3.PyLong_AsLong(resultObj)
fmt.Printf("%s(%d, %d) = %d\n", operation, a, b, result)
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
executeDynamicScript("add", 10, 20)
executeDynamicScript("multiply", 5, 6)
executeDynamicScript("power", 2, 8)
}
---
03.脚本安全
a.输入验证
验证脚本输入防止注入攻击。
b.沙箱执行
使用受限环境执行不受信任的代码。
c.安全示例
a.功能说明
在受限环境中安全执行Python代码。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import sys
restricted_builtins = {
'print': print,
'len': len,
'range': range,
'sum': sum,
}
def safe_exec(code_str):
try:
exec(code_str, {"__builtins__": restricted_builtins})
return "执行成功"
except Exception as e:
return f"执行失败: {str(e)}"
`)
mainModule := python3.PyImport_AddModule("__main__")
safeExec := python3.PyObject_GetAttrString(mainModule, "safe_exec")
defer safeExec.DecRef()
safeCode := "print(sum(range(10)))"
unsafeCode := "import os; os.system('ls')"
for _, code := range []string{safeCode, unsafeCode} {
args := python3.PyTuple_New(1)
python3.PyTuple_SetItem(args, 0, python3.PyUnicode_FromString(code))
result := safeExec.CallObject(args)
resultStr := python3.PyUnicode_AsUTF8(result)
fmt.Printf("代码: %s -> %s\n", code, resultStr)
result.DecRef()
args.DecRef()
}
}
---
6.6 常见问题
01.内存泄漏
a.引用计数错误
未正确DecRef导致对象无法释放。
b.检测方法
a.功能说明
使用Python gc模块检测内存泄漏。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
python3.PyRun_SimpleString(`
import gc
import sys
def check_memory():
gc.collect()
return len(gc.get_objects())
`)
mainModule := python3.PyImport_AddModule("__main__")
checkMem := python3.PyObject_GetAttrString(mainModule, "check_memory")
defer checkMem.DecRef()
emptyArgs := python3.PyTuple_New(0)
defer emptyArgs.DecRef()
beforeCount := checkMem.CallObject(emptyArgs)
beforeVal := python3.PyLong_AsLong(beforeCount)
beforeCount.DecRef()
for i := 0; i < 1000; i++ {
obj := python3.PyLong_FromGoInt(i)
obj.DecRef()
}
afterCount := checkMem.CallObject(emptyArgs)
afterVal := python3.PyLong_AsLong(afterCount)
afterCount.DecRef()
fmt.Printf("对象数 - 前: %d, 后: %d\n", beforeVal, afterVal)
}
---
02.GIL死锁
a.死锁原因
多个goroutine竞争GIL导致死锁。
b.避免策略
正确使用PyGILState_Ensure/Release和LockOSThread。
c.解决示例
a.功能说明
正确的多线程调用模式避免死锁。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"sync"
python3 "github.com/DataDog/go-python3"
)
func safeWorker(id int, wg *sync.WaitGroup) {
defer wg.Done()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
gilState := python3.PyGILState_Ensure()
defer python3.PyGILState_Release(gilState)
code := fmt.Sprintf(`
import time
time.sleep(0.001)
print("Worker %d done")
`, id)
python3.PyRun_SimpleString(code)
}
func main() {
runtime.LockOSThread()
python3.Py_Initialize()
defer python3.Py_Finalize()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go safeWorker(i, &wg)
}
wg.Wait()
fmt.Println("所有worker完成,无死锁")
}
---
03.类型转换错误
a.类型检查
调用前检查Python对象类型。
b.错误处理
转换失败时正确处理异常。
c.处理示例
a.功能说明
安全的类型转换与错误处理。
b.代码示例
---
package main
import (
"fmt"
python3 "github.com/DataDog/go-python3"
)
func safeConvertToInt(obj *python3.PyObject) (int, error) {
if !python3.PyLong_Check(obj) {
if python3.PyFloat_Check(obj) {
floatVal := python3.PyFloat_AsDouble(obj)
return int(floatVal), nil
}
return 0, fmt.Errorf("对象不是整数或浮点数")
}
return python3.PyLong_AsLong(obj), nil
}
func main() {
python3.Py_Initialize()
defer python3.Py_Finalize()
intObj := python3.PyLong_FromGoInt(42)
defer intObj.DecRef()
floatObj := python3.PyFloat_FromDouble(3.14)
defer floatObj.DecRef()
strObj := python3.PyUnicode_FromString("hello")
defer strObj.DecRef()
for i, obj := range []*python3.PyObject{intObj, floatObj, strObj} {
val, err := safeConvertToInt(obj)
if err != nil {
fmt.Printf("对象%d转换失败: %v\n", i, err)
} else {
fmt.Printf("对象%d转换成功: %d\n", i, val)
}
}
}
---
04.性能问题
a.频繁跨语言调用
减少Go-Python边界跨越次数。
b.批量处理
使用批量操作代替循环调用。