You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

配置被C++调用的Python文件:实现全局字典数据一次性加载复用

解决方案:单次初始化Python环境+类级数据共享

核心问题分析

你当前的C代码每次调用Python函数时,都会重复执行Py_Initialize()和Py_Finalize(),这意味着每次调用都会启动一个全新的Python解释器实例,之前加载的字典数据无法在多次调用间保留。要实现数据复用,必须让Python解释器在C程序生命周期内只初始化一次,同时Python端确保数据仅加载一次。

实现步骤

1. Python端:用类实现单例式数据加载

修改Python代码,让类的静态字典仅在首次访问时加载数据,后续所有方法直接复用该字典,同时补充缺失的特定物品计数函数:

import re
import string

class ItemCounter:
    # 类级静态字典,所有实例共享
    _item_counts = None

    @classmethod
    def _load_data(cls):
        # 仅在首次调用时加载文件
        if cls._item_counts is None:
            cls._item_counts = {}
            with open("CS210_Project_Three_Input_File.txt", "r") as text:
                for line in text:
                    line = line.strip().lower()
                    words = line.split()
                    for word in words:
                        cls._item_counts[word] = cls._item_counts.get(word, 0) + 1

    @classmethod
    def count_all_items(cls):
        cls._load_data()
        for key, value in cls._item_counts.items():
            print(f"{key}: {value}")

    @classmethod
    def count_specific_item(cls, item):
        cls._load_data()
        return cls._item_counts.get(item.lower(), 0)

2. C++端:全局初始化Python解释器

修改C++代码,在程序启动时初始化Python解释器,退出时才终结,所有Python调用共享同一个环境:

#include <Python.h>
#include <iostream>
#include <Windows.h>
#include <cmath>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

// 全局Python环境变量,所有函数共享
PyObject* g_pModule = nullptr;

// 初始化Python环境,仅调用一次
void InitPython() {
    Py_Initialize();
    g_pModule = PyImport_ImportModule("PythonCode");
    if (!g_pModule) {
        PyErr_Print();
        cerr << "Failed to load Python module" << endl;
    }
}

// 清理Python环境,程序退出时调用
void CleanupPython() {
    if (g_pModule) {
        Py_DECREF(g_pModule);
    }
    Py_Finalize();
}

// 调用无参数Python函数
void CallProcedure(string pName) {
    if (!g_pModule) return;

    PyObject* my_function = PyObject_GetAttrString(g_pModule, pName.c_str());
    if (my_function && PyCallable_Check(my_function)) {
        PyObject* my_result = PyObject_CallObject(my_function, NULL);
        Py_DECREF(my_result);
    } else {
        PyErr_Print();
    }
    Py_XDECREF(my_function);
}

// 调用带字符串参数的Python函数,返回int
int callIntFunc(string proc, string param) {
    if (!g_pModule) return 0;

    PyObject* pFunc = PyObject_GetAttrString(g_pModule, proc.c_str());
    if (!pFunc || !PyCallable_Check(pFunc)) {
        PyErr_Print();
        Py_XDECREF(pFunc);
        return 0;
    }

    PyObject* pValue = Py_BuildValue("(s)", param.c_str());
    PyObject* pResult = PyObject_CallObject(pFunc, pValue);
    Py_DECREF(pValue);
    Py_DECREF(pFunc);

    if (!pResult) {
        PyErr_Print();
        return 0;
    }

    int result = _PyLong_AsInt(pResult);
    Py_DECREF(pResult);
    return result;
}

// 原辅助函数保持不变
string nCharString(int t_length, char t_character) {
    string returnString;
    for (int i = 0; i < t_length; i++) {
        returnString += t_character;
    }
    return returnString;
}

bool checkIfDigitAndRange(string input, int lowEnd, int highEnd, int& choice) {
    if (isdigit(input[0])) {
        int temp = stoi(input);
        if (temp >= lowEnd && temp <= highEnd) {
            choice = temp;
            return true;
        } else {
            cout << "Out of range choice, try again!" << endl;
            return false;
        }
    }
    cout << "Digit was not entered, try again!" << endl;
    return false;
}

bool checkIfInputYesOrNo(char input) {
    return input == 'y' || input == 'Y';
}

void choiceOne() {
    cout << "List of quantity of each item purchased on a given day." << endl << nCharString(55, '-') << endl;
    CallProcedure("ItemCounter.count_all_items");
    cout << endl << "Would you like to rerun this program? Enter 'Y' for yes, enter anything else for no!" << endl;
}

void choiceTwo() {
    string itemToFind;
    cout << "Enter an item to see how much that item sold on a given day:" << endl;
    cin >> itemToFind;
    system("cls");
    cout << itemToFind << " was sold " << callIntFunc("ItemCounter.count_specific_item", itemToFind) << " times!" << endl;
}

void choiceThree() {
    cout << "Text-based histogram:" << endl << nCharString(55, '-') << endl;
    // 可添加Python端的直方图生成方法调用,例如:
    // CallProcedure("ItemCounter.generate_histogram");
}

int getMenuAndChoice() {
    char yOrNo;
    string input;
    while (true) {
        int choice = 0;
        cout << nCharString(78, '-') << endl;
        cout << "Choose an option, '1', '2', '3', or '4'" << endl;
        cout << "1: Produce list of number of times each item was purchased." << endl;
        cout << "2: Produce a number representing how many times a specific item was purchased." << endl;
        cout << "3: Produce a text-based histogram listing all items purchased." << endl;
        cout << "4: Exit Program." << endl;
        cout << nCharString(78, '-') << endl;
        cin >> input;
        system("cls");
        if (checkIfDigitAndRange(input, 1, 4, choice)) {
            if (choice == 1) {
                choiceOne();
                cin >> yOrNo;
                if (!checkIfInputYesOrNo(yOrNo))
                    break;
                system("cls");
            } else if (choice == 2) {
                choiceTwo();
                cin >> yOrNo;
                if (!checkIfInputYesOrNo(yOrNo))
                    break;
                system("cls");
            } else if (choice == 3) {
                choiceThree();
                cin >> yOrNo;
                if (!checkIfInputYesOrNo(yOrNo))
                    break;
                system("cls");
            } else {
                break;
            }
        }
    }
    return 0;
}

int main()
{
    InitPython();
    getMenuAndChoice();
    CleanupPython();
    return 0;
}

关键改动说明

  1. Python端:

    • 用ItemCounter类的静态变量_item_counts存储数据,通过_load_data类方法实现懒加载,仅在首次调用时读取文件。
    • 所有业务方法先调用_load_data,确保数据已加载完成。
    • 使用with语句管理文件,自动关闭文件,避免资源泄漏。
  2. C++端:

    • 新增全局变量g_pModule存储Python模块,在程序启动时初始化解释器并加载模块,退出时统一清理。
    • 移除每个调用函数中的重复初始化/终结逻辑,避免每次调用都重建Python环境。
    • 修改函数调用方式,直接通过类方法名调用Python逻辑。

效果验证

  • 首次调用任意菜单选项时,Python会读取文件并加载数据到字典。
  • 后续所有调用都会直接复用已加载的字典,不会重复读取文件。
  • C++程序全程仅初始化一次Python环境,性能更优。

内容的提问来源于stack exchange,提问作者Cole Baxendale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:25:26