2009-02-23 13 views
40

Escribí una clase en python que quiero envolver en un ensamblado .net a través de IronPython y crear instancias en una aplicación C#. Migré la clase a IronPython, creé un conjunto de biblioteca y lo referenciaba. Ahora, ¿cómo obtengo una instancia de esa clase?Crear una instancia de una clase python en C#

Las miradas de clase (parcialmente) como este:

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

    def __init__(self, cardName): 

El talón de prueba he escrito en C# es:

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(); 
     } 
    } 
} 

¿Qué tengo que hacer con el fin de crear una instancia de esta clase en C# ?

Respuesta

51

Las clases de IronPython son no .NET classes. Son instancias de IronPython.Runtime.Types.PythonType que es la metaclase de Python. Esto se debe a que las clases Python son dinámicas y admiten la adición y eliminación de métodos en tiempo de ejecución, cosas que no se pueden hacer con las clases .NET.

Para usar las clases de Python en C#, necesitará usar la clase ObjectOperations. Esta clase le permite operar en tipos e instancias de Python en la semántica del lenguaje en sí. p.ej. utiliza los métodos mágicos cuando es apropiado, promueve automáticamente enteros a largos, etc. Puede obtener más información sobre ObjectOperations mirando la fuente o utilizando el reflector.

Aquí hay un ejemplo. Calculator.py contiene una clase simple:

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

Usted puede utilizarlo desde su pre .NET 4.0 C# código como esto:

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) 

Usted tendrá que hacer referencia a las asambleas IronPython.dll, de Microsoft. Scripting y Microsoft.Scripting.Core.

C# 4 hizo esto mucho más fácil con el nuevo tipo dinámico.

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); 

Si está utilizando Visual Studio 2010 o posterior con soporte NuGet, simplemente ejecútelo para descargar y consultar las bibliotecas apropiadas.

Install-Package IronPython 
+1

I no tienen la representante para editar esto , pero en la muestra Calculator.py, la primera "def" debe sangrarse. ¡Gran ejemplo, sin embargo! Muy útil. Ahora que .Net 4.0 está listo, sería bueno ver un ejemplo actualizado. –

+5

Se agregó un ejemplo de .Net 4.0, utilizando su misma clase de muestra de Calculadora. –

+0

Gracias, agregué la sangría. –

-4

He buscado alto y bajo y me temo que no parece haber mucha información relacionada con esto. Estoy casi seguro de que nadie ha ideado una forma de hacer esto de la manera más limpia que le gustaría.

La razón principal por la que creo que esto es un problema es que para ver el tipo PokerCard en su aplicación C# tendría que compilar su código Python a IL. No creo que haya compiladores Python -> IL por ahí.

31

Ahora que se lanzó .Net 4.0 y tiene el tipo dinámico, este ejemplo debe actualizarse. Usando el mismo archivo Python como en m-aguda de respuesta original:

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

Aquí es cómo se llaman utilizando .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);   

Una vez más, es necesario agregar referencias a IronPython.dll y Microsoft.Scripting.

Como puede ver, la configuración inicial y la creación del archivo de origen es la misma.

Pero una vez que la fuente se ejecuta con éxito, trabajar con las funciones de python es mucho más fácil gracias a la nueva palabra clave "dinámica".

+0

¡Gracias por agregar el ejemplo! –

+0

¡Esto realmente ayudó! –

0

Estoy actualizando el ejemplo anterior proporcionado por Clever Human para compilar las clases de IronPython (dll) en lugar del código fuente de IronPython en un archivo .py.

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

C# 4.0 código con el nuevo tipo dinámico es el siguiente:

// 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); 

Referencias:

  1. Using Compiled Python Classes from .NET/CSharp IP 2.6
  2. Static Compilation of IronPython scripts
Cuestiones relacionadas