Ghopper21
Ghopper21

Reputation: 10477

Why can't Python find the built-in print function when calling from an imported function?

Take this main.py:

from __future__ import print_function

from sub import print

print("hello, world")

and this sub.py:

from __future__ import print_function

def print(*args, **kwargs):
    return __builtins__.print(*args, **kwargs)

Using Python 2.7.9, run main.py and you get:

Traceback (most recent call last):
File "main.py", line 5, in <module>
    print("hello, world")
File "/Users/ien/Studio/songifier/sub.py", line 4, in print
    return __builtins__.print(*args, **kwargs)
AttributeError: 'dict' object has no attribute 'print'

Why and how to make this work?

NOTE: This is an artificial example to isolate the problem, which has arisen in a logging context, where the print function sometimes does some fancy logging, and other times wants to just call the built-in print function.

Upvotes: 2

Views: 274

Answers (2)

smac89
smac89

Reputation: 43196

Try this:

import __builtin__
from __future__ import print_function

def print(*args, **kwargs):
    return __builtin__.print(*args, **kwargs)

>>> print
<function print at 0x7f80cd622668>
>>> print("Hello", "world", sep="\n")
Hello
world

The reason for the error you were seeing can be explained better by this excerpt from the python docs:

By default, when in the __main__ module, __builtins__ is the built-in module __builtin__ (note: no 's'); when in any other module, __builtins__ is an alias for the dictionary of the __builtin__ module itself.

__builtins__ can be set to a user-created dictionary to create a weak form of restricted execution.

CPython implementation detail: Users should not touch __builtins__; it is strictly an implementation detail. Users wanting to override values in the builtins namespace should import the __builtin__ (no 's') module and modify its attributes appropriately. The namespace for a module is automatically created the first time a module is imported.

Upvotes: 3

Athena
Athena

Reputation: 3228

To quote an answer on this question: overload print python

In Python 2.x you can't, because print isn't a function, it's a statement. In Python 3 print is a function, so I suppose it could be overridden (haven't tried it, though).

Upvotes: -1

Related Questions