43 votes

Instancier une classe python en C#

J'ai écrit une classe en python que je veux intégrer dans un assembly .net via IronPython et instancier dans une application C#. J'ai migré la classe vers IronPython, créé une bibliothèque d'assemblage et l'ai référencée. Maintenant, comment puis-je obtenir une instance de cette classe ?

La classe ressemble (partiellement) à ceci :

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

    def __init__(self, cardName):

Le stub de test que j'ai écrit en C# est :

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

Que dois-je faire pour instancier cette classe en C# ?

54voto

m-sharp Points 4349

Les classes IronPython sont no Les classes .NET. Ce sont des instances de IronPython.Runtime.Types.PythonType qui est la métaclasse Python. En effet, les classes Python sont dynamiques et permettent l'ajout et la suppression de méthodes au moment de l'exécution, ce qui est impossible avec les classes .NET.

Pour utiliser les classes Python en C#, vous devez utiliser la classe ObjectOperations. Cette classe vous permet d'opérer sur des types et des instances Python en respectant la sémantique du langage lui-même. Par exemple, elle utilise les méthodes magiques lorsque cela est approprié, fait passer automatiquement les entiers en longs, etc. Vous pouvez en savoir plus sur ObjectOperations en regardant la source ou en utilisant reflector.

Voici un exemple. Calculator.py contient une classe simple :

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

Vous pouvez l'utiliser à partir de votre code C# pré .NET 4.0 comme ceci :

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)

Vous devrez référencer les assemblages IronPython.dll, Microsoft.Scripting et Microsoft.Scripting.Core.

C# 4 a rendu cela beaucoup plus facile avec le nouveau type dynamique.

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 vous utilisez Visual Studio 2010 ou une version ultérieure avec la prise en charge de NuGet, il suffit d'exécuter cette opération pour télécharger et référencer les bibliothèques appropriées.

Install-Package IronPython

31voto

Clever Human Points 3174

Maintenant que .Net 4.0 est sorti et qu'il dispose du type dynamique, cet exemple doit être mis à jour. En utilisant le même fichier python que dans la réponse originale de m-sharp :

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

Voici comment vous l'appelleriez en utilisant .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);          

Là encore, vous devez ajouter des références à IronPython.dll et à Microsoft.Scripting.

Comme vous pouvez le constater, la mise en place initiale et la création du fichier source sont les mêmes.

Mais une fois que la source est exécutée avec succès, le travail avec les fonctions python est beaucoup plus facile grâce au nouveau mot clé "dynamic".

0voto

bhadra Points 7255

Je mets à jour l'exemple ci-dessus fourni par Clever Human pour les classes IronPython compilées (dll) au lieu du code source IronPython dans un fichier .py.

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

Le code C# 4.0 avec le nouveau type dynamique est le suivant :

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

Références :

  1. Utilisation de classes Python compilées à partir de .NET/CSharp IP 2.6
  2. Compilation statique des scripts d'IronPython

-4voto

Andrew Hare Points 159332

J'ai cherché partout et j'ai bien peur qu'il n'y ait pas beaucoup d'informations à ce sujet. Je suis à peu près certain que personne n'a trouvé le moyen de le faire proprement comme vous le souhaitez.

La principale raison pour laquelle je pense que c'est un problème est que pour voir la PokerCard dans votre application C#, vous devrez compiler votre code Python en IL. Je ne pense pas qu'il y ait de code Python -> Il existe des compilateurs IL.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X