Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

# Copyright 2007 Google, Inc. All Rights Reserved. 

# Licensed to PSF under a Contributor Agreement. 

 

"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141. 

 

TODO: Fill out more detailed documentation on the operators.""" 

 

from abc import ABCMeta, abstractmethod 

 

__all__ = ["Number", "Complex", "Real", "Rational", "Integral"] 

 

class Number(metaclass=ABCMeta): 

"""All numbers inherit from this class. 

 

If you just want to check if an argument x is a number, without 

caring what kind, use isinstance(x, Number). 

""" 

__slots__ = () 

 

# Concrete numeric types must provide their own hash implementation 

__hash__ = None 

 

 

## Notes on Decimal 

## ---------------- 

## Decimal has all of the methods specified by the Real abc, but it should 

## not be registered as a Real because decimals do not interoperate with 

## binary floats (i.e. Decimal('3.14') + 2.71828 is undefined). But, 

## abstract reals are expected to interoperate (i.e. R1 + R2 should be 

## expected to work if R1 and R2 are both Reals). 

 

class Complex(Number): 

"""Complex defines the operations that work on the builtin complex type. 

 

In short, those are: a conversion to complex, .real, .imag, +, -, 

*, /, abs(), .conjugate, ==, and !=. 

 

If it is given heterogeneous arguments, and doesn't have special 

knowledge about them, it should fall back to the builtin complex 

type as described below. 

""" 

 

__slots__ = () 

 

@abstractmethod 

def __complex__(self): 

"""Return a builtin complex instance. Called for complex(self).""" 

 

def __bool__(self): 

"""True if self != 0. Called for bool(self).""" 

return self != 0 

 

@property 

@abstractmethod 

def real(self): 

"""Retrieve the real component of this number. 

 

This should subclass Real. 

""" 

raise NotImplementedError 

 

@property 

@abstractmethod 

def imag(self): 

"""Retrieve the imaginary component of this number. 

 

This should subclass Real. 

""" 

raise NotImplementedError 

 

@abstractmethod 

def __add__(self, other): 

"""self + other""" 

raise NotImplementedError 

 

@abstractmethod 

def __radd__(self, other): 

"""other + self""" 

raise NotImplementedError 

 

@abstractmethod 

def __neg__(self): 

"""-self""" 

raise NotImplementedError 

 

@abstractmethod 

def __pos__(self): 

"""+self""" 

raise NotImplementedError 

 

def __sub__(self, other): 

"""self - other""" 

return self + -other 

 

def __rsub__(self, other): 

"""other - self""" 

return -self + other 

 

@abstractmethod 

def __mul__(self, other): 

"""self * other""" 

raise NotImplementedError 

 

@abstractmethod 

def __rmul__(self, other): 

"""other * self""" 

raise NotImplementedError 

 

@abstractmethod 

def __truediv__(self, other): 

"""self / other: Should promote to float when necessary.""" 

raise NotImplementedError 

 

@abstractmethod 

def __rtruediv__(self, other): 

"""other / self""" 

raise NotImplementedError 

 

@abstractmethod 

def __pow__(self, exponent): 

"""self**exponent; should promote to float or complex when necessary.""" 

raise NotImplementedError 

 

@abstractmethod 

def __rpow__(self, base): 

"""base ** self""" 

raise NotImplementedError 

 

@abstractmethod 

def __abs__(self): 

"""Returns the Real distance from 0. Called for abs(self).""" 

raise NotImplementedError 

 

@abstractmethod 

def conjugate(self): 

"""(x+y*i).conjugate() returns (x-y*i).""" 

raise NotImplementedError 

 

@abstractmethod 

def __eq__(self, other): 

"""self == other""" 

raise NotImplementedError 

 

Complex.register(complex) 

 

 

class Real(Complex): 

"""To Complex, Real adds the operations that work on real numbers. 

 

In short, those are: a conversion to float, trunc(), divmod, 

%, <, <=, >, and >=. 

 

Real also provides defaults for the derived operations. 

""" 

 

__slots__ = () 

 

@abstractmethod 

def __float__(self): 

"""Any Real can be converted to a native float object. 

 

Called for float(self).""" 

raise NotImplementedError 

 

@abstractmethod 

def __trunc__(self): 

"""trunc(self): Truncates self to an Integral. 

 

Returns an Integral i such that: 

* i>0 iff self>0; 

* abs(i) <= abs(self); 

* for any Integral j satisfying the first two conditions, 

abs(i) >= abs(j) [i.e. i has "maximal" abs among those]. 

i.e. "truncate towards 0". 

""" 

raise NotImplementedError 

 

@abstractmethod 

def __floor__(self): 

"""Finds the greatest Integral <= self.""" 

raise NotImplementedError 

 

@abstractmethod 

def __ceil__(self): 

"""Finds the least Integral >= self.""" 

raise NotImplementedError 

 

@abstractmethod 

def __round__(self, ndigits=None): 

"""Rounds self to ndigits decimal places, defaulting to 0. 

 

