P
Paul Rubin
I'm sure this has been done before, but it just struck my fancy, an
example of Python's "emulating numeric types", inspired by the old
Unix "units" utility, and the Frink language. The language reference
for these features is somewhat unclear and I'll enter some sourceforge
items. Maybe I'll write a calculator-with-units around it. If I were
really industrious, I'd attempt a Frink-like interpreter, but don't
hold your breath.
================================================================
try:
set
except NameError:
from sets import Set as set # python 2.3 ...
class Unit:
def __init__(self, coef, dimensions):
self.dimensions = dimensions
self.coef = coef
def __add__(self, other):
if self.dimensions != other.dimensions:
raise TypeError, ('dimension mismatch', self, other)
return Unit(self.coef + other.coef, self.dimensions)
def __sub__(self,other):
return self + (-1.0) * other
def __rmul__(self, x):
return x*self
def __rdiv__(self, x):
return x/self
def __mul__(self, other):
pc = self.coef * other.coef
sd, od = self.dimensions, other.dimensions
basis = set(sd.keys()) | set(od.keys())
pa = [(d, sd.get(d,0)+od.get(d,0)) for d in basis]
pd = dict([(d,a) for d,a in pa if a != 0])
return Unit(pc, pd)
def __repr__(self):
a = [repr(self.coef)]
for d,c in self.dimensions.iteritems():
s = str(d)
if c != 1: s += '^'+str(c)
a.append(s)
return '*'.join(a)
def __div__(self, other):
od = other.dimensions
inv = Unit(1.0 / other.coef,
dict([(d, -od[d]) for d in od]))
return self * inv
def __pow__(self, n):
n = n.coef
if self.dimensions and type(n) not in (int,long):
raise TypeError, ('exponent must be integer', self,n)
cn = self.coef ** n
sd = self.dimensions
return Unit(self.coef ** n,
dict([(d,sd[d]*n) for d in sd]))
def __coerce__(self, other):
if isinstance(other, Unit): return self, other
return self, Unit(other, {})
def __float__(self):
if self.dimensions:
raise TypeError, ('unit must be dimensionless for float cast', self)
return float(self.coef)
def __int__(self):
return int(float(self))
def base_unit(name):
return Unit(1.0, {name : 1})
meter = base_unit('m')
second = base_unit('s')
kg = base_unit('kg')
coulomb = base_unit('coulomb')
centimeter = meter / 100
inch = 2.54 * centimeter
foot = ft = 12 * inch
mile = 5280*foot
minute=60*second
hour=60*minute
speed_limit = 55 * mile / hour
furlong = mile / 8
day = 24 * hour
fortnight = 14 * day
# could include more units but you get the idea
c = 186282*mile/second
print 'speed of light =', c/(furlong/fortnight), 'furlongs per fortnight'
# ...
example of Python's "emulating numeric types", inspired by the old
Unix "units" utility, and the Frink language. The language reference
for these features is somewhat unclear and I'll enter some sourceforge
items. Maybe I'll write a calculator-with-units around it. If I were
really industrious, I'd attempt a Frink-like interpreter, but don't
hold your breath.
================================================================
try:
set
except NameError:
from sets import Set as set # python 2.3 ...
class Unit:
def __init__(self, coef, dimensions):
self.dimensions = dimensions
self.coef = coef
def __add__(self, other):
if self.dimensions != other.dimensions:
raise TypeError, ('dimension mismatch', self, other)
return Unit(self.coef + other.coef, self.dimensions)
def __sub__(self,other):
return self + (-1.0) * other
def __rmul__(self, x):
return x*self
def __rdiv__(self, x):
return x/self
def __mul__(self, other):
pc = self.coef * other.coef
sd, od = self.dimensions, other.dimensions
basis = set(sd.keys()) | set(od.keys())
pa = [(d, sd.get(d,0)+od.get(d,0)) for d in basis]
pd = dict([(d,a) for d,a in pa if a != 0])
return Unit(pc, pd)
def __repr__(self):
a = [repr(self.coef)]
for d,c in self.dimensions.iteritems():
s = str(d)
if c != 1: s += '^'+str(c)
a.append(s)
return '*'.join(a)
def __div__(self, other):
od = other.dimensions
inv = Unit(1.0 / other.coef,
dict([(d, -od[d]) for d in od]))
return self * inv
def __pow__(self, n):
n = n.coef
if self.dimensions and type(n) not in (int,long):
raise TypeError, ('exponent must be integer', self,n)
cn = self.coef ** n
sd = self.dimensions
return Unit(self.coef ** n,
dict([(d,sd[d]*n) for d in sd]))
def __coerce__(self, other):
if isinstance(other, Unit): return self, other
return self, Unit(other, {})
def __float__(self):
if self.dimensions:
raise TypeError, ('unit must be dimensionless for float cast', self)
return float(self.coef)
def __int__(self):
return int(float(self))
def base_unit(name):
return Unit(1.0, {name : 1})
meter = base_unit('m')
second = base_unit('s')
kg = base_unit('kg')
coulomb = base_unit('coulomb')
centimeter = meter / 100
inch = 2.54 * centimeter
foot = ft = 12 * inch
mile = 5280*foot
minute=60*second
hour=60*minute
speed_limit = 55 * mile / hour
furlong = mile / 8
day = 24 * hour
fortnight = 14 * day
# could include more units but you get the idea
c = 186282*mile/second
print 'speed of light =', c/(furlong/fortnight), 'furlongs per fortnight'
# ...