1

I'm trying to write a replacement for the print() function; I'd like to understand what Python 3 is doing here.

Consider the following two Python 3 source files:

file.py:

def in_a_file():
    print("this is in a file")

minimal.py:

import builtins
from file import *

def test():
    print("this is a test")

def printA(*args, **kwargs):
    builtins.print("A: ", end="")
    builtins.print(*args, **kwargs)

print = printA

test()
in_a_file()

When I run minimal.py, I get this output:

A: this is a test
this is in a file

So, clearly, the assignment print=printA has changed the behavior of print() in function test(), but not in function file().

Why?

And, is there code I could put in minimal.py that would similarly change the behavior of print() in function file()?

nerdfever.com
  • 1,652
  • 1
  • 20
  • 41
  • 6
    A module has its own namespace, it doesn't use the variables defined in the file that imports it. – Barmar Jan 20 '21 at 19:50
  • @Barmar I suppose you're correct, but can you please elaborate? I don't understand how "it doesn't use the variables defined in the file that imports it" explains what I'm seeing. Or how to get the behavior I want - which is to change the way print() in the module works. – nerdfever.com Jan 20 '21 at 19:51
  • Does this answer your question? [Python3 global scoping in different modules](https://stackoverflow.com/questions/60352980/python3-global-scoping-in-different-modules/60353153#60353153) – MisterMiyagi Jan 20 '21 at 19:53
  • Does this answer your question? [Short description of the scoping rules?](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) – MisterMiyagi Jan 20 '21 at 19:54
  • 2
    Every module has its own namespace where it looks up variable names. So the variable `print` in your file is not the same as the one in `file.py`. This is done so that module authors don't have to worry that their variables might conflict with variables in the caller. – Barmar Jan 20 '21 at 19:54
  • As for your second question: Do you want to change ``print`` only in ``file`` or in all modules? – MisterMiyagi Jan 20 '21 at 19:54
  • @MisterMiyagi: I'd like to change 'print' in all modules. If I need to specify which modules specifically to make this work, I can do that. – nerdfever.com Jan 20 '21 at 19:56
  • When `test` is called, it uses whatever the name `print` is bound to at that time, not what `print` was bound to when `test` was defined. – chepner Jan 20 '21 at 20:05

1 Answers1

1

The name lookup is roughly builtins shared by all modules, each module's own global namespace, and then subsequently nested function/class namespaces. The print function lives in builtins, and is thus visible in all modules by default.

The assignment print = printA in minimal.py adds a new name print to minimal's global namespace. This means minimal.print shadows builtins.print inside the minimal module. The change is not visible in any other module, since each has a separate module-global namespace.

To change print across all modules, re-assign builtins.print.

import builtins

_real_print = builtins.print

def printA(*args, **kwargs):
    _real_print("A: ", end="")
    _real_print(*args, **kwargs)

builtins.print = printA
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119