Создание экземпляра класса Python в C#
-
06-09-2019 - |
Вопрос
Я написал класс на Python, который хочу обернуть в сборку .net через IronPython и создать экземпляр в приложении C#.Я перенес класс в IronPython, создал сборку библиотеки и сослался на нее.Теперь, как мне получить экземпляр этого класса?
Класс выглядит (частично) так:
class PokerCard:
"A card for playing poker, immutable and unique."
def __init__(self, cardName):
Тестовая заглушка, которую я написал на 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();
}
}
}
Что мне нужно сделать, чтобы создать экземпляр этого класса на C#?
Решение
Классы IronPython нет .NET-классы.Они являются экземплярами IronPython.Runtime.Types.PythonType, который является метаклассом Python.Это связано с тем, что классы Python являются динамическими и поддерживают добавление и удаление методов во время выполнения, чего нельзя сделать с классами .NET.
Чтобы использовать классы Python в C#, вам понадобится класс ObjectOperations.Этот класс позволяет вам работать с типами и экземплярами Python в семантике самого языка.напримерон использует магические методы, когда это необходимо, автоматически преобразует целые числа в длинные и т. д.Вы можете узнать больше об ObjectOperations, посмотрев исходный код или используя отражатель.
Вот пример.Calculator.py содержит простой класс:
class Calculator(object):
def add(self, a, b):
return a + b
Вы можете использовать его из кода C# до .NET 4.0 следующим образом:
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)
Вам потребуется указать ссылки на сборки IronPython.dll, Microsoft.Scripting и Microsoft.Scripting.Core.
В 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);
Если вы используете Visual Studio 2010 или более позднюю версию с поддержкой NuGet, просто выполните это, чтобы загрузить соответствующие библиотеки и обратиться к ним.
Install-Package IronPython
Другие советы
Теперь, когда .Net 4.0 выпущен и имеет динамический тип, этот пример следует обновить.Используя тот же файл Python, что и в исходном ответе m-sharp:
class Calculator(object):
def add(self, a, b):
return a + b
Вот как вы бы это назвали, используя .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);
Опять же, вам нужно добавить ссылки на IronPython.dll и Microsoft.Scripting.
Как видите, первоначальная настройка и создание исходного файла одинаковы.
Но как только исходный код будет успешно выполнен, работать с функциями Python станет намного проще благодаря новому ключевому слову «dynamic».
Я обновляю приведенный выше пример, предоставленный Clever Human, для скомпилированных классов IronPython (dll) вместо исходного кода IronPython в файле .py.
# Compile IronPython calculator class to a dll
clr.CompileModules("calculator.dll", "calculator.py")
Код 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);
Использованная литература:
Я искал повсюду и боюсь, что информации по этому поводу не так уж и много.Я почти уверен, что никто не придумал способа сделать это так чисто, как вам хотелось бы.
Основная причина, по которой я думаю, что это проблема, заключается в том, что для того, чтобы увидеть PokerCard
введите свое приложение C#, вам придется скомпилировать код Python в IL.Я не верю, что существует какой-либо Python->
IL-компиляторы существуют.