配置被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; }
关键改动说明
Python端:
- 用
ItemCounter类的静态变量_item_counts存储数据,通过_load_data类方法实现懒加载,仅在首次调用时读取文件。 - 所有业务方法先调用
_load_data,确保数据已加载完成。 - 使用
with语句管理文件,自动关闭文件,避免资源泄漏。
- 用
C++端:
- 新增全局变量
g_pModule存储Python模块,在程序启动时初始化解释器并加载模块,退出时统一清理。 - 移除每个调用函数中的重复初始化/终结逻辑,避免每次调用都重建Python环境。
- 修改函数调用方式,直接通过类方法名调用Python逻辑。
- 新增全局变量
效果验证
- 首次调用任意菜单选项时,Python会读取文件并加载数据到字典。
- 后续所有调用都会直接复用已加载的字典,不会重复读取文件。
- C++程序全程仅初始化一次Python环境,性能更优。
内容的提问来源于stack exchange,提问作者Cole Baxendale
相关产品推荐
相关产品推荐

