WoJ
WoJ

Reputation: 29987

why importing a module clashes with overridden print?

I want to automatically add a timestamp to my print statements (in Python 2.x) by overriding it. It works, except when I import a module which also contains the override.

My main file testa.py:

from __future__ import print_function
import datetime
import testb

def print(*args, **kwargs):
    __builtins__.print(datetime.datetime.now(), ' ', end='')
    return __builtins__.print(*args, **kwargs)

print("from main file")
testb.MyClass()

The helper file testb.py

from __future__ import print_function
import datetime

def print(*args, **kwargs):
    __builtins__.print(datetime.datetime.now(), ' ', end='')
    return __builtins__.print(*args, **kwargs)

class MyClass():
    def __init__(self):
        print("from helper file")

When running testa:

2014-07-29 09:43:54.375000  from main file
Traceback (most recent call last):
  File "C:/testa.py", line 10, in <module>
    testb.MyClass()
  File "C:\testb.py", line 15, in __init__
    print("from helper file")
  File "C:\testb.py", line 10, in print
    __builtins__.print(datetime.datetime.now(), ' ', end='')
AttributeError: 'dict' object has no attribute 'print'

I think that when importing testb, its print definition somehow clashes with the one in testa but this is where my thinking reaches its limits.

Upvotes: 1

Views: 85

Answers (3)

holdenweb
holdenweb

Reputation: 37033

Your code doesn't look too bad (though the DRY principle is being violated). It appears you have made an assignment (of a dict value) to the name builtins, which in my 2.7 installation is a module not a dict. But you haven't.

airhead:~ sholden$ python
Python 2.7.6 (default, Nov 19 2013, 03:12:29)
[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> __builtins__
<module '__builtin__' (built-in)>
>>>

@rczajka give you the correct answer, which I've upvoted.

Upvotes: 0

rczajka
rczajka

Reputation: 1840

Do not rely on the __builtins__. Instead, import __builtin__ and use __builtin__.print. See here: https://docs.python.org/2/reference/executionmodel.html

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.

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.

Upvotes: 4

Aaron Digulla
Aaron Digulla

Reputation: 328614

There might be a way to make this work but I suggest to look at the logging module instead.

print() is a nice little helper for you basic "output text" needs. Logging is much more powerful, it can add time stamps and "where was this printed" information to the output.

Upvotes: 1

Related Questions