Globally override built-in print function?

Discussion in 'Python' started by Dave W., Apr 16, 2010.

  1. Dave W.

    Dave W. Guest

    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)
    Dave W., Apr 16, 2010
    #1
    1. Advertising

  2. Dave W.

    Robert Kern Guest

    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
    Robert Kern, Apr 16, 2010
    #2
    1. Advertising

  3. Dave W.

    Dave W. Guest

    > > 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?
    Dave W., Apr 16, 2010
    #3
  4. Dave W.

    Peter Otten Guest

    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
    Peter Otten, Apr 16, 2010
    #4
  5. Dave W.

    Lie Ryan Guest

    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)
    ============================================================
    Lie Ryan, Apr 16, 2010
    #5
  6. Dave W.

    Robert Kern Guest

    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
    Robert Kern, Apr 16, 2010
    #6
  7. Dave W.

    Dave W. Guest

    >>> 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"]
    Dave W., Apr 16, 2010
    #7
  8. 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.
    J. Cliff Dyer, Apr 16, 2010
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    914
    Bengt Richter
    Aug 1, 2005
  2. keto
    Replies:
    0
    Views:
    923
  3. David Cournapeau

    print a vs print '%s' % a vs print '%f' a

    David Cournapeau, Dec 30, 2008, in forum: Python
    Replies:
    0
    Views:
    345
    David Cournapeau
    Dec 30, 2008
  4. V S Rawat
    Replies:
    5
    Views:
    296
    Richard Cornford
    Jul 3, 2007
  5. Michael Herrmann
    Replies:
    16
    Views:
    281
    Michael Herrmann
    Dec 3, 2012
Loading...

Share This Page