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

Reply via email to