6

IronPythonで .NET 値型を使用する場合、よく知られている問題があります。これは最近、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 に答える 4

4

ライブラリを変更する必要はありません。プロキシを使用するだけです。

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;
   }
}
于 2010-04-21T22:43:05.020 に答える
2

電話すると

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
于 2010-04-20T19:37:03.593 に答える
1

構造体を更新するために私が見つけた唯一の方法は、構造体を作成するときに任意のパブリック フィールド/プロパティを指定できるという事実を利用することです。構文は、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

古いものからフィールドをコピーして、新しい構造体を作成するための F# 'with' のような構文が Python にあればいいのですが。残念ながら、構造体を複製するときはすべてのフィールドを指定する必要があります。

于 2010-04-23T07:34:11.513 に答える
-1

あなたがそのような隅にたどり着いたことはむしろ不可解です. 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

私の疑似コードとあなたの疑似コードには 1 つの違いがあることに注意してください。静的プロパティには、型定義だけでなく、クラスのインスタンスが割り当てられます。副作用として、クラスの実際のインスタンスは、b がインスタンス化されるときに b.Vector として初期化されます。

(疑似コードはまだ「壊れている」 - 初期化は def init (self) に入る必要がありますが、それは別の話です)

この例の教訓は、「public Vector position」を初期化せずに残す代わりに、「position」の初期化をクラス Object に組み込むことです。

于 2010-06-15T04:18:40.760 に答える