If ndigits is omitted or None, returns an Integral, otherwise 

returns a Real. Rounds half toward even. 

""" 

raise NotImplementedError 

 

def __divmod__(self, other): 

"""divmod(self, other): The pair (self // other, self % other). 

 

Sometimes this can be computed faster than the pair of 

operations. 

""" 

return (self // other, self % other) 

 

def __rdivmod__(self, other): 

"""divmod(other, self): The pair (self // other, self % other). 

 

Sometimes this can be computed faster than the pair of 

operations. 

""" 

return (other // self, other % self) 

 

@abstractmethod 

def __floordiv__(self, other): 

"""self // other: The floor() of self/other.""" 

raise NotImplementedError 

 

@abstractmethod 

def __rfloordiv__(self, other): 

"""other // self: The floor() of other/self.""" 

raise NotImplementedError 

 

@abstractmethod 

def __mod__(self, other): 

"""self % other""" 

raise NotImplementedError 

 

@abstractmethod 

def __rmod__(self, other): 

"""other % self""" 

raise NotImplementedError 

 

@abstractmethod 

def __lt__(self, other): 

"""self < other 

 

< on Reals defines a total ordering, except perhaps for NaN.""" 

raise NotImplementedError 

 

@abstractmethod 

def __le__(self, other): 

"""self <= other""" 

raise NotImplementedError 

 

# Concrete implementations of Complex abstract methods. 

def __complex__(self): 

"""complex(self) == complex(float(self), 0)""" 

return complex(float(self)) 

 

@property 

def real(self): 

"""Real numbers are their real component.""" 

return +self 

 

@property 

def imag(self): 

"""Real numbers have no imaginary component.""" 

return 0 

 

def conjugate(self): 

"""Conjugate is a no-op for Reals.""" 

return +self 

 

Real.register(float) 

 

 

class Rational(Real): 

""".numerator and .denominator should be in lowest terms.""" 

 

__slots__ = () 

 

@property 

@abstractmethod 

def numerator(self): 

raise NotImplementedError 

 

@property 

@abstractmethod 

def denominator(self): 

raise NotImplementedError 

 

# Concrete implementation of Real's conversion to float. 

def __float__(self): 

"""float(self) = self.numerator / self.denominator 

 

It's important that this conversion use the integer's "true" 

division rather than casting one side to float before dividing 

so that ratios of huge integers convert without overflowing. 

 

""" 

return self.numerator / self.denominator 

 

 

class Integral(Rational): 

"""Integral adds a conversion to int and the bit-string operations.""" 

 

__slots__ = () 

 

@abstractmethod 

def __int__(self): 

"""int(self)""" 

raise NotImplementedError 

 

def __index__(self): 

"""Called whenever an index is needed, such as in slicing""" 

return int(self) 

 

@abstractmethod 

def __pow__(self, exponent, modulus=None): 

"""self ** exponent % modulus, but maybe faster. 

 

Accept the modulus argument if you want to support the 

3-argument version of pow(). Raise a TypeError if exponent < 0 

or any argument isn't Integral. Otherwise, just implement the 

2-argument version described in Complex. 

""" 

raise NotImplementedError 

 

@abstractmethod 

def __lshift__(self, other): 

"""self << other""" 

raise NotImplementedError 

 

@abstractmethod 

def __rlshift__(self, other): 

"""other << self""" 

raise NotImplementedError 

 

@abstractmethod 

def __rshift__(self, other): 

"""self >> other""" 

raise NotImplementedError 

 

@abstractmethod 

def __rrshift__(self, other): 

"""other >> self""" 

raise NotImplementedError 

 

@abstractmethod 

def __and__(self, other): 

"""self & other""" 

raise NotImplementedError 

 

@abstractmethod 

def __rand__(self, other): 

"""other & self""" 

raise NotImplementedError 

 

@abstractmethod 

def __xor__(self, other): 

"""self ^ other""" 

raise NotImplementedError 

 

@abstractmethod 

def __rxor__(self, other): 

"""other ^ self""" 

raise NotImplementedError 

 

@abstractmethod 

def __or__(self, other): 

"""self | other""" 

raise NotImplementedError 

 

@abstractmethod 

def __ror__(self, other): 

"""other | self""" 

raise NotImplementedError 

 

@abstractmethod 

def __invert__(self): 

"""~self""" 

raise NotImplementedError 

 

# Concrete implementations of Rational and Real abstract methods. 

def __float__(self): 

"""float(self) == float(int(self))""" 

return float(int(self)) 

 

@property 

def numerator(self): 

"""Integers are their own numerators.""" 

return +self 

 

@property 

def denominator(self): 

"""Integers have a denominator of 1.""" 

return 1 

 

Integral.register(int)