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'

# ...