Key Word(s): Privacy, Name mangling, Modules, vars
Exercise 2: "Private" Methods and Names in Python¶
Background¶
We will consider two extensions to the real numbers: complex numbers and dual numbers.
Complex Numbers¶
A complex number is defined as $$z = a + ib$$ where $i^{2} = -1$. $a$ is the real part and $b$ is the imaginary part. The polar form of a complex number is $$z = \left|z\right|e^{i\theta}$$ where $\left|z\right|^{2} = zz^{*} = a^{2} + b^{2}$ and $z^{*} = a - ib$ is the complex conjugate of $z$. The angle between $a$ and $b$ is given by $$\theta = \tan^{-1}\left(\frac{b}{a}\right).$$
Dual Numbers¶
The dual numbers look similar. We have $$d = a + \epsilon b$$ where $\epsilon$ is a number (not zero!) such that $\epsilon^{2} = 0$. Once again $a$ is the real part, but here $b$ is the dual part. The polar form of this number is $$d = \displaystyle a\left(1 + \epsilon \frac{b}{a}\right).$$ Note that the magnitude of the dual number $\left|d\right| = a$ since $dd^{*} = \left(a + \epsilon b\right)\left(a - \epsilon b\right) = a$ where $d^{*} = a - \epsilon b$ is the conjugate of $d$. Finally, the angular part is $$m = \dfrac{b}{a}.$$
Dual numbers are a route to automatic differentiation. We'll mention them again in the AD lectures.
Problem Description¶
Part 1¶
For today, your task is to write a module called mynumbers.py
. The module should contain at a minimum the following:
- A base class called
RealExtensions
with a constructor that accepts $a$ and $b$. - A subclass called
Complex
(inherits fromRealExtensions
) that has the following methods:- Compute the magnitude of the complex number
- Note: This method should be preceeded by a single underscore to indicate that it should not be accessed by a user.
- Compute the "angle" of the complex number
- Note: This method should be preceeded by a single underscore to indicate that it should not be accessed by a user.
- Compute the polar form of the complex number using
_magnitude()
and_angle()
- Compute the magnitude of the complex number
- A subclass called
Dual
(inherits fromRealExtensions
) that has methods for compute the magnitude and "angle" of the dual number.- Compute the magnitude of the dual number
- Note: This method should be preceeded by a single underscore to indicate that it should not be accessed by a user.
- Compute the "angle" of the dual number
- Note: This method should be preceeded by a single underscore to indicate that it should not be accessed by a user.
- Compute the polar form of the dual number using
_magnitude()
and_angle()
- Compute the magnitude of the dual number
The choice of "hiding" the magnitude()
and angle()
methods may not be a good one. The goal is to show that this is not really privacy; it's more of a contract between people using the code. Note that a user can still access _magnitude()
and _angle()
.
Import your module using import mynumbers
and play around with creating complex and dual numbers. Demo your code in the cell below:¶
import mynumbers as myn
zc = myn.Complex(2.0,1.0) # complex number
print(zc.real, zc.imag)
zd = myn.Dual(2.0,2.0)
print(zd.real, zd.dual)
zc.polar_form()
print(zc.r, zc.theta)
zd.polar_form()
print(zd.r, zd.theta)
Part 2¶
Once you're happy with your module, make the following change:
- Rename the
Complex
subclass as_Complex
. Save the new module asmynumbers_p
. - Now import your module using
from mynumbers_p import *
- Try to create a complex number. What happens?
- Note: You can use
dir()
to see what's in your namespace.
- Note: You can use
Demo your code in the cell below.
from mynumbers_p import *
zc = Complex(2.0, 1.0)
Part 3: Extra¶
For some reason you decide to store the components of your number in an immutable data structure. You do this in the base class via a tuple. You also decide to provide a method called number
in a subclass which stores the number as a list (mutable). If the user calls the number
method, then you automatically store the number in an immutable data structure as specified in the base class constructor. You use super()
to call the base class constructor. Meanwhile, you store the mutable list of numbers as an attribute in the subclass. To avoid possible namespace collisions, you elect to mangle the names.
Save your module as mynumbers_m.py
.
Your module should be importatable and demoed as follows:
import mynumbers_m as myn_m
z = myn_m.Complex(1,1)
z.number()
print(z._RealExtensions__number, z._Complex__number)
Deliverables¶
mynumbers.py
mynumbers_p.py
mynumbers_m.py
--- Optional- A demo notebook saved as
lecture8-demo.ipynb
- The notebook can look exactly like this one (problem statements and all).