Python中級 - Python中級のチャレンジ - そこそこ複雑な注文集計処理を作る演習問題 - 2問目

main.py の2問目終了時の解答コードです。

  1from datetime import date
  2import os
  3
  4ITEM_TSV_PATH = 'items.tsv'
  5ORDER_DIR = 'order/'
  6FAILURE_DIR = 'failure/'
  7DELIVERY_DIR = 'delivery/'
  8
  9
 10class Item:
 11    """ 1商品に対応するクラス
 12    """
 13    def __init__(self, item_id, name, price):
 14    self.item_id = item_id
 15    self.name = name
 16    self.price = price
 17
 18
 19class Items:
 20    def __init__(self, items):
 21    self.items = items
 22
 23    def has_id(self, item_id):
 24    """ item_id をもつ商品が存在するかチェックする
 25    """
 26    for item in self.items:
 27        if item.item_id == item_id:
 28        return True
 29    return False
 30
 31
 32class Order:
 33    def __init__(self, item_id, amount, shipping_address, tel_number,
 34         fullname, shipping_date_str, order_file):
 35    self.item_id = item_id
 36    self.amount = amount
 37    self.shipping_address = shipping_address
 38    self.tel_number = tel_number
 39    self.fullname = fullname
 40    self.shipping_date_str = shipping_date_str
 41    self.order_file = order_file
 42
 43    self.amount_int = None
 44    self.shipping_date = None
 45
 46    def validate(self, items):
 47    """ 各注文の値が正しいかバリデーションチェックする。OKの場合True、NGの場合False
 48    """
 49
 50    def row_string(self):
 51    return ','.join((
 52        self.item_id,
 53        self.amount,
 54        self.shipping_address,
 55        self.tel_number,
 56        self.fullname,
 57        self.shipping_date_str,
 58        self.order_file,
 59    ))
 60
 61
 62def load_items():
 63    """ ITEM_TSV_PATHのTSVからItemsを作る
 64    """
 65    items = []
 66    with open(ITEM_TSV_PATH, encoding='utf-8') as f:
 67    for row in f:
 68        item_id, name, price = row.split('\t')
 69        item = Item(item_id.strip(), name.strip(), price.strip())
 70        items.append(item)
 71    return Items(items)
 72
 73
 74def load_orders(target_date):
 75    """ ORDER_DIR のCSVからOrderのリストを作る
 76
 77    * 各値の前後から空白を除外する
 78    """
 79    date_str = target_date.strftime('%Y%m%d')
 80    orders = []
 81    for filename in os.listdir(ORDER_DIR):
 82    if date_str not in filename:
 83        # 対象日でないファイルは無視する
 84        continue
 85
 86    filepath = os.path.join(ORDER_DIR, filename)
 87    with open(filepath, encoding='utf-8') as f:
 88        for row in f:
 89        item_id, amount, address, tel, name, shipping_date = row.split(',')
 90        order = Order(
 91            item_id.strip(),
 92            amount.strip(),
 93            address.strip(),
 94            tel.strip(),
 95            name.strip(),
 96            shipping_date.strip(),
 97            filename,
 98        )
 99        orders.append(order)
100    return orders
101
102
103def write_deliver_orders(orders):
104    """ Orderのリストを受け取って日別注文ファイルに書き込み
105    """
106    # 宅配日毎に集計。ファイルをオープンする回数を減らすため事前にまとめる
107    date_orders = {}
108    for order in orders:
109    if order.shipping_date in date_orders:
110        date_orders[order.shipping_date].append(order)
111    else:
112        date_orders[order.shipping_date] = [order]
113
114    for d, day_orders in date_orders.items():
115    filename = 'delivery_{}.csv'.format(d.strftime('%Y%m%d'))
116    filepath = os.path.join(DELIVERY_DIR, filename)
117    with open(filepath, 'a', encoding='utf-8') as f:
118        for order in day_orders:
119        f.write(order.row_string() + '\n')
120
121
122def write_failure_orders(orders, order_date):
123    """ Orderのリストを受け取って注文受付失敗ファイルに書き込み
124    """
125
126
127def main(target_date=None):
128    """ 毎日の注文集計用スクリプト
129
130    1. 商品マスター読み込み
131    2. 当日分の注文受付ファイル読み込み
132    3. 注文をバリデーションチェック
133    4. 日別注文ファイル書き込み
134    5. 注文受付失敗ファイル書き込み
135    """
136    target_date = target_date or date.today()
137
138    items = load_items()
139    orders = load_orders(target_date)
140    validated_orders = []
141    failed_orders = []
142    for order in orders:
143    if order.validate(items):
144        validated_orders.append(order)
145    else:
146        failed_orders.append(order)
147
148    if validated_orders:
149    write_deliver_orders(validated_orders)
150    if failed_orders:
151    write_failure_orders(failed_orders, target_date)
152
153
154if __name__ == '__main__':
155    main(date(2016, 12, 14))  # あくまで動作確認用に日付を指定している
当コンテンツの知的財産権は株式会社ビープラウドに所属します。詳しくは利用規約をご確認ください。