@@ -9,9 +9,11 @@ namespace Python.Runtime
99{
1010 internal static class OperatorMethod
1111 {
12+ // Maps the compiled method name in .NET CIL (e.g. op_Addition) to
13+ // the equivalent Python operator (e.g. __add__) as well as the offset
14+ // that identifies that operator's slot (e.g. nb_add) in heap space.
1215 public static Dictionary < string , Tuple < string , int > > OpMethodMap { get ; private set ; }
1316
14- private static Dictionary < string , string > _pyOpNames ;
1517 private static PyObject _opType ;
1618
1719 static OperatorMethod ( )
@@ -35,12 +37,6 @@ static OperatorMethod()
3537 [ "op_Modulus" ] = Tuple . Create ( "__mod__" , TypeOffset . nb_remainder ) ,
3638 [ "op_OneComplement" ] = Tuple . Create ( "__invert__" , TypeOffset . nb_invert )
3739 } ;
38-
39- _pyOpNames = new Dictionary < string , string > ( ) ;
40- foreach ( string name in OpMethodMap . Keys )
41- {
42- _pyOpNames . Add ( GetPyMethodName ( name ) , name ) ;
43- }
4440 }
4541
4642 public static void Initialize ( )
@@ -62,11 +58,6 @@ public static bool IsOperatorMethod(string methodName)
6258 return OpMethodMap . ContainsKey ( methodName ) ;
6359 }
6460
65- public static bool IsPyOperatorMethod ( string pyMethodName )
66- {
67- return _pyOpNames . ContainsKey ( pyMethodName ) ;
68- }
69-
7061 public static bool IsOperatorMethod ( MethodBase method )
7162 {
7263 if ( ! method . IsSpecialName )
@@ -75,7 +66,12 @@ public static bool IsOperatorMethod(MethodBase method)
7566 }
7667 return OpMethodMap . ContainsKey ( method . Name ) ;
7768 }
78-
69+ /// <summary>
70+ /// For the operator methods of a CLR type, set the special slots of the
71+ /// corresponding Python type's operator methods.
72+ /// </summary>
73+ /// <param name="pyType"></param>
74+ /// <param name="clrType"></param>
7975 public static void FixupSlots ( IntPtr pyType , Type clrType )
8076 {
8177 const BindingFlags flags = BindingFlags . Public | BindingFlags . Static ;
@@ -86,10 +82,16 @@ public static void FixupSlots(IntPtr pyType, Type clrType)
8682 {
8783 continue ;
8884 }
89- var slotdef = OpMethodMap [ method . Name ] ;
90- int offset = slotdef . Item2 ;
85+ int offset = OpMethodMap [ method . Name ] . Item2 ;
86+ // Copy the default implementation of e.g. the nb_add slot,
87+ // which simply calls __add__ on the type.
9188 IntPtr func = Marshal . ReadIntPtr ( _opType . Handle , offset ) ;
89+ // Write the slot definition of the target Python type, so
90+ // that we can later modify __add___ and it will be called
91+ // when used with a Python operator.
92+ // https://tenthousandmeters.com/blog/python-behind-the-scenes-6-how-python-object-system-works/
9293 Marshal . WriteIntPtr ( pyType , offset , func ) ;
94+
9395 }
9496 }
9597
@@ -116,7 +118,9 @@ private static PyObject GetOperatorType()
116118 {
117119 // A hack way for getting typeobject.c::slotdefs
118120 string code = GenerateDummyCode ( ) ;
121+ // The resulting OperatorMethod class is stored in a PyDict.
119122 PythonEngine . Exec ( code , null , locals . Handle ) ;
123+ // Return the class itself, which is a type.
120124 return locals . GetItem ( "OperatorMethod" ) ;
121125 }
122126 }
0 commit comments