Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Globally override built-in print function?

Reply
Thread Tools

Globally override built-in print function?

 
 
Dave W.
Guest
Posts: n/a
 
      04-15-2010
I naively thought I could capture output from exec()'ed print
invocations by (somehow) overriding 'print' globally. But this
seems not to be possible. Or at least not easy:

c:\d>test.py
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit
(Intel)] win32
Type "help", "copyright", "credits" or "license" for more info.
>>> print("Hello?")

Hello?
>>>


My custom print function isn't being called (see code below),
I guess because its only being overridden in the current module?
Is there some way to make InteractiveInterpreter/exec use my print
function, or is this simply not possible?

----------

### File test.py ###
from __future__ import print_function
import sys
from code import InteractiveInterpreter
from contextlib import contextmanager

def printhook(*args):
sys.stdout.write("printhook(): {0}\n".format(repr(args[0])))

@contextmanager
def global_printhook(printhook):
global print
print = printhook
yield
print = __builtins__.print

py = InteractiveInterpreter()

if not hasattr(sys, "ps1"): sys.ps1 = ">>> "
if not hasattr(sys, "ps2"): sys.ps2 = "... "

banner = ("Python %s\n%s\n" % (sys.version, sys.platform) +
'Type "help", "copyright", "credits" or "license" '
'for more info.\n')

sys.stdout.write(banner)
sys.stdout.write(sys.ps1)
while True:
try:
with global_printhook(printhook):
result = py.runsource(raw_input())
if result is None:
sys.stdout.write(sys.ps2)
elif result is True:
py.runcode(result)
except EOFError:
break
else:
sys.stdout.write(sys.ps1)
 
Reply With Quote
 
 
 
 
Robert Kern
Guest
Posts: n/a
 
      04-15-2010
On 2010-04-15 18:08 PM, Dave W. wrote:
> I naively thought I could capture output from exec()'ed print
> invocations by (somehow) overriding 'print' globally. But this
> seems not to be possible. Or at least not easy:
>
> c:\d>test.py
> Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit
> (Intel)] win32
> Type "help", "copyright", "credits" or "license" for more info.
>>>> print("Hello?")

> Hello?
>>>>

>
> My custom print function isn't being called (see code below),
> I guess because its only being overridden in the current module?
> Is there some way to make InteractiveInterpreter/exec use my print
> function, or is this simply not possible?
>
> ----------
>
> ### File test.py ###
> from __future__ import print_function
> import sys
> from code import InteractiveInterpreter
> from contextlib import contextmanager
>
> def printhook(*args):
> sys.stdout.write("printhook(): {0}\n".format(repr(args[0])))
>
> @contextmanager
> def global_printhook(printhook):
> global print
> print = printhook
> yield
> print = __builtins__.print


old_print = __builtins__.print
__builtins__.print = printhook
yield
__builtins__.print = old_print

But you really should replace sys.stdout and sys.stderr instead.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

 
Reply With Quote
 
 
 
 
Dave W.
Guest
Posts: n/a
 
      04-16-2010
> > I naively thought I could capture output from exec()'ed print
> > invocations by (somehow) overriding 'print' globally. But this
> > seems not to be possible. <snip>


>
> old_print = __builtins__.print
> __builtins__.print = printhook
> yield
> __builtins__.print = old_print


I'm pretty sure this is semantically equivalent to my original code,
but I gave it a try anyway. FWIW, it doesn't work, either. :-}

> But you really should replace sys.stdout and sys.stderr instead.


I'm starting to believe it, but... I thought that one of the
benefits of making print a function was that it *could* be globally
replaced. So far I've had no luck injecting a custom print
replacement into other modules. Is this really not possible?
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      04-16-2010
Dave W. wrote:

> I naively thought I could capture output from exec()'ed print
> invocations by (somehow) overriding 'print' globally. But this
> seems not to be possible. Or at least not easy:


Assigning a new function to the global print name affects only print() calls
within your script, not the REPL. You have to redirect the latter and make
sure that it is actually used instead of the print statement.

The easiest way I see to achieve that would be:

py.runsource("from __future__ import print_function")
py.runsource("from __main__ import printhook as print")

Peter

 
Reply With Quote
 
Lie Ryan
Guest
Posts: n/a
 
      04-16-2010
On 04/16/10 12:17, Dave W. wrote:
>>> I naively thought I could capture output from exec()'ed print
>>> invocations by (somehow) overriding 'print' globally. But this
>>> seems not to be possible. <snip>

>
>>
>> old_print = __builtins__.print
>> __builtins__.print = printhook
>> yield
>> __builtins__.print = old_print

>
> I'm pretty sure this is semantically equivalent to my original code,
> but I gave it a try anyway. FWIW, it doesn't work, either. :-}
>
>> But you really should replace sys.stdout and sys.stderr instead.

>
> I'm starting to believe it, but... I thought that one of the
> benefits of making print a function was that it *could* be globally
> replaced. So far I've had no luck injecting a custom print
> replacement into other modules. Is this really not possible?


No, the benefit of 'from __future__ import print_function' is for easing
transition to python 3. The ability to replace print globally only works
in python 3, after applying the change Robert Kern and turning raw_input
to input, the code works in python 3:

lieryan@compaq ~/junks $ python3 printhook.py
Python 3.1.2 (r312:79147, Apr 16 2010, 16:58:34)
[GCC 4.3.4]
linux2
Type "help", "copyright", "credits" or "license" for more info.
>>> print(32)

