#! /usr/bin/env python # -*- coding: utf-8 -*- """ Quick introduction to classes and objects. Intensive use of doctests to try and experiment every functions and methods. Credit: Lilian Besson for http://perso.crans.org/besson/cs101/solutions/examples/ License: GPLv3 """ class ComplexNumber(object): """ A simple class to represent a complex number. Example: >>> z1 = ComplexNumber(x=1, y=0) >>> print z1 (1, 0) >>> z2 = ComplexNumber(1, 1) >>> print "z2 = ComplexNumber(1, 1) is {}.".format(z2) z2 = ComplexNumber(1, 1) is (1, 1). """ def __init__(self, x=0, y=0): """ Create a complex number. - x: is the real part (default to 0), - y: is the complex part (default to 0). Example: >>> z0 = ComplexNumber() >>> print z0 (0, 0) """ # self is a special 'variable' representing the object itself. self.x = x self.y = y # This object will have two attributes, x and y, initialzed here: def __str__(self): """ The function used to convert the object self to a string. For a complex number, we chose to print it like '(x, y)' simply. This special method __str__ is used to compute str(self) == self.__str__() Example: >>> z3 = ComplexNumber(-1, 8) >>> print str(z3) (-1, 8) >>> print z3 # print use 'str' implicitely! (-1, 8) """ # Or with # return "({}, {})".format(self.x, self.y) # This can be done like this: return "(" + str(self.x) + ", " + str(self.y) + ")" def __repr__(self): """ The function used to convert the object self to a string with repr. For a complex number, we chose to print it like '(x, y)' simply. This special method __str__ is used to compute repr(self) == self.__repr__() Example: >>> from math import sqrt >>> z = ComplexNumber(-sqrt(2)/2, sqrt(2)/2) >>> print z # print use 'str' implicitely! (-0.707106781187, 0.707106781187) >>> print repr(z) (-0.7071067811865476, 0.7071067811865476) """ return "(" + repr(self.x) + ", " + repr(self.y) + ")" def __abs__(self): """ The function used to compute abs(self) == self.__abs__(). Example: >>> print abs(ComplexNumber(2, 0)) 2.0 >>> print abs(ComplexNumber(0, 4)) 4.0 >>> print abs(ComplexNumber(-3, 3)) 4.24264068712 """ from math import sqrt return sqrt(self.x ** 2 + self.y ** 2) def conjugate(self): """ Conjugate the complex number (modify the object). Example: >>> z5 = ComplexNumber(8, -2) >>> z5.conjugate() >>> print z5 (8, 2) >>> z5.conjugate() >>> print z5 (8, -2) """ self.y = - self.y def __add__(self, z): """ Add two complex numbers (produce a new object). This special method `__add__` is designed to change to behavior of the natural '+' operator. a.__add__(b) <=> a + b Example: >>> z6 = ComplexNumber(8, -2) >>> z7 = z6 # Warning: here z7 is a link to z6 >>> z6.conjugate() # So this changes both z6 and z7! >>> print z6 + z7 (16, 4) >>> print ComplexNumber(0, 2014) + ComplexNumber(2015, 0) (2015, 2014) >>> print ComplexNumber(2015, 0) + ComplexNumber(0, 2014) (2015, 2014) """ newx = self.x + z.x newy = self.y + z.y return ComplexNumber(x=newx, y=newy) def __mul__(self, z): """ Multiply two complex numbers (produce a new object). This special method `__mul__` is designed to change to behavior of the natural '*' operator. a.__mul__(b) <=> a * b .. note:: More details ? Please refer to `that page of the documentation `_ for a list of special methods like this. Example: >>> z8 = ComplexNumber(2, 3) >>> print z8 * z8 (-5, 12) """ newx = self.x * z.x - self.y * z.y newy = self.x * z.y + self.y * z.x return ComplexNumber(x=newx, y=newy) def arg(self, ourself=True): """ Try to compute the principal complex argument. Exception: Fails if and only if self == (0, 0). Example: >>> print ComplexNumber(3, 0).arg() # 0 0.0 >>> print ComplexNumber(3, 3).arg() # pi/4 0.785398163397 >>> print ComplexNumber(0, 6).arg() # pi/2 1.57079632679 >>> print ComplexNumber(-2, 4).arg() # something between pi/2 and pi 2.0344439358 >>> print ComplexNumber(-2, 0).arg() # pi 3.14159265359 >>> print ComplexNumber(-1, -1).arg() # -3pi/4 -2.35619449019 >>> print ComplexNumber(0, -172).arg() # -pi/2 -1.57079632679 >>> print ComplexNumber(0, 0).arg() # ValueError Traceback (most recent call last): ... ValueError: principal argument not defined for (0, 0) """ # First idea, cheating by using from math import atan2, atan, pi if not ourself: if self.x == 0 and self.y == 0: raise ValueError("principal argument not defined for (0, 0)") return atan2(self.y, self.x) # Second idea, doing it ourself # (cf. https://en.wikipedia.org/wiki/Atan2#Definition_and_computation) if self.x > 0: return atan(self.y/self.x) elif self.x < 0 and self.y >= 0: return atan(self.y/self.x) + pi elif self.x < 0 and self.y < 0: return atan(self.y/self.x) - pi elif self.x == 0 and self.y > 0: return pi / 2.0 elif self.x == 0 and self.y < 0: return - pi / 2.0 elif self.x == 0 and self.y == 0: raise ValueError("principal argument not defined for (0, 0)") else: raise ValueError("unknown complex value") # Some examples if __name__ == '__main__': from doctest import testmod testmod(verbose=False)