游戏蛮牛学习群(纯技术交流,不闲聊):539178957
游戏蛮牛 手机端
开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:2286

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 309|回复: 2
发新帖

[小贱] [DotNetPy]C#、Python大融合之术(二)

[复制链接]  [移动端链接]
排名
1085
昨日变化
3

16

主题

160

帖子

2379

积分

Rank: 9Rank: 9Rank: 9

UID
14099
好友
23
蛮牛币
3050
威望
0
注册时间
2014-2-11
在线时间
629 小时
最后登录
2018-8-17

七夕浪漫情人专栏作家

跳转到指定楼层
楼主

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 佑丶小贱 于 2018-8-14 16:31 编辑

        前一篇文章简单的提了DotNetPy的设计思路、C++多python的调用方法,我对项目作了一个整理,从这篇文章开始,详细的讲述DotNetPy项目的开发。有兴趣的可以从https://gitee.com/Jianghy/DotNetPy中获取项目源码,和我一起开发完善该项目(更重要的是需要C++大佬指导)。
        以下是上篇文章已经提到的基础代码:
[C++] 纯文本查看 复制代码
// PyEngine.h
#pragma once
#include "Python.h"
#include <vector>
#include <algorithm>
#include <msclr/marshal_cppstd.h>

using namespace std;
using namespace System;
using namespace msclr::interop;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;

namespace DotNetPy {
public ref class PyEngine
        {
        public:
                PyEngine(void);
                ~PyEngine(void);

                // 初始化
                bool PyInitialize(void);
                // 检查状态
                bool PyIsInitialized(void);
                // 释放
                void PyFinalize(void);
                // 设置模块路径
                void PySetModulePath(String ^path);
                // 执行代码
                void PyExecuteString(String ^code);
                // 加载模块
                bool PyImportModule(String ^moduleName);
                // 加载函数
                bool PyImportFunc(String ^moduleName, String ^funcName);
                // 调用函数
                Object^ PyCallFunc(String ^funcName, Array ^args);
                // 调用函数
                Object^ PyCallFuncFromModule(String ^moduleName, String ^funcName, Array ^args);
        private
                // 参数类型转换 String^转std::string
                string String2string(String ^str);
                // 参数类型转换 char*转String^
                String^ Char2String(char *ch)
        };
}


[C++] 纯文本查看 复制代码
// PyEngine.cpp
#include "stdafx.h"
#include "PyEngine.h"

namespace DotNetPy {
        PyEngine::PyEngine(void) {}
        PyEngine::~PyEngine(void) {}

        string PyEngine::String2string(String ^str) {
                string stdString = marshal_as<string>(str);
                return stdString;
        }

        String^ PyEngine::Char2String(char *ch) {
                String ^string = marshal_as<String^>(ch);
                return string;
        }

        bool PyEngine::PyInitialize(void) {
                Py_Initialize();
                if (Py_IsInitialized() == 0)
                        return false;
                return true;
        }

        bool PyEngine::PyIsInitialized(void) {
                if (Py_IsInitialized() == 0)
                        return false;
                return true;
        }

        void PyEngine::PyFinalize(void) {
                Py_Finalize();
        }

        void PyEngine::PySetModulePath(String ^path) {
                PyRun_SimpleString("import sys,os");
                if (path) {
                        string pathCode = "sys.path.append(r'";
                        string pathString = String2string(path);
                        pathCode += pathString + "')";
                        PyRun_SimpleString(pathCode.data());
                }
                else
                {
                        PyRun_SimpleString("sys.path.append(os.getcwd())");
                }
        }

