Skip to content

Delphi中的Python代码生成

在Delphi应用程序中集成Python的能力,为开发者提供了强大的扩展性和灵活性。本文将详细介绍如何在Delphi中实现动态生成Python代码并执行的功能。

前言

随着人工智能和数据科学的快速发展,Python已成为这些领域的主导语言。而Delphi作为一款高效的应用程序开发工具,如果能够与Python无缝集成,将为开发者带来巨大的便利。通过Python for Delphi (P4D)库,我们可以在Delphi应用中嵌入Python解释器,实现两种语言的优势互补。

环境准备

安装Python

首先,需要在系统中安装Python。建议使用Python 3.6或更高版本,可以从Python官网下载并安装。

安装Python for Delphi

Python for Delphi (P4D)是连接Delphi和Python的桥梁。安装步骤如下:

  1. 从GitHub下载最新版本的P4D:https://github.com/pyscripter/python4delphi
  2. 解压下载的文件
  3. 在Delphi中,选择"组件" > "安装包",浏览到P4D目录下的相应包文件
  4. 编译并安装组件

基本架构设计

在实现Python代码生成功能时,我们需要考虑以下几个方面:

  1. 用户界面:允许用户输入参数或选择选项
  2. 代码生成器:根据用户输入生成Python代码
  3. Python执行引擎:执行生成的代码并返回结果
  4. 结果展示:将执行结果展示给用户

实现步骤

1. 创建基本界面

首先,我们需要创建一个基本的用户界面,包含以下元素:

  • 参数输入区域(如文本框、下拉列表等)
  • 生成代码按钮
  • 代码预览区域
  • 执行代码按钮
  • 结果显示区域
procedure TForm1.FormCreate(Sender: TObject);
begin
  // 初始化界面
  Memo1.Lines.Clear;  // 代码预览区
  Memo2.Lines.Clear;  // 结果显示区

  // 初始化Python引擎
  PythonEngine1.LoadDll;
end;

2. 实现代码生成逻辑

根据用户输入的参数,动态生成Python代码:

procedure TForm1.btnGenerateCodeClick(Sender: TObject);
var
  PythonCode: TStringList;
  Param1, Param2: string;
begin
  PythonCode := TStringList.Create;
  try
    // 获取用户输入
    Param1 := Edit1.Text;
    Param2 := Edit2.Text;

    // 生成Python代码
    PythonCode.Add('# 自动生成的Python代码');
    PythonCode.Add('import numpy as np');
    PythonCode.Add('import matplotlib.pyplot as plt');
    PythonCode.Add('');
    PythonCode.Add(Format('x = np.linspace(0, %s, 100)', [Param1]));
    PythonCode.Add(Format('y = np.sin(%s * x)', [Param2]));
    PythonCode.Add('');
    PythonCode.Add('plt.figure(figsize=(10, 6))');
    PythonCode.Add('plt.plot(x, y)');
    PythonCode.Add('plt.title("Sin Wave")');
    PythonCode.Add('plt.grid(True)');
    PythonCode.Add('plt.savefig("sin_wave.png")');
    PythonCode.Add('');
    PythonCode.Add('result = {"max_value": float(np.max(y)), "min_value": float(np.min(y))}');
    PythonCode.Add('print(result)');

    // 显示生成的代码
    Memo1.Lines.Assign(PythonCode);
  finally
    PythonCode.Free;
  end;
end;

3. 执行生成的Python代码

使用P4D提供的功能执行生成的Python代码:

procedure TForm1.btnExecuteCodeClick(Sender: TObject);
var
  PythonCode: string;
begin
  // 获取代码
  PythonCode := Memo1.Text;

  // 清空结果区域
  Memo2.Lines.Clear;

  try
    // 执行Python代码
    PythonEngine1.ExecString(PythonCode);

    // 获取执行结果
    Memo2.Lines.Add('执行成功!');

    // 如果生成了图像,显示图像
    if FileExists('sin_wave.png') then
    begin
      Image1.Picture.LoadFromFile('sin_wave.png');
      Memo2.Lines.Add('图像已生成,请查看。');
    end;

    // 获取Python变量
    with PythonEngine1.PyEval_GetGlobals do
    begin
      if VariableExists('result') then
      begin
        Memo2.Lines.Add('计算结果:');
        Memo2.Lines.Add('最大值: ' + VarToStr(GetVariable('result')['max_value']));
        Memo2.Lines.Add('最小值: ' + VarToStr(GetVariable('result')['min_value']));
      end;
    end;
  except
    on E: Exception do
    begin
      Memo2.Lines.Add('执行错误:');
      Memo2.Lines.Add(E.Message);
    end;
  end;
end;

4. 处理Python依赖

为了确保生成的Python代码能够正确执行,我们需要处理Python依赖:

procedure TForm1.CheckPythonDependencies;
var
  PipInstallCmd: string;
