-1
class TrialDetails:
    trial_number: int
    def __init__(self, trial_number=-1):
        self.trial_number = trial_number
    def set_trial_number(self, trial_number):
        self.trial_number = trial_number
class HpoExperiment:
    experiment_name: str
    total_trials: int
    trialDetails: object
    def __init__(self, experiment_name, total_trials, trialDetails = TrialDetails()):
        self.experiment_name = experiment_name
        self.total_trials = total_trials
        self.trialDetails = trialDetails
    def set_trial(self, trial_number):
        self.trialDetails.set_trial_number(trial_number)
    def display(self):
        print ("exp name = ", self.experiment_name)
        print ("total trials = ", self.total_trials)
        print ("trial number = ", self.trialDetails.trial_number)

def main():
    exp1 = HpoExperiment("A", 5)
    exp2 = HpoExperiment("B", 3)
    print("Experiment Details")
    exp1.display()
    exp2.display()
    print("Update Experiment 1")
    exp1.set_trial(22)
    print("Experiment Details")
    exp1.display()
    exp2.display()

if __name__ == '__main__':
    main()

While running the above code, why does the value of exp2 object also gets modified? I want to keep it separate for each object. Unable to understand how to do that.

Saad Khan
  • 41
  • 8
  • Because it is a **class** variable and not an **instance** variable. Leave them out of the class body. – Klaus D. Sep 20 '22 at 07:21
  • There are no *class variables* here, only class-level type hints, which is okay (though somewhat redundant). It's *mutable default arguments* again… – deceze Sep 20 '22 at 07:27
  • Although the comments are correct: you were defining class attributes (if you'd assign them values - which you didn't, currently they were just type hints), the real issue is what's described in the linked question - you were providing a mutable default value with `trialDetails = TrialDetails()` in the constructor definition. – Grismar Sep 20 '22 at 07:27

1 Answers1

0

It's because of the way you initialize trialDetails in your constructor:

def __init__(self, experiment_name, total_trials, trialDetails = TrialDetails()):

You may think that on each call the trialDetails gets initialized to new instance of your TrialDetails class, but it is not the case, as default argument is bond to function definition. Because of this you get the same instance for your both HpoExperiment objects, which you can easily verify by adding plain print(trialDetails) to __init__(). The solution would be to move initialization of the trialDetails to constructor body, i.e.:

def __init__(self, experiment_name, total_trials, trialDetails = None):
    if not trialDetails:
       trialDetails = TrialDetails()
    ...

After that change you got two instances and expected outcome:

Experiment Details
exp name =  A
total trials =  5
trial number =  -1
exp name =  B
total trials =  3
trial number =  -1

Update Experiment 1
Experiment Details
exp name =  A
total trials =  5
trial number =  22
exp name =  B
total trials =  3
trial number =  -1
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141