printhook(): 32

Note that assigning to __builtins__.print is different from assigning to
print. With the latter, you shadowed the print function in
__builtins__.print by putting your own print in the global namespace
(which in python really means module-level); while with the former
you're switching print in the interpreter level, the true global namespace.

================================================== ======
### File test.py ###
from __future__ import print_function
import sys
from code import InteractiveInterpreter
from contextlib import contextmanager

def printhook(*args):
sys.stdout.write("printhook(): {0}\n".format(repr(args[0])))

@contextmanager
def global_printhook(printhook):
global print
print = printhook
yield
print = __builtins__.print

py = InteractiveInterpreter()

if not hasattr(sys, "ps1"): sys.ps1 = ">>> "
if not hasattr(sys, "ps2"): sys.ps2 = "... "

banner = ("Python %s\n%s\n" % (sys.version, sys.platform) +
'Type "help", "copyright", "credits" or "license" '
'for more info.\n')

sys.stdout.write(banner)
sys.stdout.write(sys.ps1)
while True:
try:
with global_printhook(printhook):
result = py.runsource(input())
if result is None:
sys.stdout.write(sys.ps2)
elif result is True:
py.runcode(result)
except EOFError:
break
else:
sys.stdout.write(sys.ps1)
================================================== ==========
 
Reply With Quote
 
Robert Kern
Guest
Posts: n/a
 
      04-16-2010
On 2010-04-15 21:17 PM, Dave W. wrote:
>>> I naively thought I could capture output from exec()'ed print
>>> invocations by (somehow) overriding 'print' globally. But this
>>> seems not to be possible.<snip>

>
>>
>> old_print = __builtins__.print
>> __builtins__.print = printhook
>> yield
>> __builtins__.print = old_print

>
> I'm pretty sure this is semantically equivalent to my original code,
> but I gave it a try anyway.


Not at all. Declaring "global print" then assigning to "print" simply changes
what the module's "print" variable refers to. Other modules are unaffected.
"Global" variables aren't truly global; they are actually local to the module.
You need to replace it in the __builtins__ because that's where everyone else
gets it.

> FWIW, it doesn't work, either. :-}


Right. Lie answered why. I didn't pay attention and thought you were already
using Python 3.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

 
Reply With Quote
 
Dave W.
Guest
Posts: n/a
 
      04-16-2010
>>> old_print = __builtins__.print
>>> __builtins__.print = printhook
>>> yield
>>> __builtins__.print = old_print

>
>> I'm pretty sure this is semantically equivalent to my original
>> code, but I gave it a try anyway.

>
> Not at all. Declaring "global print" then assigning to "print"
> simply changes what the module's "print" variable refers to. Other
> modules are unaffected. "Global" variables aren't truly global;
> they are actually local to the module. You need to replace it in
> the __builtins__ because that's where everyone else gets it.
>
> > FWIW, it doesn't work, either. :-}

>
> Right. Lie answered why. I didn't pay attention and thought you
> were already using Python 3.


Thanks, Robert and Lie for the considered and informative responses.
Getting feedback like this from people who really understand
Python's internals is invaluable. Sounds like redirecting
stdout/stderr is the way to go. (Especially given that they're not
the 'real' stdout/stderr---that was news to me!)

[xref "Suppress output to stdout/stderr in InteractiveInterpreter"]
 
Reply With Quote
 
J. Cliff Dyer
Guest
Posts: n/a
 
      04-16-2010
On Fri, 2010-04-16 at 09:50 -0700, Dave W. wrote:
> >>> old_print = __builtins__.print
> >>> __builtins__.print = printhook
> >>> yield
> >>> __builtins__.print = old_print

> >
> >> I'm pretty sure this is semantically equivalent to my original
> >> code, but I gave it a try anyway.

> >
> > Not at all. Declaring "global print" then assigning to "print"
> > simply changes what the module's "print" variable refers to. Other
> > modules are unaffected. "Global" variables aren't truly global;
> > they are actually local to the module. You need to replace it in
> > the __builtins__ because that's where everyone else gets it.
> >
> > > FWIW, it doesn't work, either. :-}

> >
> > Right. Lie answered why. I didn't pay attention and thought you
> > were already using Python 3.

>
> Thanks, Robert and Lie for the considered and informative responses.
> Getting feedback like this from people who really understand
> Python's internals is invaluable. Sounds like redirecting
> stdout/stderr is the way to go. (Especially given that they're not
> the 'real' stdout/stderr---that was news to me!)
>
> [xref "Suppress output to stdout/stderr in InteractiveInterpreter"]


It's good to remember that names in python are just names. The objects
that have the names "sys.stdout" and "sys.stderr" are the real deal, but
when you assign a file object to them, you are not actually
"redirecting" anything. You are assigning a name (sys.stdout) to a
different file object. The old object still points to STDOUT, but
sys.stdout no longer refers to that object as long as your assignment
remains in scope.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
print a vs print '%s' % a vs print '%f' a David Cournapeau Python 0 12-30-2008 03:19 AM
Problem - I want to print Current Output of Pdf file and should print once.I get print dialog box but it is not working keto Java 0 05-30-2007 11:27 AM
Unlarging the print to print using PDF file to print Bun Mui Computer Support 3 09-13-2004 03:15 AM
Actual is not a globally static expression valentin tihomirov VHDL 7 02-17-2004 03:48 PM
Error: Actual is not a globally static expression Steve Harrad VHDL 5 12-22-2003 08:49 PM



Advertisments