C#调用Python3(在Visual Studio 2022 中基于.NET 6.0框架调用Python3.9代码)

  • Post author:
  • Post category:python



这两天基于CSDN【码客巅云】转载的【C#调用python脚本样例】进行学习,过程中遇到不少坑,折腾了好久,改了不少代码和配置才避坑成功。想到大家,特别是初学者可能也会遇到这些问题,特分享复盘如下。期望能帮助大家。






1.工具环境


环境和工具。

  • Visual Studio 2022
  • 框架:.NET 6.0
  • 依赖NuGet包:ironPython 2.7.11
  • 运行环境:Python 3.9 64位


提示:以下是本篇文章正文内容,下面案例可供参考



2.创建C#项目

使用console控制台应用

在这里插入图片描述

使用.NET6.0

在这里插入图片描述



3.安装ironPython

通过NuGet在线安装【ironPython 2.7.11】。


切记!!!不要安装【预发行版】


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

最终在依赖项中看到已下载好的ironPython

在这里插入图片描述



4.Python代码文件

创建一个英文文件夹【PythonCodeFile】用于存放Python的代码文件

在这里插入图片描述

打开Python代码文件所在文件夹,拖动至资源管理器中【PythonCodeFile】文件夹上方,文件会自动复制到项目目录下。

在这里插入图片描述

在这里插入图片描述



5.创建类

一共要创建两个类:

  • 一个是用于存放数据对象的类【DateObjectTest.cs】
  • 另一个是用来调用Python代码的执行类【RunPython.cs】


引用都是:

using System;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;



5.1.类【DateObjectTest.cs】代码


代码如下(示例),命名空间大家记得改成自己的:

using System;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

namespace ConsoleAppRunPythonCode001
{
    public class DataObjectTest
    {
        public DataObjectTest(string userName, int age, string desc)
        {
            UserName = userName;
            Age = age;
            Desc = desc;
        }

        /// <summary>
        /// 属性:姓名
        /// </summary>
        public string UserName { set; get; }
        /// <summary>
        /// 属性:年龄
        /// </summary>
        public int Age { set; get; }
        /// <summary>
        /// 属性:描述
        /// </summary>
        public string Desc { set; get; }


        public void AddAge(int age)
        {
            this.Age += age;
            this.Desc = String.Format("{0}长大了{1}岁(from C#)", this.UserName, age);
        }
        public override string ToString()
        {
            return String.Format("姓名:{0}; 年龄:{1}; 描述:{2}", this.UserName, this.Age, this.Desc);
        }
    }
}



5.2.类【RunPython.cs】代码


代码如下(示例),命名空间大家记得改成自己的:

using System;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

namespace ConsoleAppRunPythonCode001
{
    internal class RunPython
    {

        public void RunPythonTest()
        {
            // 加载外部 python 脚本文件.
            ScriptRuntime pyRumTime = Python.CreateRuntime();
            dynamic obj = pyRumTime.UseFile(@"E:\MyPython\ConsoleAppRunPythonCode001\ConsoleAppRunPythonCode001\PythonCodeFile\TestPythonFile.py");

            // ==================================================
            // 简单调用脚本文件中的方法.
            Console.WriteLine(obj.welcome("Test C# Call Python."));
            Console.WriteLine(obj.welcome("测试中文看看是否正常!"));

            // ==================================================
            // 测试自定义对象.
            DataObjectTest testObj = new DataObjectTest("张三", 20, "");


            Console.WriteLine("调用脚本前对象数据:{0}", testObj);
            obj.testAddAge(testObj);
            Console.WriteLine("调用 testAddAge 脚本后,对象数据={0}", testObj);
            obj.testAddAge2(testObj);
            Console.WriteLine("调用 testAddAge2 脚本后,对象数据={0}", testObj);


            // ==================================================
            // 测试 List.
            IronPython.Runtime.List testList = new IronPython.Runtime.List();
            testList.Add("List数据1");
            testList.Add("List数据2");
            testList.Add("List数据3");
            // 测试参数为 List.
            string result = obj.testList(testList);
            Console.WriteLine("调用 testList , 返回结果:{0}", result);

            // ==================================================
            // 测试 Set.
            IronPython.Runtime.SetCollection testSet = new IronPython.Runtime.SetCollection();
            testSet.add("Set数据1");
            testSet.add("Set数据2");
            testSet.add("Set数据3");
            // 测试参数为 Set.
            result = obj.testSet(testSet);
            Console.WriteLine("调用 testSet , 返回结果:{0}", result);

            // ==================================================
            // 测试 Dictionary.
            IronPython.Runtime.PythonDictionary testDictionary = new IronPython.Runtime.PythonDictionary();
            testDictionary["Key1"] = "Value1";
            testDictionary["Key2"] = "Value2";
            testDictionary["Key3"] = "Value3";
            // 测试参数为 Dictionary.
            result = obj.testDictionary(testDictionary);
            Console.WriteLine("调用 testDictionary , 返回结果:{0}", result);
            Console.ReadLine();
        }
    }
}

