I thought I'd try writing a kind of a measurements units conversion thingy just for practice. I would like it to work in a way that the user would be given a single input prompt and i开发者_如何学JAVAt would run the appropriate function based on the string.
I'm just wondering what would be the best way to tell weather the string is formatted like this:
number unit unit
example: 30 cm inch (this would run the function named cmtoinch passing the number 30 as an arguement).
I would also need to be able to tell which unit is in front of the other cause "30 cm inch" would give different results then "30 inch cm".
I was thinking I'd put the names of each unit into a list, but I don't know how to compare a string to the list to see if it contains at least two of the values.
Use .split()
on the string to break it into words (then you can re-interpret the first one as an int
or float
as appropriate). The resulting list will be in the same order as the input string, so you can look at each element in turn and check it against your reference list of units.
Making a separate function for each conversion is probably not what you want to do. Instead, translate the input into some common unit, and then translate from the common unit to the desired output unit. To do this, we associate each unit with a single conversion factor; we multiply the first time, and divide the second time.
To make the association between unit names and conversion values, we use a dict
. This lets us look up the conversion value directly by plugging in the name.
conversion_rates = {
'in': 2.54, # 2.54 inches in a centimetre
'cm': 1.00, # this is our reference unit
'sun': 3.03 # a traditional Japanese unit of measurement
}
# raises ValueError if the number of words in the input is wrong
amount, original_unit, final_unit = line.split()
# raises ValueError if the amount is not formatted as a floating-point number
amount = float(amount)
# Now we do the conversion.
# raises KeyError if either unit is not found in the dict.
result = amount * conversion_rates[original_unit] / conversion_rates[final_unit]
Depending on the organization of this code, you may want to use globals()
, <modulename>.__dict__
, or getattr(obj)
here. My example uses globals()
.
def cmtoinch(x):
return x / 2.54
def inchtocm(x):
return x * 2.54
def convert(input):
num, unit1, unit2 = input.split()
func = unit1 + "to" + unit2
if func in globals():
return globals()[func](float(num))
else:
raise NotImplementedException()
You can use a dictionary (mapping), and take advantage of the fact that you use tuples as keys.
#!/usr/bin/python2
import sys
def inch2cm(inches):
return inches * 2.54
def cm2inch(cm):
return cm / 2.54
DISPATCH_TABLE = {
("in", "cm"): inch2cm,
("cm", "in"): cm2inch,
}
def converter(argv):
"""converter <value> <from unit> <to unit>
"""
try:
value = float(argv[1])
unit_from = argv[2]
unit_to = argv[3]
except (ValueError, IndexError), ex:
print ex
print converter__doc__
return 2
func = DISPATCH_TABLE[(unit_from.lower()[:2], unit_to.lower()[:2])]
print func(value)
return 0
sys.exit(converter(sys.argv))
Not saying this is the best way to do unit conversion, but just a demonstration of dispatching functions.
I like this better than picking from globals() because it's more explicit and safer.
{
'cm': {
'inch': cmtoinch,
'microparsec': cmtomicroparsec
}
}
How's this?
class Translator():
UNITS = [
# length
{
"cm": 1.0,
"inch": 2.54,
"foot": 30.48,
"rod": 502.92
},
# weight
{
"kg": 1.0,
"pound": 0.454,
"stone": 6.356
},
# liquid volume
{
"litre": 1.0,
"pint": 0.473,
"gallon": 3.785
}
]
def translate(self, val, unit1, unit2):
for u in Translator.UNITS:
if u.has_key(unit1) and u.has_key(unit2):
return float(val) * u[unit1] / u[unit2]
return "Can't convert from %s to %s" % (unit1, unit2)
def translateString(self, str):
args = str.split()
if len(args)==3:
return self.translate( float(args[0]), args[1], args[2] )
else:
return "Exactly three arguments required!"
def main():
t = Translator()
while True:
inp = raw_input("Translate what? (hit Enter to quit) ")
if len(inp) > 0:
t.translateString(inp)
else:
break
精彩评论