        void PyEngine::PyExecuteString(String ^code) {
                string codeString = String2string(code);
                PyRun_SimpleString(codeString.data());
        }
}
生成dll后,我们再C#脚本中可以这样使用:
[C#] 纯文本查看 复制代码
// C#
using System;
using DotNetPy; // 引用DLL

namespace CsConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            PyEngine pyEngine = new PyEngine();
            if (pyEngine.PyInitialize()) // 初始化PyEngine
            {
                pyEngine.PyExecuteString("print('Hello World')");
            }
            pyEngine.PyFinalize();
            Console.ReadLine();
        }
    }
}
Hello World已实现,我们应该进一步实现对python的操作。 聪明的你一定发现了,光打印个字太简单了,我要传参数,我要返回值!ok,今天就讲。以配置模块路径为例,使用过python的同学应该知道,python中import有个搜索路径,就是你导入某个模块的时候,它得去一些文件夹中查找是不是有这个模块。我们通常可以使用“sys.path”来查看这些路径:
[C++] 纯文本查看 复制代码
using System;
using DotNetPy;

namespace CsConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            PyEngine pyEngine = new PyEngine();
            if (pyEngine.PyInitialize()) // 初始化PyEngine
            {
                pyEngine.PyExecuteString("import sys");
                pyEngine.PyExecuteString("print(sys.path)");
}
            pyEngine.PyFinalize();
            Console.ReadLine();
        }
    }
}



我们的目标就是在这个path中添加我们自定义的一个路径,我们定义void PySetModulePath(String ^path);path就是我们自定义的路径,PySetModulePath的具体实现如下:
[C++] 纯文本查看 复制代码
void PyEngine::PySetModulePath(String ^path) {
                PyRun_SimpleString("import sys,os"); // 导入sys和os
                if (path) {
                        string pathCode = "sys.path.append(r'";
                        string pathString = String2string(path);
                        pathCode += pathString + "')"; // 拼接命令
                        PyRun_SimpleString(pathCode.data());
                }
                else
                {
                        PyRun_SimpleString("sys.path.append(os.getcwd())"); // 若参数为null则,添加当前路径
                }
        }
        这段代码很简单,但重点不是如何执行了python脚本,而是C#中的System.String如何转成C++中的std::string再转成python需要的char*。当C#中的string作为参数传入C++中定义的函数中,因为有CLR的加持,在C++中是以System::String^的类型存在的。你可以看作两个是一样的,那System::String^如何转换成std::string呢?我们引用了msclr/marshal_cppstd.h中的marshal_as<outputType>(input)函数,它还可以转换哪些类型可以在https://msdn.microsoft.com/zh-cn/library/bb384865.aspx中查询。当转成std::string后,使用.data()就可以得到char*了。这里提到的类型转换只是该项目中最基础的一部分,之后的开发中会有更多复杂的转换,比如C#使用什么类型去对应python中的tuple。现在我们可以使用PySetModulePath来添加新的模块路径了:
[C++] 纯文本查看 复制代码
using System;
using DotNetPy;

namespace CsConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            PyEngine pyEngine = new PyEngine();
            if (pyEngine.PyInitialize()) // 初始化PyEngine
            {
                pyEngine.PySetModulePath(@"D:\Module"); // null 默认当前路径否则填绝对路径
                pyEngine.PyExecuteString("print(sys.path)");
}
            pyEngine.PyFinalize();
            Console.ReadLine();
        }
    }
}




这样自定义的路径就被添加到python的搜索路径中了。了解了参数的传递,下一篇文章我们会讲如何获取python的返回值。






回复

使用道具 举报

7日久生情
1645/5000
排名
3632
昨日变化
14

0

主题

995

帖子

1645

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
189581
好友
0
蛮牛币
2221
威望
0
注册时间
2016-12-5
在线时间
276 小时
最后登录
2018-8-17
沙发
发表于 3 天前 | 只看该作者
可以的给力的

回复

使用道具 举报

5熟悉之中
620/1000
排名
7940
昨日变化
5

0

主题

372

帖子

620

积分

Rank: 5Rank: 5

UID
254705
好友
0
蛮牛币
520
威望
0
注册时间
2017-11-16
在线时间
106 小时
最后登录
2018-8-15
板凳
发表于 3 天前 | 只看该作者
666666666666666666666666666666666
[发帖际遇]: 15234084053 在论坛发帖时没有注意,被小偷偷去了 1 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表