@@ -92,37 +92,51 @@ class DummyFraction(fractions.Fraction):
92
92
def _components (r ):
93
93
return (r .numerator , r .denominator )
94
94
95
- def is_eq (a , b ):
95
+ def typed_approx_eq (a , b ):
96
96
return type (a ) == type (b ) and (a == b or math .isclose (a , b ))
97
97
98
- class One :
98
+ class Symbolic :
99
+ """Simple non-numeric class for testing mixed arithmetic.
100
+ It is not Integral, Rational, Real or Complex, and cannot be conveted
101
+ to int, float or complex. but it supports some arithmetic operations.
102
+ """
103
+ def __init__ (self , value ):
104
+ self .value = value
99
105
def __mul__ (self , other ):
100
106
if isinstance (other , F ):
101
107
return NotImplemented
102
- return other
108
+ return self . __class__ ( f' { self } * { other } ' )
103
109
def __rmul__ (self , other ):
104
- return other
110
+ return self . __class__ ( f' { other } * { self } ' )
105
111
def __truediv__ (self , other ):
106
112
if isinstance (other , F ):
107
113
return NotImplemented
108
- return 1 / other
114
+ return self . __class__ ( f' { self } / { other } ' )
109
115
def __rtruediv__ (self , other ):
110
- return other
116
+ return self . __class__ ( f' { other } / { self } ' )
111
117
def __mod__ (self , other ):
112
118
if isinstance (other , F ):
113
119
return NotImplemented
114
- return 1 % other
120
+ return self . __class__ ( f' { self } % { other } ' )
115
121
def __rmod__ (self , other ):
116
- return other % 1
122
+ return self . __class__ ( f' { other } % { self } ' )
117
123
def __pow__ (self , other ):
118
124
if isinstance (other , F ):
119
125
return NotImplemented
120
- return self
126
+ return self . __class__ ( f' { self } ** { other } ' )
121
127
def __rpow__ (self , other ):
122
- return other
123
- One = One ()
128
+ return self .__class__ (f'{ other } ** { self } ' )
129
+ def __eq__ (self , other ):
130
+ if other .__class__ != self .__class__ :
131
+ return NotImplemented
132
+ return self .value == other .value
133
+ def __str__ (self ):
134
+ return f'{ self .value } '
135
+ def __repr__ (self ):
136
+ return f'{ self .__class__ .__name__ } ({ self .value !r} )'
124
137
125
138
class Rat :
139
+ """Simple Rational class for testing mixed arithmetic."""
126
140
def __init__ (self , n , d ):
127
141
self .numerator = n
128
142
self .denominator = d
@@ -163,13 +177,14 @@ def __float__(self):
163
177
def __eq__ (self , other ):
164
178
if self .__class__ != other .__class__ :
165
179
return NotImplemented
166
- return (is_eq (self .numerator , other .numerator ) and
167
- is_eq (self .denominator , other .denominator ))
180
+ return (typed_approx_eq (self .numerator , other .numerator ) and
181
+ typed_approx_eq (self .denominator , other .denominator ))
168
182
def __repr__ (self ):
169
183
return f'{ self .__class__ .__name__ } ({ self .numerator !r} , { self .denominator !r} )'
170
184
numbers .Rational .register (Rat )
171
185
172
186
class Root :
187
+ """Simple Real class for testing mixed arithmetic."""
173
188
def __init__ (self , v , n = F (2 )):
174
189
self .base = v
175
190
self .degree = n
@@ -194,12 +209,13 @@ def __float__(self):
194
209
def __eq__ (self , other ):
195
210
if self .__class__ != other .__class__ :
196
211
return NotImplemented
197
- return is_eq (self .base , other .base ) and is_eq (self .degree , other .degree )
212
+ return typed_approx_eq (self .base , other .base ) and typed_approx_eq (self .degree , other .degree )
198
213
def __repr__ (self ):
199
214
return f'{ self .__class__ .__name__ } ({ self .base !r} , { self .degree !r} )'
200
215
numbers .Real .register (Root )
201
216
202
217
class Polar :
218
+ """Simple Complex class for testing mixed arithmetic."""
203
219
def __init__ (self , r , phi ):
204
220
self .r = r
205
221
self .phi = phi
@@ -222,12 +238,13 @@ def __pow__(self, other):
222
238
def __eq__ (self , other ):
223
239
if self .__class__ != other .__class__ :
224
240
return NotImplemented
225
- return is_eq (self .r , other .r ) and is_eq (self .phi , other .phi )
241
+ return typed_approx_eq (self .r , other .r ) and typed_approx_eq (self .phi , other .phi )
226
242
def __repr__ (self ):
227
243
return f'{ self .__class__ .__name__ } ({ self .r !r} , { self .phi !r} )'
228
244
numbers .Complex .register (Polar )
229
245
230
246
class Rect :
247
+ """Other simple Complex class for testing mixed arithmetic."""
231
248
def __init__ (self , x , y ):
232
249
self .x = x
233
250
self .y = y
@@ -251,7 +268,7 @@ def __complex__(self):
251
268
def __eq__ (self , other ):
252
269
if self .__class__ != other .__class__ :
253
270
return NotImplemented
254
- return is_eq (self .x , other .x ) and is_eq (self .y , other .y )
271
+ return typed_approx_eq (self .x , other .x ) and typed_approx_eq (self .y , other .y )
255
272
def __repr__ (self ):
256
273
return f'{ self .__class__ .__name__ } ({ self .x !r} , { self .y !r} )'
257
274
numbers .Complex .register (Rect )
@@ -780,8 +797,8 @@ def testMixedMultiplication(self):
780
797
self .assertRaises (TypeError , operator .mul , Polar (4 , 2 ), F (3 , 2 ))
781
798
self .assertTypedEquals (Rect (4 , 3 ) * F (3 , 2 ), 6.0 + 4.5j )
782
799
783
- self .assertTypedEquals (F (3 , 2 ) * One , F ( 3 , 2 ))
784
- self .assertRaises (TypeError , operator .mul , One , F (3 , 2 ))
800
+ self .assertEqual (F (3 , 2 ) * Symbolic ( 'X' ), Symbolic ( '3/2 * X' ))
801
+ self .assertRaises (TypeError , operator .mul , Symbolic ( 'X' ) , F (3 , 2 ))
785
802
786
803
def testMixedDivision (self ):
787
804
self .assertTypedEquals (F (1 , 10 ), F (1 , 10 ) / 1 )
@@ -805,8 +822,8 @@ def testMixedDivision(self):
805
822
self .assertRaises (TypeError , operator .truediv , Polar (4 , 2 ), F (2 , 3 ))
806
823
self .assertTypedEquals (Rect (4 , 3 ) / F (2 , 3 ), 6.0 + 4.5j )
807
824
808
- self .assertTypedEquals (F (3 , 2 ) / One , F ( 3 , 2 ))
809
- self .assertRaises (TypeError , operator .truediv , One , F (2 , 3 ))
825
+ self .assertEqual (F (3 , 2 ) / Symbolic ( 'X' ), Symbolic ( '3/2 / X' ))
826
+ self .assertRaises (TypeError , operator .truediv , Symbolic ( 'X' ) , F (2 , 3 ))
810
827
811
828
def testMixedIntegerDivision (self ):
812
829
self .assertTypedEquals (0 , F (1 , 10 ) // 1 )
@@ -844,8 +861,8 @@ def testMixedIntegerDivision(self):
844
861
self .assertRaises (TypeError , operator .mod , F (3 , 2 ), Polar (4 , 2 ))
845
862
self .assertRaises (TypeError , operator .mod , Rect (4 , 3 ), F (2 , 3 ))
846
863
847
- self .assertTypedEquals (F (3 , 2 ) % One , F ( 1 , 2 ))
848
- self .assertRaises (TypeError , operator .mod , One , F (2 , 3 ))
864
+ self .assertTypedEquals (F (3 , 2 ) % Symbolic ( 'X' ), Symbolic ( '3/2 % X' ))
865
+ self .assertRaises (TypeError , operator .mod , Symbolic ( 'X' ) , F (2 , 3 ))
849
866
850
867
def testMixedPower (self ):
851
868
# ** has more interesting conversion rules.
@@ -890,8 +907,8 @@ def testMixedPower(self):
890
907
self .assertTypedEquals (Polar (4 , 2 ) ** F (- 3 , 1 ), Polar (0.015625 , - 6 ))
891
908
self .assertTypedEquals (Polar (4 , 2 ) ** F (- 3 , 2 ), Polar (0.125 , - 3.0 ))
892
909
893
- self .assertTypedEquals (F (3 , 2 ) ** One , 1.5 )
894
- self .assertTypedEquals (One ** F (3 , 2 ), One )
910
+ self .assertTypedEquals (F (3 , 2 ) ** Symbolic ( 'X' ), Symbolic ( ' 1.5 ** X' ) )
911
+ self .assertTypedEquals (Symbolic ( 'X' ) ** F (3 , 2 ), Symbolic ( 'X ** 1.5' ) )
895
912
896
913
def testMixingWithDecimal (self ):
897
914
# Decimal refuses mixed arithmetic (but not mixed comparisons)
0 commit comments