понедельник, 2 мая 2011 г.

Внедрение IronPython. Функционал.

В последний раз я рассказывал о внедрении модулей Iron Python в свою программу на языке C#. Мы рассмотрели основы, рассмотрели создание простенького интерпретатора. В этот раз я хочу сделать акцент на более углубленное изучение неких базовых возможностей, которые предоставляются сборками Iron Python.

 Речь пойдет о взаимодействии динамически генерированного кода Iron Python с статическим кодом C# и, соответственно, наоборот - из программы, написанной на C#, мы будем извлекать некие данные и передавать их в динамически генерированный код Iron Python. Также мы рассмотрим такие вещи, как импорт пространств имен и взаимодействие с ними. Данная статься будет не особо объемной, так как планируется рассмотреть только базу подобной работы с интерпретатором - я просто не вижу смысла останавливаться подробно на каждом методе, так как они все имеют весьма осмысленное название, а в окне авто синтаксиса можно прочитать очень понятное краткое описание функционала, который метод в себе реализует. Остановимся лишь на главных.

Вообще Iron Python предоставляет весьма хороший функционал для полной реализации своей скриптовой системы в игре, программе и т.п. Затрачивая минимум усилий, вы получаете полнофункциональный скриптовый движок, который тесно связан с кодом и хорошо в него интегрирован. Главным вопросом остается только производительность. Она, к сожалению, не является сильной стороной модуля Iron Python. По некоторым данным, он в два раза медленнее CPython, который сам по себе не является шустрым языком. Конечно, Crysis или Unreal Tournament 3 просто не написать на таком, но мы с вами и не программисты сильнейших фирм в мире, так что особенно о производительности думать не стоит, а стоит рассматреть Python, как приятную и легко реализуемую систему собственных скриптов в игре. Ну что же, приступим к рассмотрению кода.

Взаимодействие IronPython с C#

Здесь я планирую рассмотреть взаимодействие Python со сборкой C#. Естественно, создавая динамически компилируемые скрипты, вы будете подразумевать использование пространств имен, классов, полей, методов, находящихся внутри библиотек .NET или программы, из которой вызывается код Python.

Для того, чтобы использовать сборки .NET, необходимо их сначала импортировать в Python. Для этого в коде IronPython сначала напишем следующую строчку

from %namespace import *

,где %namespace - имя любого пространства имен. Пример:

from System import *

импортируется пространство имен System

from System.Drawing import *

импортируется Drawing из System. Также вы можете импортировать пространство имен своей программы (положим, что ваша программа содержится в namespce Compiler и в ней есть класс SomeClass)

from Compiler import *

После импортирования пространства имен вы можете в коде объявлять экземпляры классов пространства имен и располагать всем функционалом, который они предоставляют:

from Compiler import *
test = SomeClass()

(как мы положили выше, в namespce Compiler есть класс SomeClass). Некое удобство в том, что Python не строго типизированный язык, так что нет проблем во сторогой типизацией аргументов, т.е. упрощается процесс вызова конструкторов, методов. Таким образом, используя ключевые слова from - import вы обеспечиваете взаимодействие со статичным кодом программы. Возможности, которые открываются-поистине безграничны. Теперь рассмотрим взаимодействие C# с динамически сгенерированным кодом Iron Python.

Взаимодействие C# с IronPython

Взаимодействие вашей программы с кодом IronPython на самом деле весьма и весьма тривиально, в нем можно было разобраться просто прочитав описание методов в авто синтаксисе. Но прежде чем начать, необходимо сказать пару слов о том, откуда именно необходимо вызывать методы. Так как engine и scope имеют сходные по именам методы (SetVariable,GetVariable), то необходимо четко помнить разницу между ними. Engine - это просто интерпретатор кода, а scope - это уже область, на которой отражается этот код.Именно в scope хранятся все переменные и вся программа (Но на самом деле, если вы будете вызывать эти методы из engine, то в качестве параметра вам надо будет передать scope, на котором все это отразится). Мы же,для простоты, условимся, что будем вызывать эти методы из scope.Давайте рассмотрим главные из них.


SetVariable()

Этот метод используется для того, чтобы установить значение для переменной или же создать переменную с таким именем и присвоить ей значение. Передается два аргумента

string <имя переменной>, object <значение>

Как вы могли заметить, код банальный до ужаса). Следующий пример просто добавит переменную и присвоит ей значение 5

scope.SetVariable("testInt", 5);


GetVariable()

Данный метод возвращает значение переменной. Значение возвращается упакованным в object. В качестве параметра передается имя переменной

string <имя переменной>

Пример кода, возвращающего наше значение testInt

object returnedValue = scope.GetVariable("testInt");

Если вас не устраивает, что возвращается упакованный object, можете воспользоватся шаблонным методом GetVariable<> и в него передать тип значения, который вам надо вернуть.

int returnedValue = scope.GetVariable<typeof(int)>("testInt");

И никаких приведений - все просто и в одну строчку)

TryGetVariable

Метод, принимающий два параметра - имя переменной и выходной параметр типа object, в который будет записано значение. Метод возвращает переменную bool об успешности операции

object returnedValue = new object();
scope.TryGetVariable("testInt", out returnedValue);

В случае успешного выполнения операции значение переменной записывается в returnedValue. Для изыскательных - есть перегрузка с использованием шаблонов. Там все аналогично:

int returnedValue;
scope.TryGetVariable<returnedValue.GetType()>("testInt", out returnedValue);

Данный метод - альтернатива вышеописанным методам.

GetItems()

Раз уж зашел разговор о получении переменных, наверняка вам захочется получить сразу все переменные из scope. За это отвечает метод GetItems. Он возвращает коллекцию KeyValuePair<string,object>, снабженную интерфейсом IEnumerable. Вызов метода будет выглядеть так:

IEnumerable<KeyValuePair<string,object>> items = scope.GetItems();

Получаем коллекцию всех объектов из scope и делаем с ними все,что хотим)

GetVariableNames()

Метод, возвращающий коллекцию строк, содержащих имена всех переменных. В паре со всеми остальными дает полную свободу в творчестве.

IEnumerable<string> allVariableNames = scope.GetVariableNames();

RemoveVariable()

Простенький метод, удаляющий переменную? возвращает bool, который сообщает об успешности операции. На вход принимает имя переменной:

scope.RemoveVariable("testInt")


ContainsVariable()

Опять же простой метод, возвращает значение типа bool, определяет, есть ли определенная переменная в данном scope:

bool isExist = scope.ContainsVariable("testInt");

На этом все. Все основные методы (а на самом деле-почти все, осталось лишь пара-тройка специализированных методов, которые в повседневной жизни вам не понадобятся) успешно были рассмотрены и применены в действии. Все они достаточно просто  работают, кому хочется порыться - рефрактор вам в помощь, посмотрите начинку методов всех.

До новых встреч! С вами был Денис Горячев

Комментариев нет:

Отправить комментарий