3
\$\begingroup\$

In the bit of code below:

  1. How can I make add_day, add_ week and add_month work as a single function? They are almost copy-paste of one another. I'm trying to follow the DRY rule.
  2. How can I set this so that I don't use the variables day/week/cur_day?

import datetime
from collections import defaultdict

class ParsedData:
    def __init__(self, date, score, status, item_name):
        year, month, self.day = date.split("-")
        self.month = datetime.date(int(year), int(month), int(self.day)).strftime("%B")
        self.score = int(score)
        self.status = status
        self.item_name = item_name


class Log:
    def __init__(self):
        self.day = {}
        self.week = {}
        self.month = {}
        self.counter = {}

        self.default_data 

    def add_day(self, day, status, item_name, score):
        day = 'Day %i' % day
        if day not in self.day:
            self.day[day] = {"Comp": defaultdict(int),
                         "Miss": defaultdict(int),
                         "Post": defaultdict(int),
                         "Add": defaultdict(int),
                         "Score": 0}

        self.day[day][status][item_name] += 1
        self.day[day]['Score'] = score

    def add_week(self, week, status, item_name, score):
        week = 'Week %i' % week
        if week not in self.week:
            self.week[week] = {"Comp": defaultdict(int),
                         "Miss": defaultdict(int),
                         "Post": defaultdict(int),
                         "Add": defaultdict(int),
                         "Score": 0}

        self.week[week][status][item_name] += 1
        self.week[week]['Score'] = score

    def add_month(self, month, status, item_name, score):
        if month not in self.month:
            self.month[month] = {"Comp": defaultdict(int),
                         "Miss": defaultdict(int),
                         "Post": defaultdict(int),
                         "Add": defaultdict(int),
                         "Score": 0}

        self.month[month][status][item_name] += 1
        self.month[month]['Score'] = score


def update_views(log_file):
    log = Log()
    day = 0
    cur_day = None
    week = 1

    for line in log_file:
        parsed = ParsedData(*line.strip().split(","))

        if cur_day != parsed.day:
            cur_day = parsed.day
            day += 1
            if day % 7 == 0:
                week += 1

        log.add_day(day, parsed.status, parsed.item_name, parsed.score)
        log.add_week(week, parsed.status, parsed.item_name, parsed.score)
        log.add_month(parsed.month, parsed.status, parsed.item_name, parsed.score)


log_file =   """2015-01-1,0,Add,DW_05
                2015-01-2,-1,Post,CR_02
                2015-01-3,-1,Comp,DIY_01
                2015-01-3,-1,Post,CD_01
                2015-01-4,-1,Miss,D_03
                2015-01-4,0,Miss,D_03
                2015-01-4,-1,Miss,CD_01
                2015-01-4,0,Miss,LS_04
                2015-01-5,1,Comp,DW_05
                2015-01-6,1,Comp,ANI_06
                2015-01-6,1,Comp,LS_04
                2015-01-7,1,Comp,NMW_07
                2015-01-7,1,Post,DW_05
                2015-01-7,1,Miss,LP_08
                2015-01-8,2,Post,CR_02
                2015-01-8,2,Miss,SEV_09
                2015-01-10,3,Comp,M_10
                2015-01-10,3,Add,NID_11
                2015-01-11,2,Add,ANI_06
                2015-01-12,1,Add,VF_12
                2015-01-12,0,Miss,DIY_01
                2015-01-12,1,Add,NID_11
                2015-01-12,0,Miss,D_03
                2015-01-13,1,Miss,SEV_09
                2015-01-13,2,Add,DW_05
                2015-01-13,1,Comp,NMW_07
                2015-01-13,1,Add,CPC_12""".splitlines()

update_views(log_file)
| improve this question | | | | |
\$\endgroup\$
  • \$\begingroup\$ Have you actually tested this? All days, weeks and months share the same data... so what's the point of separating it? \$\endgroup\$ – Veedrac Jan 17 '15 at 20:28
  • \$\begingroup\$ It's for display purpose, the log goes to a MVC with three different display modes, daily, weekly and monthly. Each day will have a entry in the Day View, but the will be joined together in the week (every 7 days), and this will also be joined together in the month display. \$\endgroup\$ – f.rodrigues Jan 17 '15 at 23:20
  • \$\begingroup\$ I'm not sure you get it; self.month['January'] is self.month['February'] is self.day['Day 2']... and so on. Why? \$\endgroup\$ – Veedrac Jan 17 '15 at 23:45
  • \$\begingroup\$ Oh I see, somehow after refactoring I forgot to use deepcopy to set the default_data. \$\endgroup\$ – f.rodrigues Jan 18 '15 at 2:28
4
\$\begingroup\$

To avoid repetitive code, make the Log class do only one of the three things it currently does, and create three instances instead:

class Log(object):
    def __init__(self, name):
        self.name = name
        self.data = {}

    def add_item(self, key, status, item_name, score):
        key = '%s %i' % (self.name, key)
        if key not in self.data:
            self.data[key] = {"Comp": defaultdict(int),
                         "Miss": defaultdict(int),
                         "Post": defaultdict(int),
                         "Add": defaultdict(int),
                         "Score": 0}

        self.data[key][status][item_name] += 1
        self.data[key]['Score'] = score

def update_views(log_file):
    daily_log = Log('Day')
    weekly_log = Log('Week')
    monthly_log = Log('Month')
    ...
| improve this answer | | | | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.