Как обрабатывать типы значений при встраивании IronPython в C #? - PullRequest
6 голосов
/ 19 апреля 2010

Существует хорошо известная проблема , когда речь идет об использовании типов значений .NET в IronPython . Это недавно вызвало у меня головную боль при попытке использовать Python как встроенный язык сценариев в C #. Проблема может быть подытожена следующим образом:

Учитывая структуру C #, такую ​​как:

struct Vector {
    public float x;
    public float y;
}

И класс C #, такой как:

class Object {
    public Vector position;
}

В IronPython произойдет следующее:

obj = Object()
print obj.position.x    # prints ‘0’
obj.position.x = 1
print obj.position.x    # still prints ‘0’

Как говорится в статье, это означает, что типы значений в основном неизменяемы. Однако это проблема, так как я планировал использовать векторную библиотеку, которая реализована, как показано выше. Существуют ли обходные пути для работы с существующими библиотеками, основанными на типах значений? Модификация библиотеки была бы последним средством, но я бы предпочел этого избежать.

Ответы [ 4 ]

4 голосов
/ 22 апреля 2010

Нет необходимости изменять библиотеку, просто используйте прокси.

struct Vector {
    public float X;
    public float Y;
}

class BetterVector {
    public float X;
    public float Y;
    public Vector Optimized { get { return new Vector(X, Y); } }
}

class Object {
    public BetterVector Position { get; set; }
}

Теперь код Python может устанавливать поля как обычно, и ваш код может вызывать Optimized, когда ему нужно передать данные в OpenGL или XNA или что-то еще, что вы используете.

Вы даже можете использовать неявное принуждение, если вызов Optimized кажется слишком большой работой:

class BetterVector {
   // ...
   public static implicit operator Vector(BetterVector v) {
       return v.Optimized;
   }
}
2 голосов
/ 20 апреля 2010

при звонке

obj.position.x = 1

То, что вы получаете, это то, что объект obj получает вам экземпляр структуры позиции, копию которой он, по сути, делает, поэтому установка значения X не распространяется.

Вы говорите, что obj.position = Vector (1,0) - это то, что вы должны делать. Подобные вещи случаются в C #.


Редактировать - возможный обходной путь.

Если вы не хотите настраивать конструктор, я думаю, это сработает:

obj = Object()
pos = obj.position; # gets the object
pos.x = 1
pos.y = 2
obj.position = pos # I'm not sure if this line is necessary
1 голос
/ 23 апреля 2010

Единственный способ обновить структуры - использовать тот факт, что вы можете указать любое открытое поле / свойство при создании структуры. Синтаксис выглядит как именованные / необязательные параметры в Python.

namespace StructExample
{
    public struct MyStruct
    {
        public int x;
        public int y { get; set; }
    }

    public class MyClass
    {
        public MyStruct a;
    }
}

Мы можем использовать классы в IronPython следующим образом:

>>> foo = MyClass()
>>> print "%d:%d" % (foo.a.x, foo.a.y)
0:0
>>> foo.a.x = 1 # doesn't work!
>>> print "%d:%d" % (foo.a.x, foo.a.y)
0:0
>>> foo.a = MyStruct(x=1,y=2)
>>> print "%d:%d" % (foo.a.x, foo.a.y)
1:2

Было бы хорошо, если бы у Python был такой синтаксис, как F # 'with' для создания новой структуры, копирования полей из старой. К сожалению, мы должны указать все поля при клонировании структуры.

0 голосов
/ 15 июня 2010

Скорее озадачивает, что вы оказались в таком углу. В python (пробовал это на IronPython 2.6.1, .Net 4.0) эквивалентный код будет примерно таким:

>>> class a:
...  x = 0
...  y = 0
...
>>> class b:
...  Vector = a()
...
>>> c = b()
>>> c.Vector.x = 1
>>> print c.Vector.x
1

Обратите внимание, что между моим псевдокодом и вашим есть одно отличие: статическому свойству присваивается экземпляр класса, а не только определение типа. Как побочный эффект, фактический экземпляр класса инициализируется как b.Vector, когда создается экземпляр b.

(псевдокод все еще не работает - инициализация должна идти в def init (self), но это другая история)

Мораль примера, вместо того, чтобы оставлять "public Vector position" неинициализированной, встроить инициализацию "position" в класс Object.

...