简体   繁体   English

在C#中实例化python类

[英]Instantiating a python class in C#

I've written a class in python that I want to wrap into a .net assembly via IronPython and instantiate in a C# application. 我在python中编写了一个类,我希望通过IronPython将其包装到.net程序集中并在C#应用程序中实例化。 I've migrated the class to IronPython, created a library assembly and referenced it. 我已经将类迁移到IronPython,创建了一个库程序集并引用它。 Now, how do I actually get an instance of that class? 现在,我如何实际获得该类的实例?

The class looks (partially) like this: 该类看起来(部分)像这样:

class PokerCard:
    "A card for playing poker, immutable and unique."

    def __init__(self, cardName):

The test stub I wrote in C# is: 我在C#中编写的测试存根是:

using System;

namespace pokerapp
{
    class Program
    {
        static void Main(string[] args)
        {
            var card = new PokerCard(); // I also tried new PokerCard("Ah")
            Console.WriteLine(card.ToString());
            Console.ReadLine();
        }
    }
}

What do I have to do in order to instantiate this class in C#? 为了在C#中实例化这个类,我该怎么办?

IronPython classes are not .NET classes. IronPython类不是 .NET类。 They are instances of IronPython.Runtime.Types.PythonType which is the Python metaclass. 它们是IronPython.Runtime.Types.PythonType的实例,它是Python元类。 This is because Python classes are dynamic and support addition and removal of methods at runtime, things you cannot do with .NET classes. 这是因为Python类是动态的,并且支持在运行时添加和删除方法,这是.NET类无法做到的。

To use Python classes in C# you will need to use the ObjectOperations class. 要在C#中使用Python类,您需要使用ObjectOperations类。 This class allows you to operate on python types and instances in the semantics of the language itself. 该类允许您在语言本身的语义中操作python类型和实例。 eg it uses the magic methods when appropriate, auto-promotes integers to longs etc. You can find out more about ObjectOperations by looking at the source or using reflector. 例如,它在适当时使用魔术方法,自动将整数提升为long等。您可以通过查看源或使用反射器来了解有关ObjectOperations的更多信息。

Here is an example. 这是一个例子。 Calculator.py contains a simple class: Calculator.py包含一个简单的类:

class Calculator(object):
    def add(self, a, b):
        return a + b

You can use it from your pre .NET 4.0 C# code like this: 您可以在.NET 4.0 C#代码中使用它,如下所示:

ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();

ObjectOperations op = engine.Operations;

source.Execute(scope); // class object created
object klaz = scope.GetVariable("Calculator"); // get the class object
object instance = op.Call(klaz); // create the instance
object method = op.GetMember(instance, "add"); // get a method
int result = (int)op.Call(method, 4, 5); // call method and get result (9)

You will need to reference the assemblies IronPython.dll, Microsoft.Scripting and Microsoft.Scripting.Core. 您需要引用程序集IronPython.dll,Microsoft.Scripting和Microsoft.Scripting.Core。

C# 4 made this much easier with the new dynamic type. C#4使用新的动态类型使这变得更容易。

ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);

dynamic Calculator = scope.GetVariable("Calculator");
dynamic calc = Calculator();
int result = calc.add(4, 5);

If you are using Visual Studio 2010 or later with NuGet support simply execute this to download and reference the appropriate libraries. 如果您正在使用Visual Studio 2010或更高版本支持NuGet,只需执行此操作即可下载并引用相应的库。

Install-Package IronPython

Now that .Net 4.0 is released and has the dynamic type, this example should be updated. 现在.Net 4.0已经发布并具有动态类型,因此应该更新此示例。 Using the same python file as in m-sharp's original answer: 使用与m-sharp原始答案相同的python文件:

class Calculator(object):
    def add(self, a, b):
        return a + b

Here is how you would call it using .Net 4.0: 以下是使用.Net 4.0调用它的方法:

string scriptPath = "Calculator.py";
ScriptEngine engine = Python.CreateEngine();
engine.SetSearchPaths(new string[] {"Path to your lib's here. EG:", "C:\\Program Files (x86)\\IronPython 2.7.1\\Lib"});
ScriptSource source = engine.CreateScriptSourceFromFile(scriptPath);
ScriptScope scope = engine.CreateScope();
ObjectOperations op = engine.Operations;
source.Execute(scope);

dynamic Calculator = scope.GetVariable("Calculator");
dynamic calc = Calculator();
return calc.add(x,y);          

Again, you need to add references to IronPython.dll and Microsoft.Scripting. 同样,您需要添加对IronPython.dll和Microsoft.Scripting的引用。

As you can see, the initial setting up and creating of the source file is the same. 如您所见,源文件的初始设置和创建是相同的。

But once the source is succesfully executed, working with the python functions is far easier thanks to the new "dynamic" keyword. 但是一旦源成功执行,由于新的“动态”关键字,使用python函数会更容易。

I am updating the above example provided by Clever Human for compiled IronPython classes (dll) instead of IronPython source code in a .py file. 我正在更新Clever Human为编译的IronPython类(dll)提供的上述示例,而不是.py文件中的IronPython源代码。

# Compile IronPython calculator class to a dll
clr.CompileModules("calculator.dll", "calculator.py")

C# 4.0 code with the new dynamic type is as follows: 具有新动态类型的C#4.0代码如下:

// IRONPYTHONPATH environment variable is not required. Core ironpython dll paths should be part of operating system path.
ScriptEngine pyEngine = Python.CreateEngine();
Assembly myclass = Assembly.LoadFile(Path.GetFullPath("calculator.dll"));
pyEngine.Runtime.LoadAssembly(myclass);
ScriptScope pyScope = pyEngine.Runtime.ImportModule("calculator");
dynamic Calculator = pyScope.GetVariable("Calculator");
dynamic calc = Calculator();
int result = calc.add(4, 5);

References: 参考文献:

  1. Using Compiled Python Classes from .NET/CSharp IP 2.6 使用.NET / CSharp IP 2.6中的编译Python类
  2. Static Compilation of IronPython scripts IronPython脚本的静态编译

I have searched high and low and I am afraid that there does not seem to be much information pertaining to this. 我已经搜索过高低,我担心似乎没有太多关于此的信息。 I am pretty much certain that no one has devised a way to do this in the clean manner that you would like. 我很确定没有人设计出一种方法,以你想要的干净方式做到这一点。

The main reason I think this is a problem is that in order to see the PokerCard type in your C# application you would have to compile your Python code to IL. 我认为这是一个问题的主要原因是,为了在你的C#应用​​程序中看到PokerCard类型,你必须将你的Python代码编译成IL。 I don't believe that there are any Python -> IL compilers out there. 我不相信有任何Python -> IL编译器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM