Thanks for your help! I've rewritten it with many of your suggestions
and will definitely use this as a reference for future scripts.
Here's the updated one.
(I also played around with lambdas, I don't know if they're actually
needed/useful there, but I haven't used them before and I wanted some
practice with them).
I ran into some trouble with string.strip(). I worked around it by
simply piling on more strip statements, although I doubt that's the
correct way to do it :P. It's in the splitInput() function, inside the
parseInput() function.
> That's a lot of comments for such a small program, so keep in mind you don't
> have to do everything I (or others :)) write. Some of the advice is generic in
> nature: e.g. you might not care about reuse in this particular case, but it's
> still good to know what you should pay attention to in the cases where you DO
> care.
I was afraid I hadn't commented enough! Well, now I know...
Thanks again,
Adam
#!/usr/bin/python
# Adam Gomaa, started Oct 24 2006 (finished same day)
# An attempt to clean up/improve v2, with suggestions from the -tutor list.
"""Calculate a single missing variable in the Ideal Gas Equation.
If no unknown is indicated (via an 'x'), indicate if the values satisfy the equation.
Includes functions to convert many units."""
from __future__ import division # so that i/i=f. But i'll use f/i anyway.
import string
R=8.314472 #in Kilopascal-Liters per Mole-Kelvin.
def getInput():
"""Get the user's input and return it in a list."""
temp_list=[]
#The following must be raw_inputs in case an 'x' is entered.
temp_list.append(raw_input("Pressure: "))
temp_list.append(raw_input("Volume: "))
temp_list.append(raw_input("Moles: "))
temp_list.append(raw_input("Temperature: "))
return temp_list
def parseInput(pressure,volume,moles,temperature):
"""Take input and determine whether a check or calculation is needed.
Also, determine units."""
pressureUnitDict={
'kpa':(lambda p:p),
'atm':(lambda p:p*101.325),
'torr':(lambda p:p*101.325/760.)
}
#The following have to be added afterwards since they reference the list
pressureUnitDict['a']=pressureUnitDict['atm'], #'a' refers to 'atm'
pressureUnitDict['mmhg']=pressureUnitDict['torr']
volumeUnitDict={
'l':(lambda v:v),
'ml':(lambda v:v/1000.),
'm3':(lambda v:v*1000.),
'gal':(lambda v:v*3.785411784)
}
volumeUnitDict['g']=volumeUnitDict['gal']
temperatureUnitDict={
'k':(lambda t:t),
'c':(lambda t:t+273.15),
'f':(lambda t:((t+459.67)*5/9.))
}
temperatureUnitDict['kelvin']=temperatureUnits['k']
temperatureUnitDict['celcius']=temperatureUnits['c']
temperatureUnitDict['farenheight']=temperatureUnits['f']
def splitInput(userInput):
#Because strip() only pulls out the matching charachters on each end,
# we need all these in order to "dig" through to the middle of the
# input to be sure we get a match when the user inputs a decimal.
# Comment out the indicated lines and use "50.000 atm""x""1""0c" as
# input to see what I'm talking about.
userInputString=userInput.strip(string.digits)
userInputString=userInputString.strip(string.punctuation)# this one
userInputString=userInputString.strip(string.digits)
userInputString=userInputString.strip(string.whitespace)
userInputString=userInputString.strip(string.digits)# and this one.
userInputValue=userInput.strip(string.letters)
userInputValue=userInputValue.strip(string.whitespace)
try:
return userInputString,float(userInputValue) #PV&T will be converted
#to floats here (if possible)
except ValueError:
return userInputString,'x'
def convertUnits(startingUnit,value):
"""Convert the passed value, with startingUnit, into appropriate units
for the rest of the module."""
#For next if block, each of these should pass value into a lambda
# function from the dictionaries above. In theory, then, it should
# always convert into kPa, l, or k.
if startingUnit in pressureUnitDict.keys(): #WHY the error?
return pressureUnitDict[startingUnit](value)
elif startingUnit in volumeUnitDict.keys():
return volumeUnitDict[startingUnit](value)
elif startingUnit in temperatureUnitDict.keys():
return temperatureUnitDict[startingUnit](value)
elif startingUnit=='x':
return value
else:
print '### Unknown unit "%s" -- Using default. ###' % startingUnit
return value
"""Return the same value in endingUnit"""
pressureUnit,pressureValue=splitInput(pressure)
volumeUnit,volumeValue=splitInput(volume)
temperatureUnit,temperatureValue=splitInput(temperature)
pressureValue=convertUnits(pressureUnit,pressureValue)
volumeValue=convertUnits(volumeUnit,volumeValue)
temperatureValue=convertUnits(temperatureUnit,temperatureValue)
#At this point, pressureValue, volumeValue, and temperatureValue
# should be floats that are in appropriate units.
try:
return pressureValue,volumeValue,float(moles),temperatureValue
#this works unless moles is 'x'
except ValueError:
return pressureValue,volumeValue,moles,temperatureValue
def pvnrt(pressure=101.325,volume=22.4,moles=1.,
temperature=273.15):
"""Calculate for 'x' using the Ideal Gas Equation.
If no 'x' is specified , try and determine if entered numbers satisfy
the equation.
Warning: No error checking is done in this function. Must be passed
good values (and floats)."""
if pressure=='x': #P=nRT/V
return (moles*R*temperature/volume)
elif volume=='x': #V=nRT/P
return (moles*R*temperature/pressure)
elif moles=='x': #n=PV/RT
return pressure*volume/(R*temperature)
elif temperature=='x': #T=PV/nR
return pressure*volume/(R*moles)
elif (pressure*volume>.99*moles*R*temperature) and\
(pressure*volume<1.01*moles*R*temperature):
return True
else:
return False
def main():
inputList=getInput()
Pressure,Volume,Moles,Temperature=parseInput(*inputList)
Solution=pvnrt(Pressure,Volume,Moles,Temperature)
print "\n\n"+str(Solution)
if __name__=="__main__":
main()
_______________________________________________
Tutor maillist - Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor