[Tutor] how to make classes play well together

C or L Smith smiles at worksmail.net
Fri Apr 10 18:34:30 CEST 2009

Unum is a module that allows one to handle units with numbers, e.g. 3*M -> 3 [m], a measurement of 3 meters.

I have a module that I wrote some time ago that handles uncertainties with numbers as they are involved with calculations. Let's call it the pnum module (for physical numbers) e.g. pnum(3,.1) specifies a value of 3 +/- 0.1. 

I worked with someone at that time of writing it who said..."it would be nice to get this working with Unum." Well...it's that time, perhaps, but I could use some help in knowing what's the best way to go.

(Q1) My basic question is how to have these two work together. If they are to be two separate entities, my routines need to check whether they are dealing with a unum or not before doing certain operations. e.g. my routines define "x" and "u" attributes for the numbers, but if the pnum gets wrapped up with a unum then asking for x and u no longer works. I have to extract the pnum part from the pnum/unum composite before asking for x and u. But...does that mean I have to be unum aware in the pnum module? i.e. I have to import unum (actually Unum from unum) so I can figure out what I am dealing with in the routines that I have defined, e.g.

 def __mul__(self, other):
  if isinstance(other,Unum):
   return other*self
   return pnum(self.x*other.x,math.hypot(other.u*self.x,other.x*self.u),1)


 def cos(x):
  if isinstance(x,pnum):
   return x.cos()
  elif isinstance(x,Unum):
   arg = x.asNumber(1)
   if isinstance(arg,pnum):#it's a pnum unum
    return pnum(arg[0],arg[1],1).cos()
   else:#it's a pure unum
    return math.cos(arg)
  return math.cos(x)

Since unums only have a simple numeric portion, they don't need a special cos() routine, but my pnum's have two numbers to keep track of and so there *is* a special cos() routine. When a script calls for cos(x) my module handles it, checks to see who x is and then acts accordingly. I can't just have a test for whether x is a pnum and if not, pass off the result to math.cos(x) because math.cos() will ask for a float, unum will ask pnum for a float representation...and I don't know what to give back. If I give back the value part of pnum then I lose the uncertainty portion. If I give back the value, uncertainty pnum tuple it generate "TypeError: __float__ returned non-float (type instance)". So...you can see what I do to try handle the situation with the cos() routine above. Which brings me to the 2nd question.

(Q2) If someone doesn't have unum installed, they should still be able to run pnum...but now it has tests for unums sprinkled all throughout it. Do I now have to put the tests for unums inside a try/except sort of structure to allow pnum to run if unum isn't present?

Right now everything is working only so long as pnum imports unum so all the tests work. The two directions I would go now (not knowing any better) would be to a) put unum tests (and the import itself?) into try/except blocks or b) weave pnums into unum so that unums get a new attribute and all the instructions on how to deal with the value,uncertainty tuple that every numeric part of a unum would have (instead of just a float).

Thanks for help in pointing me in a sane direction,

More information about the Tutor mailing list