为何修改HpoExperiment实例exp1时exp2也被改动?如何隔离?
Python类实例状态共享问题的原因与解决方法
问题描述
运行以下Python代码时,修改HpoExperiment类的实例exp1的trial_number后,实例exp2的该属性值也随之改变。需要让每个实例的状态相互独立,请问问题原因是什么?如何实现状态隔离?
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()
问题原因
这是Python中可变默认参数的常见陷阱:
- 函数的默认参数是在函数定义阶段创建的,而非每次调用函数时重新生成
HpoExperiment.__init__方法里的trialDetails = TrialDetails(),会在类定义时生成一个TrialDetails实例,所有没有显式传入trialDetails参数的HpoExperiment实例,都会共享这同一个TrialDetails对象- 修改
exp1的trial_number时,实际是修改了这个共享对象的属性,exp2引用的是同一个对象,自然属性值也会跟着变化
实现实例状态隔离的方法
方法1:修改默认参数为None,在初始化时创建新实例
把__init__的默认参数改为None,然后在方法内部判断,若没有传入自定义的trialDetails,就新建一个独立的TrialDetails实例:
class HpoExperiment: experiment_name: str total_trials: int trialDetails: object def __init__(self, experiment_name, total_trials, trialDetails=None): self.experiment_name = experiment_name self.total_trials = total_trials # 为每个实例创建独立的TrialDetails对象 self.trialDetails = trialDetails if trialDetails is not None else 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)
方法2:显式传入独立的TrialDetails实例
在创建HpoExperiment实例时,手动为每个实例传入新的TrialDetails对象,确保每个实例拥有专属的状态:
def main(): # 每个实例都传入独立的TrialDetails对象 exp1 = HpoExperiment("A", 5, TrialDetails()) exp2 = HpoExperiment("B", 3, TrialDetails()) print("Experiment Details") exp1.display() exp2.display() print("Update Experiment 1") exp1.set_trial(22) print("Experiment Details") exp1.display() exp2.display()
内容的提问来源于stack exchange,提问作者Saad Khan
相关产品推荐
相关产品推荐

