pythonvariablesmethodsprivate

Why is my dunder variable defined at module scope not recognized from a function scope as int but recognized as list[int]?


I tried to make a variable as "private" in the module using __dunder_case__ and use it in the function below.

I finally changed the variable name to uppercase naming and forget about anything private when using python. I'm running python 3.12.2 on windows 11. But I cannot wrap my mind around why is it treated this way...

__use_this__ = 0


def test_out_scope():
    __use_this__ += 1
    return __use_this__


if __name__ == "__main__":
    print(__use_this__)
    print(test_out_scope())
    print(test_out_scope())
    print(test_out_scope())
    print(test_out_scope())

and expecting to add the variable but got this instead:

UnboundLocalError: cannot access local variable '__use_this__' where it is not associated with a value.

Edited

__use_this__ = [0]



def test_out_scope():
    __use_this__[0] += 1
    return __use_this__[0]


if __name__ == "__main__":
    print(__use_this__[0])
    print(test_out_scope())
    print(test_out_scope())
    print(test_out_scope())
    print(test_out_scope())

expecting to fail


Solution

  • This has nothing to do with variable naming. Double underscore only makes variable names behave differently in class definitions - it is treated like any other variable otherwise.

    The reason you're seeing an error when __use_this__ == 0 is simply because of incorrect reference to nonlocal variable. Because integers are immutable - += doesn't work in place with immutable variables. It creates a new object (well, not really but for simplicity let's say it does) and assigns it to the variable name. Since you are reassigning name inside a function, it is treated as local and throws UnboundLocalError: cannot access local variable '__use_this__' where it is not associated with a value.

    When you are modifying a list, it still points to the same list object. Since you don't assign it anywhere in the function, it looks for the reference in outer scope.

    Simply marking a variable as global will solve the issue.

    def test_out_scope():
        global __use_this__
        __use_this__ += 1
        return __use_this__