Overload Print Python

How to overload print function to expand its functionality?

You can create a class with a write method and inside of that method you can print both stdout as well as write to the file.

import sys

class A(object):
def __init__(self, f):
self.f = open(f, 'w')

def __enter__(self):
return self # return instance of A which is assign to `f`.

def write(self, text):
sys.stdout.write(text) # print to the shell
self.f.write(text) # write in the file

def __exit__(self, *args):
self.f.close()
return True

with A('foo.txt') as f:
print("test0","test1","test4",sep='\n', file=f) #`file = f` calls `write` method

How to overload python's print function globally?

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)

  • If you ever want to change the file the output goes to, you have to modify the script. If you instead used >> in the shell, you could just call the script differently.
  • Someone reading or debugging your code (like, say, you, three months after you forgot how it worked) will be surprised by what's going on.
  • Some stdlib/third-party/coworker/etc. code you call will check that stdout is a tty before you make the change, and configure itself for interactive output.
  • Some code will print before you got a chance to redirect, and you'll spend hours trying to figure out how to reorder things to work around the problem.
  • You have to know how to implement a 'file-like object' completely—and that concept is not fully defined in 2.6—or it will break with some code.
  • Somewhere, there's some code that you thought was printing, but it was actually, say, logging 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…

How to print instances of a class using print()?

>>> class Test:
... def __repr__(self):
... return "Test()"
... def __str__(self):
... return "member of Test"
...
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test

The __str__ method is what gets called happens when you print it, and the __repr__ method is what happens when you use the repr() function (or when you look at it with the interactive prompt).

If no __str__ method is given, Python will print the result of __repr__ instead. If you define __str__ but not __repr__, Python will use what you see above as the __repr__, but still use __str__ for printing.

Python change Exception printable output, eg overload __builtins__

I'll just explain the behaviour you described:

  • exc.__repr__()

This will just call your lambda function and return the expected string. Btw you should return the string, not print it in your lambda functions.

  • print(repr(exc))

Now, this is going a different route in CPython and you can see this in a GDB session, it's something like this:

Python/bltinmodule.c:builtin_repr will call Objects/object.c:PyObject_Repr - this function gets the PyObject *v as the only parameter that it will use to get and call a function that implements the built-in function repr(), BaseException_repr in this case. This function will format the error message based on a value from args structure field:

(gdb) p ((PyBaseExceptionObject *) self)->args 
$188 = ("name 'x' is not defined",)

The args value is set in Python/ceval.c:format_exc_check_arg based on a NAME_ERROR_MSG macro set in the same file.

Update: Sun 8 Nov 20:19:26 UTC 2020

test.py:

import sys
import dis

def main():
try:
x
except NameError as exc:
tb = sys.exc_info()[2]
frame, i = tb.tb_frame, tb.tb_lasti
code = frame.f_code
arg = code.co_code[i + 1]
name = code.co_names[arg]
print(name)

if __name__ == '__main__':
main()

Test:

# python test.py
x

Note:

I would also recommend to watch this video from PyCon 2016.



Related Topics



Leave a reply



Submit