begin
  // 检查并安装必要的Python包
  PipInstallCmd := 
    'import sys, subprocess;' +
    'packages = ["numpy", "matplotlib"];' +
    'for package in packages:' +
    '    try:' +
    '        __import__(package)' +
    '        print(f"{package} 已安装")' +
    '    except ImportError:' +
    '        print(f"正在安装 {package}...")' +
    '        subprocess.check_call([sys.executable, "-m", "pip", "install", package])' +
    '        print(f"{package} 安装完成")';

  try
    PythonEngine1.ExecString(PipInstallCmd);
  except
    on E: Exception do
      ShowMessage('依赖检查失败: ' + E.Message);
  end;
end;

高级功能

模板系统

为了使代码生成更加灵活,我们可以实现一个模板系统:

procedure TForm1.LoadTemplates;
var
  TemplateDir: string;
  SearchRec: TSearchRec;
  TemplateFiles: TStringList;
begin
  TemplateDir := ExtractFilePath(Application.ExeName) + 'Templates\';
  TemplateFiles := TStringList.Create;
  try
    if DirectoryExists(TemplateDir) then
    begin
      if FindFirst(TemplateDir + '*.py', faAnyFile, SearchRec) = 0 then
      begin
        repeat
          TemplateFiles.Add(SearchRec.Name);
        until FindNext(SearchRec) <> 0;
        FindClose(SearchRec);
      end;
    end;

    // 将模板添加到下拉列表
    ComboBoxTemplates.Items.Assign(TemplateFiles);
    if ComboBoxTemplates.Items.Count > 0 then
      ComboBoxTemplates.ItemIndex := 0;
  finally
    TemplateFiles.Free;
  end;
end;

procedure TForm1.ComboBoxTemplatesChange(Sender: TObject);
var
  TemplatePath: string;
  TemplateContent: TStringList;
begin
  if ComboBoxTemplates.ItemIndex >= 0 then
  begin
    TemplatePath := ExtractFilePath(Application.ExeName) + 'Templates\' + ComboBoxTemplates.Text;
    if FileExists(TemplatePath) then
    begin
      TemplateContent := TStringList.Create;
      try
        TemplateContent.LoadFromFile(TemplatePath);
        Memo1.Lines.Assign(TemplateContent);
      finally
        TemplateContent.Free;
      end;
    end;
  end;
end;

参数替换

实现参数替换功能,使模板更加通用:

function TForm1.ReplaceParameters(const Template: string): string;
var
  Result: string;
begin
  Result := Template;

  // 替换参数
  Result := StringReplace(Result, '{{PARAM1}}', Edit1.Text, [rfReplaceAll]);
  Result := StringReplace(Result, '{{PARAM2}}', Edit2.Text, [rfReplaceAll]);
  Result := StringReplace(Result, '{{DATE}}', FormatDateTime('yyyy-mm-dd', Now), [rfReplaceAll]);
  Result := StringReplace(Result, '{{TIME}}', FormatDateTime('hh:nn:ss', Now), [rfReplaceAll]);

  // 返回替换后的结果
  Result := Result;
end;

procedure TForm1.btnApplyParametersClick(Sender: TObject);
begin
  Memo1.Text := ReplaceParameters(Memo1.Text);
end;

实际应用案例

数据分析应用

创建一个简单的数据分析应用,允许用户上传CSV文件并生成分析报告:

procedure TForm1.btnAnalyzeDataClick(Sender: TObject);
var
  PythonCode: TStringList;
  CSVPath: string;
