I am using python 2.6.6 and I need to overload the default python print function. I need to do it because this code may be used on a system where a built-in function has to be used to generate output, otherwise no output is displayed.
So, just for example, if you have a python script like this:
from __future__ import print_function
def NewPrint(Str):
with open("somefile.txt","a") as AFile:
AFile.write(Str)
def OverloadPrint():
global print
print = NewPrint
OverloadPrint()
print("ha")
It works fine. The input to the "overloaded" print is in the file specified by NewPrint.
Now with that in mind I would like to be able to run the couple of lines above and have print to do what NewPrint does during the entire execution of the script. Right now if I call a function from another module that uses print it will use the built-in print and not the one I just overwrote. I guess this has something to do with namespaces and built-ins, but my python is not good enough.
Edit:
I tried to keep simple, but looks like this caused more confusion...
I know my example does not do what the print function actually does. A better example of how I am thinking of coding it is (still not great I know):
def hli_print(*args, **kw):
"""
print([object, ...], sep=' ', end='\n', file=sys.stdout)
"""
sep = kw.get('sep', ' ')
end = kw.get('end', '\n')
File = kw.get('file', sys.stdout)
args = [str(arg) for arg in args]
string = sep.join(args) + end
File.write(string)
hli_Print(string)
From 2 above you can see the function I have to use to print to the GUI "hli_Print" it is a C++ function exposed through a swig wrapper.
From all the comments I guess that just using some print_() function instead of print() (which is what we currently do) may be the best, but I got really curious to see if in python it would be possible to do what I described.
By default, Python's print statement ends each string that is passed into the function with a newline character, \n . This behavior can be overridden with the function's end parameter, which is the core of this method.
Python print() Function The print() function prints the specified message to the screen, or other standard output device. The message can be a string, or any other object, the object will be converted into a string before written to the screen.
You saw print() called without any arguments to produce a blank line and then called with a single argument to display either a fixed or a formatted message. However, it turns out that this function can accept any number of positional arguments, including zero, one, or more arguments.
As @abarnert's answer and several comments have pointed out, replacing print
is probably not a good idea. But just for the sake of completeness, here's why your code was not successfully overriding it for other modules.
The print
function is defined in the module __builtin__
(which is renamed to builtins
in Python 3). The Python interpreter makes everything in the __builtin__
module's namespace available to all other code it is running without importing it into your module's own namespace. It's magical!
However, when you create your own function named print
(using print = NewPrint
) it doesn't overwrite the original version in __builtin__
. You're just creating a new variable in your module's namespace that shadows the old one from __builtin__
. The global
statement doesn't help, as it only lets you tell Python to that you want to write into your module's global namespace rather than some inner namespace inside a function.
To replace the default print
function, you will need to explicitly replace it in the __builtin__
module. Here's some example code that does that:
from __future__ import print_function
try:
import __builtin__ as builtins # Python 2
except ImportError:
import builtins # Python 3
_print = print # keep a local copy of the original print
builtins.print = lambda *args, **kwargs: _print("foo:", *args, **kwargs)
To repeat, this is really not a good idea. While making sure I understood what I was talking about in this answer, I managed to crash one of my Python sessions by replacing print
with a lambda function that didn't accept the file
parameter that Python uses to print to standard error. A few lines later the exception handler was not pleased when it got a second exception while trying to print another exception's traceback.
There's almost certainly a better way to get the results you want.
I don't think your question makes any sense.
First, if you're running Python 2.6, everything you import, etc., will be using print
statements, even if your own module is using the print
function. So, overloading the function will not affect anything else.
Second, you say "I need to do it because this code may be used on a system where a built-in function has to be used to generate output, otherwise no output is displayed." Well, your NewPrint
is not a built-in function, so this won't help anyway.
It's also worth noting that your NewPrint
doesn't implement most of the functionality of the print
function, and even the bit that it does implement, it does wrong (print(s)
will print s
followed by a newline). So, if you did replace the builtin print
function with yours, you'd just end up breaking most of your own code and any stdlib/third-party code you depend on.
It may be that you can accomplish what you want by creating a file-like object that replaces sys.stdout
. Otherwise, I can't see how anything could work. For example:
class FakeStdOut(object):
# … lots of other stuff to implement or inherit
def write(s):
with open("somefile.txt", "a") as f:
f.write(s)
def OverloadPrint():
sys.stdout = FakeStdOut()
But even if this works, it probably isn't what you really want. For a quick&dirty script, on a platform with a defective shell, this is sometimes a handy idea. But otherwise, it will probably cause you more trouble in the long run than coming up with a better solution. Here's just a few things that can go wrong (just as examples, not an exhaustive list)
>>
in the shell, you could just call the script differently.stdout
is a tty before you make the change, and configure itself for interactive output.print
ing, but it was actually, say, log
ging or writing to sys.stderr
or doing something else, so you've given yourself a false sense of security that you're now logging everything in somefile.txt
, and won't discover otherwise until 6 months later, when you desperately need that missing information to debug a problem at a customer site.Since you've edited the question, here's some further responses:
From all the comments I guess that just using some print_() function instead of print()
Yes, that's a more reasonable option. But I probably wouldn't call it print_
. And it's simpler to put the "do or do not" logic inside the function, instead of swapping implementations in and out of the global name (especially since you're going to screw that up at some point if your code isn't all in one big module).
I worked on a project with a similar use case: We had messages we wanted to go to the syslogs, and also go to a GUI "log window" if it was open. So we wrote a glog
function that wrapped that up, and nobody complained that they wanted to write print
instead. (In fact, at least one guy on the team was very happy that he could use print
for quick-and-dirty printouts while debugging without affecting the real output, especially when he had to debug the GUI logging code.)
But that was just because we didn't have any experience with the new (back then) logging
module. Nowadays, I think I'd create a logging
Handler
implementation that writes to the GUI window, and just add that handler, and use the standard logging
methods everywhere. And it sounds like that might be the best option for you.
Also, one last probably-irrelevant side issue:
We only use the standard library and our own swig wrappers, also our developers use print as a function (getting used to 3.X).
So why not use 3.x in the first place? Obviously 3.x has the actual 3.x standard library, instead of something kind of close to the 3.x standard library if you do some __future__
statements, and SWIG works with 3.x…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With