2

I have a class object which I am defining as an instance variable of another class object. I want to be able to change the variable object dynamically (as described below). I understand why it's not working (At least, I think I do.. python uses dictionary style modification of objects so this like a change in place?), but just trying to figure out a work around..

I thought if I created the object inside the loop it would take care of the problem, but I had no luck.. ideally, I would like to not have to create it in the loop because this is a really simplified version of my code and, in my actual code, the creation of the object takes 5 minutes (a lot of data/modifications are called to run when it is initialized).. so if I have to create it in the loop it would take 5 minutes per every iteration... which would be really not ideal.

Here's my full code:

class Employee:
    def __init__(self, name, unscheduled, shifts, hours_scheduled, appointments_with):
        self.name = name
        self.unscheduled = unscheduled
        self.shifts = shifts
        self.hours_scheduled = hours_scheduled
        self.appointments_with = appointments_with

    def drop_shift(self, person, hours):
        hours_with = self.shifts[person]
        new_hours = [x for x in hours_with if hours[0] not in x]
        self.shifts[person] = new_hours
        new_unscheduled = [x for x in hours_with if hours[0] in x]
        self.unscheduled = self.unscheduled + new_unscheduled[0]
        for person in list(self.shifts.keys()):
            if len(self.shifts[person]) == 0:
                del self.shifts[person]
                del self.appointments_with[self.appointments_with.index(person)]
        return self

    def add_shift(self, person, hours):
        self.unscheduled = [x for x in self.unscheduled if x not in hours]
        if person in list(self.shifts.keys()):
            self.shifts[person] = self.shifts[person] + hours
        else:
            self.shifts[person] = hours
            self.appointments_with = self.appointments_with + [person]
        self.hours_scheduled = self.hours_scheduled + hours
        return self


class Schedule:
    def __init__(self, all_employees):
        self.employees = {}
        for name in list(all_employees.keys()):
            self.employees.update({name: Employee(name, all_employees[name]['unsched'], all_employees[name]['shifts'],
                                                  all_employees[name]['hours_sched'], all_employees[name]['appts'])})

    def add_shift(self, employee, person, hours):
        employ_obj = self.employees[employee]
        self.employees[employee] = employ_obj.add_shift(person, hours)
        return self

    def drop_shift(self, employee, person, hours):
        employ_obj = self.employees[employee]
        self.employees[employee] = employ_obj.drop_shift(person, hours)
        return self


def get_changes():
    employees = {
        'Joe': {'unsched': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'shifts': {'Mark': [[11, 12, 13, 14], [21, 22, 23, 24, 25]], 'Jack': [[15, 16, 17, 18, 19, 20]]}, 'hours_sched': [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], 'appts': ['Mark', 'Jack']}}


    to_drop = [('Joe', 'Mark', [11, 12, 13, 14]), ('Joe', 'Jack', [15, 16, 17, 18, 19, 20])]
    new_schedules = []
    for drop in to_drop:
        Full_Sched = Schedule(employees)
        altered = Full_Sched.drop_shift(drop[0], drop[1], drop[2])
        new_schedules.append(altered)

    for new in new_schedules:
        print(new.employees['Joe'].unscheduled)
        print(new.employees['Joe'].shifts)
        print(new.employees['Joe'].hours_scheduled)
        print(new.employees['Joe'].appointments_with)

    return ()


if __name__ == '__main__':
    get_changes()

Output I am getting:

   > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
   > {'Mark': [[21, 22, 23, 24, 25]]}
   > [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
   > ['Mark']
   > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
   > {'Mark': [[21, 22, 23, 24, 25]]}
   > [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
   > ['Mark']

Output that I want:

> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
> {'Mark': [[21, 22, 23, 24, 25]], 'Jack': [[15, 16, 17, 18, 19, 20]]}
> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
> ['Mark', 'Jack']
> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 18, 19, 20]
> {'Mark': [[11, 12, 13, 14], [21, 22, 23, 24, 25]]}
> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
> ['Mark']

1 Answer 1

3

Your code is perfect except for one place

new_schedules.append(altered)

What is happening is that because altered itself is a reference, for all the repeats in

for new in new_schedules:
        print(new.employees['Joe'].unscheduled)
        print(new.employees['Joe'].shifts)
        print(new.employees['Joe'].hours_scheduled)
        print(new.employees['Joe'].appointments_with)

you are getting the last updated value.

For rectifying this, you can use the copy module

import copy
...
new_schedules.append(copy.deepcopy(altered))
Sign up to request clarification or add additional context in comments.

2 Comments

I have been staring at this for hours and you're my literal hero now, thank you!!
@ReblochonMasque I am a new user so I did vote on him, but my votes do not display publicly until I have certain score. There was no option for me to accept the answer at the time, but I have since accepted it- thanks for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.