Python, запустить функцию на основе форматирования и содержимого входной строки - PullRequest
2 голосов
/ 15 декабря 2010

Я подумал, что попробую написать что-то вроде преобразования единиц измерения просто для практики.Я хотел бы, чтобы он работал таким образом, чтобы пользователю было дано одно приглашение ввода, и он запускал бы соответствующую функцию, основанную на строке.

Мне просто интересно, что было бы лучшим способом сказатьЕсли строка отформатирована следующим образом:

единица измерения числа

пример: 30 см дюйм (при этом будет запускаться функция с именем cmtoinch , передавая число 30 в качестве аргумента).

Мне также нужно было бы иметь возможность определить, какая единица находится перед другой причиной, поскольку "30 см дюйма" дал бы другие результаты, чем "30 дюймовcm ".

Я думал, что я бы поместил имена каждого устройства в список, но я не знаю, как сравнить строку со списком, чтобы увидеть, содержит ли она хотя бы два значения.

Ответы [ 5 ]

4 голосов
/ 15 декабря 2010

Используйте .split() в строке, чтобы разбить ее на слова (тогда вы можете интерпретировать первый как int или float в зависимости от ситуации).Полученный список будет в том же порядке, что и входная строка, так что вы можете посмотреть на каждый элемент по очереди и сравнить его со своим списком ссылок.

Создание отдельной функции для каждого преобразования, вероятно, не то, чтоты хочешь сделать.Вместо этого переведите вход в какой-либо общий блок, а затем переведите из общего блока в требуемый выходной блок.Для этого мы связываем каждую единицу с единым коэффициентом пересчета;мы умножаем первый раз и делим второй раз.

Чтобы сделать связь между именами единиц измерения и значениями преобразования, мы используем dict.Это позволяет нам искать значение конверсии напрямую, подключив имя.

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]
3 голосов
/ 15 декабря 2010

В зависимости от организации этого кода вы можете использовать здесь globals(), <modulename>.__dict__ или getattr(obj). Мой пример использует 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()
2 голосов
/ 15 декабря 2010

Вы можете использовать словарь (отображение) и использовать тот факт, что вы используете кортежи в качестве ключей.

#!/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))

Не говорите, что это лучший способ преобразования единиц, а просто демонстрацию функций диспетчеризации.

Мне нравится это лучше, чем выбирать из глобальных (), потому что это более явно и безопасно.

0 голосов
/ 15 декабря 2010

Как это?

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
0 голосов
/ 15 декабря 2010
{
    'cm': {
        'inch': cmtoinch,
        'microparsec': cmtomicroparsec
    }
}
...