0

I'm a bit confused about a code in the book "Learning Python", p. 539.

As far as I know assignments within a function are only in this local scope. So if I want to change a global one I first have to declare it global. But why does the following code change the builtin.open() to custom completely once called?

import builtins
def makeopen(id):
    original = builtins.open
    def custom(*pargs, **kargs):
        print('Custom open call %r: ' % id, pargs, kargs)
        return original(*pargs, **kargs)
    builtins.open = custom

If I call makeopen('spam') and a F = open('text.txt') afterwards I get the custom call. So the builtin.open() has been changed in the whole script after the makeopen('spam'). Why? And if I would make some more makeopen('xx') one builtin.open('text.txt') would print the custom call for every created makeopen. Why?

Comparing this code to

x = 99
def changing():
    x = 88
changing()
print(x)

doesnt even help me. Isn't it the same but with an x instead of builtin.open()?

1 Answers1

0

A variable is considered local if you assign to it anywhere in the function, unless you declare it global.

In your first piece of code, you never assign anything to builtins, so it's not considered local. You just change one of its attributes, open.

The rule is respected!

In your second piece of code, you assign something to x in x = 88, so it is considered local.


When you call makeopen, you replace the original, global open with custom. custom, when executed, prints its name and calls the original open.

If you call makeopen a second time, it will create a second, different custom function, and make the name builtins.open refer to it. When you call this function, it will print its name, then call original, which is what builtins.open referred to when it was created - and that is your first custom function, which will print its name and call the original open.

So, successive calls to makeopen create a chain of functions, and calling open will make each of them run and call its predecessor.

Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
  • Thank you. And why is it calling `custom` for every instance of `makeopen`? If I would call three times `makeopen('text1')`... one `open('text.txt')` would show the custom for each text1... – SebbusGebbus Aug 08 '20 at 09:16