Bratwurst.py - помощник программа для кассира


Я студент в Германии, точнее в Баварии, и здесь мы используем, чтобы иметь так называемый "Kärwa", мероприятие для празднования создании поместной церкви. Он является общим, чтобы продать "Bratwürste" или колбаски на эти события. Поскольку я студент и мне нужны деньги, я часто помогаю с продажей.

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

На комментарий: Я пришел из Java/C#и C++ фон и я знаю, что я не могу относиться к питон тем же способом, но с ограниченным знанием языка Python у меня были, я старался изо всех сил. Если есть маленькие особенности в языке, который я могу использовать или есть лучшие практики, скажите мне об этом. Я в основном хотел услышать о ясности, документации, и реализация моего кода, особенно для calc_money_sizes функция.

Код может быть немного "переусложненный" это связано с некоторыми длительные периоды, когда мне было нечего делать и стало скучно. Но все равно не сдержать на критику я могу принять его :)

__author__ = "Patrick Hollweck" 

import collections

class Money:
  """ A class handling Interaction with money """

  SIZES = [0.01, 0.020, 0.050, 0.10, 0.20, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0, 200.0, 500.0]

  def calc_money_sizes(money):
    result = collections.OrderedDict()
    if money < 0:
      return result
    for size in reversed(Money.SIZES):
      while True:
        outcome = money - size
        if outcome > -0.001:
          if size in result:
            result[size] += 1
          else:
            result[size] = 1
          money = outcome
        else:
          break
    return result

class PriceCalculator:
  """ Class to calculate all sort of bratwurst Stuff! """

  SAUSAGE_PRICE = 1.10
  BREAD_PRICE = 0.30

  def calc_price(sausage_count, bread_count):
    sausage_price = sausage_count * PriceCalculator.SAUSAGE_PRICE
    bread_price = bread_count * PriceCalculator.BREAD_PRICE
    return sausage_price + bread_price

  def calc_return_money(price, given):
    return given - price


class Console:
  """ Console helpers """

  class input:
    """ Input helpers """

    def safe_int(message, allowNoInput = False):
      return Console.input.__safe_base(message, allowNoInput, int)

    def safe_float(message, allowNoInput = False):
      return Console.input.__safe_base(message, allowNoInput, float) 

    def __safe_base(message, allowNoInput, typefunc):
      while True:
        try:
          result = input(message)
          if result == "" and allowNoInput:
            return None
          elif result == "clear":
            Console.Out.clear()
            continue
          else:
            return typefunc(result)
        except Exception:
          print("Invalid input! (" + str(typefunc) + ") expected")
          continue

  class format:
    """ Formating functions for the console """

    def float(number):
      return "{0:.2f}".format(number)

    def str_normalize_lenght(string, longest):
      if len(string) < longest:
        missing_chars = longest - len(string)
        return string + " " * abs(missing_chars)
      else:
        return string

  class pretty_print:
    """ Use this class for pretty printing commons types """ 

    def float(number):
      print(Console.format.float(number))

    def dict(dictionary):
      if len(dictionary) is 0:
        print("NOT POSSIBLE")
        return

      for key in dictionary.keys():
        print(str(Console.format.str_normalize_lenght(Console.format.float(key), 6)) + " -> " + str(dictionary[key]))


  class output:
    """ Output helpers """

    def header(text):
      print("\n--- " + text + " ---\n")

    def clear():
      print("\n" * 50)


if __name__ == "__main__":

  Console.output.clear()

  while True:

    # print header
    print("Bratwurst price Calculator!\n")

    # Get input
    sausage_count = Console.input.safe_int("Sausages Count: ")
    bread_count = Console.input.safe_int("Bread Count: ")

    # Calculate total price and output
    price = PriceCalculator.calc_price(sausage_count, bread_count) 

    Console.output.header("TOTAL PRICE")
    Console.pretty_print.float(price)

    # Calculate return money 
    given = Console.input.safe_float("\nGiven money: ", allowNoInput = True)

    # Optional skip return money calculation when reqested
    if given == None:
      Console.output.clear()
      continue

    return_money = PriceCalculator.calc_return_money(price, given)

    Console.output.header("RETURN MONEY")

    # Return money amount
    if return_money < 0:
      print("WARNING: Not enought money!")

    Console.pretty_print.float(return_money)

    # Return money format
    Console.output.header("RETURN MONEY FORMAT")
    Console.pretty_print.dict(Money.calc_money_sizes(return_money))

    # Cleanup
    input("\n... Continue ...")
    Console.output.clear();


