2010-04-18 36 views
6

Có một well known issue khi nói đến việc sử dụng các loại giá trị .NET trong IronPython. Điều này gần đây đã khiến tôi đau đầu khi cố gắng sử dụng Python như một ngôn ngữ kịch bản được nhúng trong C#. Vấn đề có thể được tóm tắt như sau:Làm thế nào để xử lý các loại giá trị khi nhúng IronPython trong C#?

Cho một C# struct như:

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

Và một lớp học C# như:

class Object { 
    public Vector position; 
} 

Sau đây sẽ xảy ra trong IronPython:

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

Như bài viết nêu, điều này có nghĩa là các loại giá trị hầu như không thay đổi. Tuy nhiên, đây là một vấn đề như tôi đã có kế hoạch sử dụng một thư viện vector được thực hiện như đã thấy ở trên. Có cách giải quyết nào để làm việc với các thư viện hiện có dựa trên các loại giá trị không? Sửa đổi thư viện sẽ là phương sách cuối cùng, nhưng tôi muốn tránh điều đó.

+0

Tính năng này có hoạt động không? obj = Đối tượng() pos = Vector() pos.x = 1 obj.position = pos in obj.position.x –

+0

Có, hoạt động. Với một nhà xây dựng thích hợp, người ta cũng có thể sử dụng 'obj.position = Vector (1,0)'. Điều này có thể được chấp nhận, mặc dù hành vi tôi mô tả trong câu hỏi của tôi vẫn sẽ gây nhầm lẫn ... – kloffy

Trả lời

4

Không cần thay đổi thư viện, chỉ cần sử dụng một proxy.

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

Bây giờ mã Python có thể thiết lập các lĩnh vực như bình thường và mã của bạn có thể gọi Optimized khi nó cần để nuôi các dữ liệu để OpenGL hoặc XNA hoặc bất cứ điều gì bạn đang sử dụng.

Bạn thậm chí có thể sử dụng ép buộc ngầm nếu gọi Optimized có vẻ như quá nhiều công việc:

class BetterVector { 
    // ... 
    public static implicit operator Vector(BetterVector v) { 
     return v.Optimized; 
    } 
} 
+0

Điều đó khá thú vị, đặc biệt là với sự ép buộc ngầm. Người ta sẽ phải viết một loạt các proxy nhưng nó không phải là quá nhiều công việc. Tôi sẽ để câu hỏi mở thêm một chút, chỉ để xem có đề xuất nào khác không, nhưng tôi thích cách tiếp cận này. – kloffy

2

Khi bạn gọi

obj.position.x = 1

gì bạn nhận được là các đối tượng obj giúp bạn một thể hiện của vị trí struct, mà nó chủ yếu làm cho một bản sao của, vì vậy, việc thiết giá trị X không được khuyến khích.

Điều bạn đang nói là obj.position = Vector (1,0) là những gì bạn nên làm. Những điều tương tự xảy ra trong C#.


Chỉnh sửa - có thể làm việc xung quanh.

Nếu bạn không muốn thiết lập các nhà xây dựng, tôi tin rằng điều này sẽ làm việ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 
+0

Vâng, có và không. Tôi hiểu khái niệm về các loại giá trị và tôi có thể thấy những khó khăn mà chúng thể hiện khi dịch chúng sang IronPython. Tuy nhiên, giải pháp hiện tại khác với hành vi trong C# (như đã đề cập trong bài viết được liên kết) và khác với cách Python hoạt động (không có kiểu giá trị). Nếu IronPython có một cái gì đó giống như một hàm 'getattrref', điều đó sẽ cho phép người dùng tạo lại hành vi C#, mà theo như tôi có thể nói là không thể ngay bây giờ. – kloffy

+0

Vâng, C# là khác nhau, nhưng hành vi là loại tương tự. Tôi đã cập nhật phản ứng của tôi, có thể làm việc tốt hơn một chút – McKay

+0

Đó không phải là một cách xấu để làm cho nó trông giống như cú pháp, nhưng tôi tự hỏi nếu có một cách để có được cùng một ngữ nghĩa như trong C# (tức là không tạo ra một bản sao mới của Vector). – kloffy

1

Cách duy nhất tôi đã tìm thấy để cập nhật cấu trúc là để tận dụng thực tế là bạn có thể chỉ định bất kỳ lĩnh vực nào/thuộc tính khi tạo cấu trúc. Cú pháp trông giống như các tham số có tên/tùy chọn trong Python.

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

    public class MyClass 
    { 
     public MyStruct a; 
    } 
} 

Chúng ta có thể sử dụng các lớp trong IronPython như thế này:

>>> 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 

Nó sẽ được tốt đẹp nếu Python đã có một cú pháp giống như F # 'với' để tạo một cấu trúc mới, sao chép các lĩnh vực từ người già. Thật không may, chúng ta phải chỉ định tất cả các trường khi nhân bản một cấu trúc.

+0

Cảm ơn bạn đã đề cập đến hàm tạo kwargs, có thể rất tiện dụng. – kloffy

-1

Khá khó hiểu khi bạn kết thúc ở một góc như vậy. Trong python (thử này trên IronPython 2.6.1, Net 4.0) mã tương đương sẽ là về vấn đề này:

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

Lưu ý có một sự khác biệt giữa mã giả của tôi và của bạn - bất động sản tĩnh được gán một thể hiện của một lớp, không chỉ còn lại với định nghĩa kiểu. Là một tác dụng phụ, một thể hiện thực tế của một lớp được khởi tạo như b.Vector khi b được khởi tạo.

(The pseudo-code là vẫn "bị hỏng" - những khởi phải đi vào def init (tự), nhưng đó là một câu chuyện khác nhau)

Các đạo đức của ví dụ, thay vì để "Vector công cộng vị trí "uninitialized, xây dựng khởi tạo" vị trí "vào lớp Object.

+0

Cảm ơn bạn đã bình luận. Tuy nhiên, tôi không nghĩ rằng nó được áp dụng bởi vì tôi đã nói về các loại giá trị .NET. Tôi biết rằng bạn sẽ không gặp phải vấn đề tương tự khi chỉ sử dụng các lớp IronPython. – kloffy

Các vấn đề liên quan