'Why I can modify a value of the nested variable in a dict but not for an object

This is just a finding I made yesterday and I am trying to understand the reason behind this behavior. I am using pytest fixtures for a test, and I have a control fixture that keeps information from the system and at the end, I want to restore those values.

For the case of the dictionary, I can just modify the items and after the yield clause, I have the dict object with all the information on it, however, if I initialize a class inside the function in the fixture, as I show below, the object is empty. I have to use the python keyword nonlocal for that.

Here is the code I made for the demo.

import pytest


class ExampleClass(BaseException):
    def __init__(self, i_a):
        self.a = i_a

    def stop(self):
        print("stop")

    def start(self):
        print("start")


@pytest.fixture()
def fixture_yield():
    print(__name__)
    server_object = None
    print("server_object", server_object)
    def _initialize_server(serial_number):
        nonlocal server_object
        server_object = ExampleClass(serial_number)
        server_object.start()
        print("server_object", server_object)

    yield _initialize_server
    print("server_object", server_object)
    if hasattr(server_object, 'stop'):
        server_object.stop()
    else:
        # corrective action
        pass

@pytest.fixture()
def fixture_yield_dict():
    my_dict = {}
    print("my_dict", my_dict)

    def _my_function(input_value):
        print("my_dict", my_dict)
        my_dict['key_1'] = 'hello'
        my_dict['key_2'] = 'bye'
        my_dict['input_value'] = input_value
        print("my_dict", my_dict)

    yield _my_function

    print("my_dict", my_dict)


def test_yielding_object(fixture_yield):
    fixture_yield('hello')


def test_yield_dict(fixture_yield_dict):
    fixture_yield_dict('this is a test')

What is the reason that I have to use nonlocal keyword to maintain the value of the object instantiated in the first fixture and not in the other one?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source