Maybe this will help: https://stackabuse.com/python-nested-functions/
Notice you "sends arguments twice" (not really): first in square = raise_val(2) and second in square(2). What happens? The first calls return a function: you call to raise_val and it returns inner, which is a function. Now square variable actually holds a function. Second call, square(2), just call to the function.
It's the same as:
def a(x):
print(x)
square = a
print(square(5))
In this example, square holds a function. It's the same as in your code, since raise_val returns a function. Square holds inner method, and later it is been called. You send x directly: square(2) sends 2 for x of course.
A more interesting can be "how inner remembers n?", and as others mentioned in comments: it's manages variables of current scope.
raise_val, which is an outer scope ofinnerHere is more info: datacamp.com/community/tutorials/scope-of-variables-pythonxis just a name. Bottom line is you callsquarewith the argument2. In that casesquareis equivalent to the functioninnerwith the value ofnbeing2. So the argument2ofsquareis "passed on" toinner, which happens to be calledx...square(2)knows that the argument passed isx"? Argument binding works exactly the same for top-level and nested functions.squareis an alias for a specificdef inner(x):, which "knows" its argument isxjust likeraise_value"knows" its argument isn.raise_val(n)returns a function ofx,inner(x), which has been specified byn. When you callsquare(2)you're really calling a specific version ofinner(x), which is equivalent toraise_val(n)(x).