begin
  if OpenDialog1.Execute then
  begin
    CSVPath := OpenDialog1.FileName;
    PythonCode := TStringList.Create;
    try
      // 生成数据分析代码
      PythonCode.Add('import pandas as pd');
      PythonCode.Add('import matplotlib.pyplot as plt');
      PythonCode.Add('import seaborn as sns');
      PythonCode.Add('');
      PythonCode.Add(Format('df = pd.read_csv("%s")', [StringReplace(CSVPath, '\', '\\', [rfReplaceAll])]));
      PythonCode.Add('');
      PythonCode.Add('# 基本统计信息');
      PythonCode.Add('stats = df.describe().to_dict()');
      PythonCode.Add('');
      PythonCode.Add('# 生成图表');
      PythonCode.Add('plt.figure(figsize=(12, 8))');
      PythonCode.Add('for i, col in enumerate(df.select_dtypes(include=["float64", "int64"]).columns):');
      PythonCode.Add('    plt.subplot(2, 3, i+1)');
      PythonCode.Add('    sns.histplot(df[col], kde=True)');
      PythonCode.Add('    plt.title(f"Distribution of {col}")');
      PythonCode.Add('plt.tight_layout()');
      PythonCode.Add('plt.savefig("data_analysis.png")');
      PythonCode.Add('');
      PythonCode.Add('# 相关性分析');
      PythonCode.Add('corr = df.corr().to_dict()');
      PythonCode.Add('');
      PythonCode.Add('# 返回结果');
      PythonCode.Add('result = {"stats": stats, "corr": corr}');
      PythonCode.Add('print("Analysis completed!")');

      // 显示生成的代码
      Memo1.Lines.Assign(PythonCode);
    finally
      PythonCode.Free;
    end;
  end;
end;

机器学习模型生成器

创建一个简单的机器学习模型生成器:

procedure TForm1.btnGenerateMLModelClick(Sender: TObject);
var
  PythonCode: TStringList;
  ModelType, Dataset: string;
begin
  // 获取用户选择
  ModelType := ComboBoxModelType.Text;  // 例如:'RandomForest', 'SVM', 'NeuralNetwork'
  Dataset := ComboBoxDataset.Text;      // 例如:'iris', 'digits', 'wine'

  PythonCode := TStringList.Create;
  try
    // 生成机器学习模型代码
    PythonCode.Add('from sklearn import datasets, model_selection, metrics');
    PythonCode.Add('import numpy as np');
    PythonCode.Add('import matplotlib.pyplot as plt');

    // 加载数据集
    PythonCode.Add('');
    PythonCode.Add(Format('# 加载%s数据集', [Dataset]));
    case Dataset of
      'iris': PythonCode.Add('data = datasets.load_iris()');
      'digits': PythonCode.Add('data = datasets.load_digits()');
      'wine': PythonCode.Add('data = datasets.load_wine()');
    end;
    PythonCode.Add('X = data.data');
    PythonCode.Add('y = data.target');

    // 数据分割
    PythonCode.Add('');
    PythonCode.Add('# 数据分割');
    PythonCode.Add('X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.3, random_state=42)');

    // 模型选择和训练
    PythonCode.Add('');
    PythonCode.Add(Format('# 创建%s模型', [ModelType]));
    case ModelType of
      'RandomForest':
        begin
          PythonCode.Add('from sklearn.ensemble import RandomForestClassifier');
          PythonCode.Add('model = RandomForestClassifier(n_estimators=100, random_state=42)');
        end;
      'SVM':
        begin
          PythonCode.Add('from sklearn.svm import SVC');
          PythonCode.Add('model = SVC(kernel="rbf", C=1.0, gamma="scale", random_state=42)');
        end;
      'NeuralNetwork':
        begin
          PythonCode.Add('from sklearn.neural_network import MLPClassifier');
          PythonCode.Add('model = MLPClassifier(hidden_layer_sizes=(100,), max_iter=300, random_state=42)');
        end;
    end;

    // 训练和评估
    PythonCode.Add('');
    PythonCode.Add('# 训练模型');
    PythonCode.Add('model.fit(X_train, y_train)');
    PythonCode.Add('');
    PythonCode.Add('# 模型评估');
    PythonCode.Add('y_pred = model.predict(X_test)');
    PythonCode.Add('accuracy = metrics.accuracy_score(y_test, y_pred)');
    PythonCode.Add('report = metrics.classification_report(y_test, y_pred)');

    // 可视化结果
    PythonCode.Add('');
    PythonCode.Add('# 结果可视化');
    PythonCode.Add('plt.figure(figsize=(10, 6))');
    PythonCode.Add('cm = metrics.confusion_matrix(y_test, y_pred)');
    PythonCode.Add('plt.imshow(cm, interpolation="nearest", cmap=plt.cm.Blues)');
    PythonCode.Add('plt.title("Confusion Matrix")');
    PythonCode.Add('plt.colorbar()');
    PythonCode.Add('plt.tight_layout()');
    PythonCode.Add('plt.savefig("confusion_matrix.png")');

    // 返回结果
    PythonCode.Add('');
    PythonCode.Add('# 返回结果');
    PythonCode.Add('result = {');
    PythonCode.Add('    "accuracy": float(accuracy),');
    PythonCode.Add('    "report": report,');
    PythonCode.Add('    "model_type": "' + ModelType + '",');
    PythonCode.Add('    "dataset": "' + Dataset + '"');
    PythonCode.Add('}');
    PythonCode.Add('print(f"Model accuracy: {accuracy:.4f}")');

    // 显示生成的代码
    Memo1.Lines.Assign(PythonCode);
  finally
    PythonCode.Free;
  end;
end;

总结

通过Delphi和Python的结合,我们可以创建功能强大的应用程序,既利用了Delphi在GUI开发和系统集成方面的优势,又充分发挥了Python在数据处理、机器学习和科学计算等领域的强大能力。

动态生成Python代码的方法,为Delphi应用程序提供了极大的灵活性和扩展性,使得开发者可以根据用户需求,动态生成和执行Python代码,实现更加复杂和智能的功能。

希望本文能够帮助您在Delphi应用中成功集成Python功能,创建更加强大和灵活的应用程序。