Python: Copied object still changed with original

I have a problem with copying objects in python. The actual problem is that some variables of the original object are changed when changing variables of the copied object. But this applies only to some of the variables instead of all.

Briefly, before showing the code I want to explain a bit further. I have two parameter (pm) objects, which contain other objects. One parameter object is the original one, which is not adjusted at any time. The copy version of it is adjusted. If I want to get the default values/objects again, I delete the object from the parameter copy object and add the default object from the parameter original object. In this case, I want to remove the adjusted component and add the default component.

Here is the example (with prints to show problem):

    print('copy')
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    print('original')
    for component in self.pm_object_original.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    print('Adjust copied component')
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        component.add_input('a', 12)
        component.set_max_p(95)
        break

    print('copy')
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    print('original')
    for component in self.pm_object_original.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    # Now remove components from copy pm_object
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        self.pm_object_copy.remove_component_entirely(component.get_name())

    # Add copied component from original pm_object to copy pm_object
    for component in self.pm_object_original.get_specific_components(component_type='conversion'):
        copied_component = component.__copy__()
        self.pm_object_copy.add_component(component.get_name(), copied_component)

    print('After Copy')
    print('copy')
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    print('original')
    for component in self.pm_object_original.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    print('Adjust copied component')
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        component.add_input('a', 12)
        component.set_max_p(95)
        break

    print('copy')
    for component in self.pm_object_copy.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

    print('original')
    for component in self.pm_object_original.get_specific_components(component_type='conversion'):
        print(component.get_inputs())
        print(component.get_max_p())
        break

The problem now is that after copying from pm_object_original, the original component (in pm_object_orginial) changes if I change the copied component. Attached is the results of the prints.

copy
{}
1.0

original
{}
1.0

Adjust copied component

copy
{'a': 12}
95.0

original
{}
1.0

After Copy
copy
{}
1.0

original
{}
1.0

Adjust copied component

copy
{'a': 12}
95.0

original
{'a': 12}
1.0

I am really confused why this only affects the inputs but not other variables like max_p. My copy code looks like following:

    def __copy__(self, name=None, nice_name=None):

    if name is None:
        name = self.name
    if nice_name is None:
        nice_name = self.nice_name

    return ConversionComponent(name=name, nice_name=nice_name, lifetime=self.lifetime,
                               maintenance=self.maintenance, capex=self.capex, capex_unit=self.capex_unit,
                               scalable=self.scalable, base_investment=self.base_investment,
                               base_capacity=self.base_capacity, economies_of_scale=self.economies_of_scale,
                               max_capacity_economies_of_scale=self.max_capacity_economies_of_scale,
                               ramp_down=self.ramp_down, ramp_up=self.ramp_up,
                               shut_down_ability=self.shut_down_ability, shut_down_time=self.shut_down_time,
                               start_up_time=self.start_up_time, number_parallel_units=self.number_parallel_units,
                               min_p=self.min_p, max_p=self.max_p, inputs=self.inputs, outputs=self.outputs,
                               main_input=self.main_input, main_output=self.main_output, streams=self.streams,
                               final_unit=self.final_unit)

Answer

Lists get passed by reference, not by value.

You can import and use deepcopy(), or you can use list comprehension to create a copy.

list_copy = [elem for elem in original_list]