Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9f01ebb

Browse files
Operator overloads support (#1324)
C# operator methods generate instance methods on the Python side like `__add__`. The arguments passed from Python are then processed by `MethodBinder`.Co-authored-by: Victor <lost@losttech.software>
1 parent96cc739 commit9f01ebb

File tree

10 files changed

+612
-9
lines changed

10 files changed

+612
-9
lines changed

‎AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- Benoît Hudson ([@benoithudson](https://github.com/benoithudson))
2525
- Bradley Friedman ([@leith-bartrich](https://github.com/leith-bartrich))
2626
- Callum Noble ([@callumnoble](https://github.com/callumnoble))
27+
- Christabella Irwanto([@christabella](https://github.com/christabella))
2728
- Christian Heimes ([@tiran](https://github.com/tiran))
2829
- Christoph Gohlke ([@cgohlke](https://github.com/cgohlke))
2930
- Christopher Bremner ([@chrisjbremner](https://github.com/chrisjbremner))

‎CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1010
###Added
1111

1212
- Ability to instantiate new .NET arrays using`Array[T](dim1, dim2, ...)` syntax
13+
- Python operator method will call C# operator method for supported binary and unary operators ([#1324][p1324]).
1314

1415
###Changed
1516
- Drop support for Python 2, 3.4, and 3.5

‎src/embed_tests/TestOperator.cs

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
usingNUnit.Framework;
2+
3+
usingPython.Runtime;
4+
5+
usingSystem.Linq;
6+
usingSystem.Reflection;
7+
8+
namespacePython.EmbeddingTest
9+
{
10+
publicclassTestOperator
11+
{
12+
[OneTimeSetUp]
13+
publicvoidSetUp()
14+
{
15+
PythonEngine.Initialize();
16+
}
17+
18+
[OneTimeTearDown]
19+
publicvoidDispose()
20+
{
21+
PythonEngine.Shutdown();
22+
}
23+
24+
publicclassOperableObject
25+
{
26+
publicintNum{get;set;}
27+
28+
publicOperableObject(intnum)
29+
{
30+
Num=num;
31+
}
32+
33+
publicstaticOperableObjectoperator~(OperableObjecta)
34+
{
35+
returnnewOperableObject(~a.Num);
36+
}
37+
38+
publicstaticOperableObjectoperator+(OperableObjecta)
39+
{
40+
returnnewOperableObject(+a.Num);
41+
}
42+
43+
publicstaticOperableObjectoperator-(OperableObjecta)
44+
{
45+
returnnewOperableObject(-a.Num);
46+
}
47+
48+
publicstaticOperableObjectoperator+(inta,OperableObjectb)
49+
{
50+
returnnewOperableObject(a+b.Num);
51+
}
52+
publicstaticOperableObjectoperator+(OperableObjecta,OperableObjectb)
53+
{
54+
returnnewOperableObject(a.Num+b.Num);
55+
}
56+
publicstaticOperableObjectoperator+(OperableObjecta,intb)
57+
{
58+
returnnewOperableObject(a.Num+b);
59+
}
60+
61+
publicstaticOperableObjectoperator-(inta,OperableObjectb)
62+
{
63+
returnnewOperableObject(a-b.Num);
64+
}
65+
publicstaticOperableObjectoperator-(OperableObjecta,OperableObjectb)
66+
{
67+
returnnewOperableObject(a.Num-b.Num);
68+
}
69+
publicstaticOperableObjectoperator-(OperableObjecta,intb)
70+
{
71+
returnnewOperableObject(a.Num-b);
72+
}
73+
74+
publicstaticOperableObjectoperator*(inta,OperableObjectb)
75+
{
76+
returnnewOperableObject(a*b.Num);
77+
}
78+
publicstaticOperableObjectoperator*(OperableObjecta,OperableObjectb)
79+
{
80+
returnnewOperableObject(a.Num*b.Num);
81+
}
82+
publicstaticOperableObjectoperator*(OperableObjecta,intb)
83+
{
84+
returnnewOperableObject(a.Num*b);
85+
}
86+
87+
publicstaticOperableObjectoperator/(inta,OperableObjectb)
88+
{
89+
returnnewOperableObject(a/b.Num);
90+
}
91+
publicstaticOperableObjectoperator/(OperableObjecta,OperableObjectb)
92+
{
93+
returnnewOperableObject(a.Num/b.Num);
94+
}
95+
publicstaticOperableObjectoperator/(OperableObjecta,intb)
96+
{
97+
returnnewOperableObject(a.Num/b);
98+
}
99+
100+
publicstaticOperableObjectoperator%(inta,OperableObjectb)
101+
{
102+
returnnewOperableObject(a%b.Num);
103+
}
104+
publicstaticOperableObjectoperator%(OperableObjecta,OperableObjectb)
105+
{
106+
returnnewOperableObject(a.Num%b.Num);
107+
}
108+
publicstaticOperableObjectoperator%(OperableObjecta,intb)
109+
{
110+
returnnewOperableObject(a.Num%b);
111+
}
112+
113+
publicstaticOperableObjectoperator&(inta,OperableObjectb)
114+
{
115+
returnnewOperableObject(a&b.Num);
116+
}
117+
publicstaticOperableObjectoperator&(OperableObjecta,OperableObjectb)
118+
{
119+
returnnewOperableObject(a.Num&b.Num);
120+
}
121+
publicstaticOperableObjectoperator&(OperableObjecta,intb)
122+
{
123+
returnnewOperableObject(a.Num&b);
124+
}
125+
126+
publicstaticOperableObjectoperator|(inta,OperableObjectb)
127+
{
128+
returnnewOperableObject(a|b.Num);
129+
}
130+
publicstaticOperableObjectoperator|(OperableObjecta,OperableObjectb)
131+
{
132+
returnnewOperableObject(a.Num|b.Num);
133+
}
134+
publicstaticOperableObjectoperator|(OperableObjecta,intb)
135+
{
136+
returnnewOperableObject(a.Num|b);
137+
}
138+
139+
publicstaticOperableObjectoperator^(inta,OperableObjectb)
140+
{
141+
returnnewOperableObject(a^b.Num);
142+
}
143+
publicstaticOperableObjectoperator^(OperableObjecta,OperableObjectb)
144+
{
145+
returnnewOperableObject(a.Num^b.Num);
146+
}
147+
publicstaticOperableObjectoperator^(OperableObjecta,intb)
148+
{
149+
returnnewOperableObject(a.Num^b);
150+
}
151+
152+
publicstaticOperableObjectoperator<<(OperableObjecta,intoffset)
153+
{
154+
returnnewOperableObject(a.Num<<offset);
155+
}
156+
157+
publicstaticOperableObjectoperator>>(OperableObjecta,intoffset)
158+
{
159+
returnnewOperableObject(a.Num>>offset);
160+
}
161+
}
162+
163+
[Test]
164+
publicvoidOperatorOverloads()
165+
{
166+
stringname=string.Format("{0}.{1}",
167+
typeof(OperableObject).DeclaringType.Name,
168+
typeof(OperableObject).Name);
169+
stringmodule=MethodBase.GetCurrentMethod().DeclaringType.Namespace;
170+
171+
PythonEngine.Exec($@"
172+
from{module} import *
173+
cls ={name}
174+
a = cls(-2)
175+
b = cls(10)
176+
c = ~a
177+
assert c.Num == ~a.Num
178+
179+
c = +a
180+
assert c.Num == +a.Num
181+
182+
a = cls(2)
183+
c = -a
184+
assert c.Num == -a.Num
185+
186+
c = a + b
187+
assert c.Num == a.Num + b.Num
188+
189+
c = a - b
190+
assert c.Num == a.Num - b.Num
191+
192+
c = a * b
193+
assert c.Num == a.Num * b.Num
194+
195+
c = a / b
196+
assert c.Num == a.Num // b.Num
197+
198+
c = a % b
199+
assert c.Num == a.Num % b.Num
200+
201+
c = a & b
202+
assert c.Num == a.Num & b.Num
203+
204+
c = a | b
205+
assert c.Num == a.Num | b.Num
206+
207+
c = a ^ b
208+
assert c.Num == a.Num ^ b.Num
209+
");
210+
}
211+
212+
[Test]
213+
publicvoidOperatorOverloadMissingArgument()
214+
{
215+
stringname=string.Format("{0}.{1}",
216+
typeof(OperableObject).DeclaringType.Name,
217+
typeof(OperableObject).Name);
218+
stringmodule=MethodBase.GetCurrentMethod().DeclaringType.Namespace;
219+
220+
Assert.Throws<PythonException>(()=>
221+
PythonEngine.Exec($@"
222+
from{module} import *
223+
cls ={name}
224+
a = cls(2)
225+
b = cls(10)
226+
a.op_Addition()
227+
"));
228+
}
229+
230+
[Test]
231+
publicvoidForwardOperatorOverloads()
232+
{
233+
stringname=string.Format("{0}.{1}",
234+
typeof(OperableObject).DeclaringType.Name,
235+
typeof(OperableObject).Name);
236+
stringmodule=MethodBase.GetCurrentMethod().DeclaringType.Namespace;
237+
238+
PythonEngine.Exec($@"
239+
from{module} import *
240+
cls ={name}
241+
a = cls(2)
242+
b = 10
243+
c = a + b
244+
assert c.Num == a.Num + b
245+
246+
c = a - b
247+
assert c.Num == a.Num - b
248+
249+
c = a * b
250+
assert c.Num == a.Num * b
251+
252+
c = a / b
253+
assert c.Num == a.Num // b
254+
255+
c = a % b
256+
assert c.Num == a.Num % b
257+
258+
c = a & b
259+
assert c.Num == a.Num & b
260+
261+
c = a | b
262+
assert c.Num == a.Num | b
263+
264+
c = a ^ b
265+
assert c.Num == a.Num ^ b
266+
");
267+
}
268+
269+
270+
[Test]
271+
publicvoidReverseOperatorOverloads()
272+
{
273+
stringname=string.Format("{0}.{1}",
274+
typeof(OperableObject).DeclaringType.Name,
275+
typeof(OperableObject).Name);
276+
stringmodule=MethodBase.GetCurrentMethod().DeclaringType.Namespace;
277+
278+
PythonEngine.Exec($@"
279+
from{module} import *
280+
cls ={name}
281+
a = 2
282+
b = cls(10)
283+
284+
c = a + b
285+
assert c.Num == a + b.Num
286+
287+
c = a - b
288+
assert c.Num == a - b.Num
289+
290+
c = a * b
291+
assert c.Num == a * b.Num
292+
293+
c = a / b
294+
assert c.Num == a // b.Num
295+
296+
c = a % b
297+
assert c.Num == a % b.Num
298+
299+
c = a & b
300+
assert c.Num == a & b.Num
301+
302+
c = a | b
303+
assert c.Num == a | b.Num
304+
305+
c = a ^ b
306+
assert c.Num == a ^ b.Num
307+
");
308+
309+
}
310+
[Test]
311+
publicvoidShiftOperatorOverloads()
312+
{
313+
stringname=string.Format("{0}.{1}",
314+
typeof(OperableObject).DeclaringType.Name,
315+
typeof(OperableObject).Name);
316+
stringmodule=MethodBase.GetCurrentMethod().DeclaringType.Namespace;
317+
318+
PythonEngine.Exec($@"
319+
from{module} import *
320+
cls ={name}
321+
a = cls(2)
322+
b = cls(10)
323+
324+
c = a << b.Num
325+
assert c.Num == a.Num << b.Num
326+
327+
c = a >> b.Num
328+
assert c.Num == a.Num >> b.Num
329+
");
330+
}
331+
}
332+
}

‎src/runtime/classmanager.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,19 @@ private static ClassInfo GetClassInfo(Type type)
470470

471471
ob=newMethodObject(type,name,mlist);
472472
ci.members[name]=ob;
473+
if(mlist.Any(OperatorMethod.IsOperatorMethod))
474+
{
475+
stringpyName=OperatorMethod.GetPyMethodName(name);
476+
stringpyNameReverse=OperatorMethod.ReversePyMethodName(pyName);
477+
MethodInfo[]forwardMethods,reverseMethods;
478+
OperatorMethod.FilterMethods(mlist,outforwardMethods,outreverseMethods);
479+
// Only methods where the left operand is the declaring type.
480+
if(forwardMethods.Length>0)
481+
ci.members[pyName]=newMethodObject(type,name,forwardMethods);
482+
// Only methods where only the right operand is the declaring type.
483+
if(reverseMethods.Length>0)
484+
ci.members[pyNameReverse]=newMethodObject(type,name,reverseMethods);
485+
}
473486
}
474487

475488
if(ci.indexer==null&&type.IsClass)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp