From: Robert Kern on
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

From: Dave W. on
>>> 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"]
From: J. Cliff Dyer on
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.