Комментарии
1 ответ

Вы хотели что-то быстро?

Это не очень быстро:

# Get input
sausage_count = Console.input.safe_int("Sausages Count: ")
bread_count = Console.input.safe_int("Bread Count: ")

Что если человек только купил хлеба? Теперь вы вынуждены ввести 0 для Sausages Countи только тогда вы сможете войти в хлеб граф.

Звучит не очень быстро для меня.

Я бы посоветовал вам прибегнуть к своего рода анализатор-ридер, способ. Например, вы можете сказать, что S для Sausage и B для хлеба - все регистронезависимы конечно. Затем вы можете просто ввести:

10S4b

Или

4b10s

Для этого надо перевести 10 sausages и 4 bread.

Вы можете также ввести 10s или 4b.

Этот синтаксис, вы больше не вынуждены ввести обоим пунктам, если человек не покупал оба. Он тоже меньше набирать, потому что вы только должны нажать ввести один раз.

Чтобы сделать эту работу, вы можете использовать регулярные выражения библиотеки, и регулярное выражение вроде этого:

import re

regex = re.compile(r'(\d+[sS])|(\d+[bB])')

def get_input():
s = input()
sausage, bread = [], []
for match in regex.finditer(s):
if match.group(1) is not None:
sausages.append(match.group(1)[:-1])
if match.group(2) is not None:
bread.append(match.group(2)[:-1])

return sum(map(int, sausage)), sum(map(int, bread))

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

Проверить это, попробуйте его, улучшить его, если необходимо.

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


@staticmethod

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

Вы можете сделать это путем аннотирования методов с @staticmethod декоратор


Что-то не может быть равно нечего, потому что это сделает ничего, что-то.

Если вы не разобрать, что правильно, я имею в виду это:

if given == None:
...

Это, как правило, с неодобрением, чтобы проверить, если переменная имеет значение, сравнивая его с None. Некоторые даже считают, что это анти-паттерн.

Рекомендуемый способ сделать это с помощью is оператора, так:

if given is None:
...

Это все семантика, а если вы не понимаете, не беспокойтесь, это не конец света, я просто еще раз напомню в следующий раз я вижу это :).


Примитивы

Этот метод у вас здесь:

def str_normalize_lenght(string, longest):
if len(string) < longest:
missing_chars = longest - len(string)
return string + " " * abs(missing_chars)
else:
return string

...уже встроена в класс String. Это называется rjust. Так что заменить все использования вашего переусложненный функции str.rjust(longest)или изменить функцию, чтобы использовать rjust.


Быстрее, быстрее везде...

Этот код для расчета изменения не так быстро, как это можно сделать

def calc_money_sizes(money):
result = collections.OrderedDict()
if money < 0:
return result
for size in reversed(Money.SIZES):
while True:
outcome = money - size
if outcome > -0.001:
if size in result:
result[size] += 1
else:
result[size] = 1
money = outcome
else:
break
return result

Вы даже не заметите разницу, но вы говорили, что хотели, чтобы этот код, чтобы быть быстрым, так вот мой улучшений для достижения, что быстрый и четкий:

def calc_money_sizes(money):
result = collections.OrderedDict()
for size in reversed(Money.SIZES):
outcome = money / size
if int(outcome) > 0:
result[size] = int(outcome)
money %= size
return result


Общие замечания:


  • Избежать именования переменных и функций с таким же именем, как некоторые методы builtin или модули. Например, float, string, input.

  • Использование классов-это интересно. Вы сможете использовать их как можно было бы использовать пространства имен в C++ или C#, но я не думаю, что большинство пользователей Python будет с этим согласиться. Я не возражаю против этого, но я думаю, что вы можете захотеть взглянуть на modules и посмотреть, если это та структура, которую вы собирались.

7
ответ дан 7 февраля 2018 в 03:02 Источник Поделиться