【RunPython.cs】代码中需要修改Python文档的目录

复制Python代码文件的完整路径,设置【RunPython.cs】中的目录

在这里插入图片描述

在这里插入图片描述



5.3.编辑启动类【Program.cs】

记得必须在第一行,引用当前项目的命名空间,否则将无法调用

using ConsoleAppRunPythonCode001;//记得必须在第一行,引用当前项目的命名空间,否则将无法调用。名字请改成自己的。

// See https://aka.ms/new-console-template for more information
//Console.WriteLine("Hello, World!");

Console.WriteLine("开始执行Python脚本");
RunPython RunPython = new RunPython();
RunPython.RunPythonTest();



6.最后运行试试

在这里插入图片描述

正确的运行结果

开始执行Python脚本
hello (from Python) Test C# Call Python.
hello Test C# Call Python.
hello (from Python) 测试中文看看是否正常!
hello 测试中文看看是否正常!
调用脚本前对象数据:姓名:张三; 年龄:20; 描述:
张三 又大了一岁,测试是否中文乱码(from Python)
调用 testAddAge 脚本后,对象数据=姓名:张三; 年龄:21; 描述:张三 又大了一岁,测试是否中文乱码(from Python)
调用 testAddAge2 脚本后,对象数据=姓名:张三; 年龄:23; 描述:张三长大了2岁(from C#)
调用 testList , 返回结果: List数据1 List数据2 List数据3
调用 testSet , 返回结果: Set数据2 Set数据1 Set数据3
调用 testDictionary , 返回结果: Key1=Value1; Key3=Value3; Key2=Value2;



7.问题报错处理



7.1.异常object has no attribute

如果出现【System.MissingMemberException:“‘DataObjectTest’ object has no attribute ‘Age’”】,那是因为存放数据对象的类【DateObjectTest.cs】使用了默认的【internal】而不能被外部Python程序访问(即不能访问目标类)。需要修改访问修饰符为【public】。

在这里插入图片描述

类【DateObjectTest.cs】中修改

在这里插入图片描述



7.2.来自Python的输出出现中文乱码

请参考我的另一篇文章【C#调用Python中文乱码问题处理】


C#调用Python3中文乱码问题处理(在Visual Studio 2022 中基于.NET 6.0框架调用Python3.9代码)



8.Python代码

# -*- coding: utf-8 -*-
# 第一行的目的,是为了让代码里面,可以有中文信息. (will否则要运行报错)
# 这个 Python 脚本, 用于被 C# 来调用.

def welcome(name):
    print "hello (from Python) " + name
    return "hello " + name

# 测试 参数为 C# 对象的效果. (获取/设置 C# 对象的属性)
def testAddAge(obj):
    obj.Age = obj.Age + 1
    obj.Desc = obj.UserName + " 又大了一岁,测试是否中文乱码(from Python)"
    print obj.Desc

# 测试 参数为 C# 对象的效果. (调用 C# 对象的方法)
def testAddAge2(obj):
    obj.AddAge(2)

# 测试 List.
def testList(lst):
    vResult = ""
    for each_item in lst:
        vResult = vResult + " " + each_item
    return vResult
# 测试 Set.
def testSet(pSet):
    vResult = ""
    for each_item in pSet:
        vResult = vResult + " " + each_item
    return vResult

# 测试 Dictionary
def testDictionary(pDictionary):
    vResult = ""
    for each_item in pDictionary:
        vResult = vResult + " " + each_item + "=" + pDictionary[each_item] + ";"
    return vResult

最后可参考


C#调用Python3中文乱码问题处理(在Visual Studio 2022 中基于.NET 6.0框架调用Python3.9代码)



版权声明:本文为weixin_39401430原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。