Skip to content

Commit 9faed1f

Browse files
committed
Add files to repo.
1 parent fd6ef3e commit 9faed1f

File tree

3 files changed

+875
-0
lines changed

3 files changed

+875
-0
lines changed

README.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Python Magic Methods
2+
====================
3+
4+
Slides and code for talk on Python's magic methods.
5+
6+

great_circle.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
from math import pi, sin, asin, cos, sqrt
2+
3+
4+
JFK = ("40.641108", "-73.778246")
5+
LAX = ("33.941544", "-118.408755")
6+
SLC = ("40.788139", "-111.980268")
7+
8+
9+
class Point(object):
10+
"""
11+
Defines a point on the earth's surface using latitude and logitude.
12+
"""
13+
LATITUDE = 0
14+
LONGITUDE = 1
15+
16+
def __init__(self, p):
17+
"""
18+
Initialize instance.
19+
"""
20+
self.latitude = self.to_radians(float(p[self.LATITUDE]))
21+
self.longitude = self.to_radians(float(p[self.LONGITUDE]))
22+
23+
def to_radians(self, deg):
24+
"""
25+
Convert degrees to radians.
26+
"""
27+
rad = deg * pi / 180
28+
return rad
29+
30+
def coordinates(self):
31+
latitude = (self.latitude / pi) * 180
32+
latitude_deg, latitude_min = str(latitude).split(".")
33+
latitude_deg = int(latitude_deg)
34+
latitude_min = round(float("0.{}".format(latitude_min)) * 60)
35+
if latitude > 0:
36+
latitude_dir = 'N'
37+
else:
38+
latitude_dir = 'S'
39+
40+
longitude = (self.longitude / pi) * 180
41+
longitude_deg, longitude_min = str(longitude).split(".")
42+
longitude_deg = int(longitude_deg)
43+
longitude_min = round(float("0.{}".format(longitude_min)) * 60)
44+
if longitude > 0:
45+
longitude_dir = 'E'
46+
else:
47+
longitude_dir = 'W'
48+
49+
latitude_str = "{deg}\u00B0 {min}\u2032 {dir}".format(
50+
deg=abs(latitude_deg), min=latitude_min, dir=latitude_dir)
51+
longitude_str = "{deg}\u00B0 {min}\u2032 {dir}".format(
52+
deg=abs(longitude_deg), min=longitude_min, dir=longitude_dir)
53+
54+
return "{latitude}, {longitude}".format(
55+
latitude=latitude_str, longitude=longitude_str)
56+
57+
def calculate_distance(self, other):
58+
"""
59+
Demo how it might work without using magic methods.
60+
"""
61+
distance = 2.0 * asin(
62+
sqrt((sin((self.latitude-other.latitude)) / 2.0) ** 2 +
63+
cos(self.latitude) * cos(other.latitude) *
64+
(sin((self.longitude-other.longitude) / 2.0)) ** 2))
65+
return "{0:.2f}".format(distance* 180 * 60 / pi)
66+
67+
68+
class PointMagicMixin(object):
69+
"""
70+
Adds magic methods to base class.
71+
"""
72+
73+
def __del__(self):
74+
"""
75+
Destructor called when object destroyed by Python GC.
76+
"""
77+
print("__del__() method called on {:.2f}.".format(self))
78+
79+
def __eq__(self, other):
80+
"""
81+
Implement behavior for Python "==" operator.
82+
"""
83+
return ((self.latitude == other.latitude) and
84+
(self.longitude == other.longitude))
85+
86+
def __format__(self, formatstr):
87+
"""
88+
Implement behavior for use in format().
89+
"""
90+
# If no formatstr, just return the standard coordinates.
91+
if not formatstr:
92+
return self.coordinates()
93+
94+
# If floating point format, return coordinates in radians formatted
95+
# to specified precision.
96+
if formatstr.endswith('f') and formatstr.startswith('.'):
97+
precision = formatstr[1]
98+
return self._represent_output(precision)
99+
100+
# Otherwise, just return radians with all decimals.
101+
return self._represent_output()
102+
103+
def __repr__(self):
104+
"""
105+
Implement behavior for Python repr() command.
106+
"""
107+
return self._represent_output(5)
108+
109+
def __str__(self):
110+
"""
111+
Instance unicode string representation.
112+
"""
113+
return self.coordinates()
114+
115+
def __sub__(self, other):
116+
"""
117+
Subtract two points. Return Distance instance.
118+
"""
119+
return MagicDistance(self, other)
120+
121+
def _represent_output(self, precision=None):
122+
"""
123+
Return string representation of point to specified precision. Intended
124+
to be used in support of magic methods __repr__() and __format__().
125+
"""
126+
formatstr = "Point({{latitude:{}f}}, {{longitude:{}f}})"
127+
if not precision:
128+
formatstr = formatstr.format('', '')
129+
else:
130+
float_format = ".{}".format(precision)
131+
formatstr = formatstr.format(float_format, float_format)
132+
return formatstr.format(
133+
latitude=self.latitude, longitude=self.longitude)
134+
135+
136+
class MagicPoint(Point, PointMagicMixin):
137+
pass
138+
139+
140+
class Distance(object):
141+
"""
142+
Represents a distance between two points as defined by respective latitude
143+
and longitude.
144+
"""
145+
146+
def __init__(self, p1, p2):
147+
self.p1 = p1
148+
self.p2 = p2
149+
self.distance = self.calculate_distance(p1, p2)
150+
151+
def calculate_distance(self, p1, p2):
152+
distance = 2.0 * asin(
153+
sqrt((sin((p1.latitude-p2.latitude)) / 2.0) ** 2 +
154+
cos(p1.latitude) * cos(p2.latitude) *
155+
(sin((p1.longitude-p2.longitude) / 2.0)) ** 2))
156+
return distance * 180 * 60 / pi
157+
158+
class DistanceMagicMixin(object):
159+
160+
def __call__(self, p1, p2):
161+
"""
162+
This method called when object instance called like a function.
163+
"""
164+
distance = self.calculate_distance(p1, p2)
165+
return "{0:.2f}".format(distance)
166+
167+
def __del__(self):
168+
"""
169+
Destructor called when object destroyed by Python GC.
170+
"""
171+
print("__del__() method called on {}.".format(self))
172+
173+
def __ge__(self, other):
174+
"""
175+
Implement behavior for Python ">=" operator.
176+
"""
177+
return self.distance >= other.distance
178+
179+
def __gt__(self, other):
180+
"""
181+
Implement behavior for Python ">" operator.
182+
"""
183+
return self.distance > other.distance
184+
185+
def __le__(self, other):
186+
"""
187+
Implement behavior for Python "<=" operator.
188+
"""
189+
return self.distance <= other.distance
190+
191+
def __lt__(self, other):
192+
"""
193+
Implement behavior for Python "<" operator.
194+
"""
195+
return self.distance < other.distance
196+
197+
def __repr__(self):
198+
"""
199+
Implement behavior for Python repr() command.
200+
"""
201+
return "MagicDistance(({}) ==> ({}))".format(self.p1, self.p2)
202+
203+
def __str__(self):
204+
"""
205+
String representation for class instance. Python calls this method
206+
when:
207+
208+
print(distance_obj)
209+
"""
210+
return "{0:.2f}".format(self.distance)
211+
212+
213+
class MagicDistance(Distance, DistanceMagicMixin):
214+
pass
215+

0 commit comments

Comments
 (0)