1

I need to override some function arguments. For example I always want to call print function with argument: end='...\r\n'. I'm using functools to do that:

import functools
print = functools.partial(print, end='...\r\n')

And it works if the argument is not passed to print function:

print(1)
1...

but if someone calls print with the end parameter my override is ignored:

print(1, end='222\r\n')
1222

However I want for my override to work (I need to get this output):

print(1, end='222\r\n')
1...

How do I do that?

rfg
  • 1,331
  • 1
  • 8
  • 24
  • 4
    *Why* do you want to ignore an explicit argument? That seems like a frustrating experience for other developers. – jonrsharpe Aug 29 '19 at 09:35
  • @jonrsharpe the library I use passes `end=""` on all `print` calls and I need it to call `print` with `end='\r\n'`, as currently the formatting is broken. – rfg Aug 29 '19 at 09:38
  • What is the library? – Neil Aug 29 '19 at 09:44
  • @Neil AWS Sagemaker, here's an example: https://github.com/aws/sagemaker-python-sdk/blob/b33d1a29b77ec86d0c106ce32f97053652ff7933/src/sagemaker/session.py#L1381 – rfg Aug 29 '19 at 09:52
  • Sounds like you need `function overloading` with your scenario - https://stackoverflow.com/questions/550470/overload-print-python – shuberman Aug 29 '19 at 10:10

2 Answers2

0

Okay so first just to note, not all of the print functions in that library have and end="". And indeed there does appear to be a logic to when they aren't including a newline, so it is weird that you are finding the output unworkable. Are you sure that there is not something else causing the issue? Eg, if you are running in a container, that might be messing up your logs?

Assuming that Amazon has messed up, I would then still suggest that your first strategy is to open an issue on the Github or submit a pull request. Overriding the standard library to deal with a bad third party library should be a last resort, if a resort at all.

Just to emphasize why, if you override the meaning of print, you're pretty much working in a new programming language then. Go too far down that road and everything will be unpredictable and unsupported and you will have a very hard time convincing anyone else to contribute to your code.

If you must though, there are ways to hook into print calls, and run a pre-function. I think the best way to do this is to capture stdout itself. Because, this way, the behaviour of print is unaffected (it still sends data to stdout). You are just saying that you want stdout to go do something a bit different in your environment, which is not something that uncommon to want. See and example of this approach here: http://code.activestate.com/recipes/119404-print-hook/ and here is an example of hooking directly into print: https://github.com/rugginoso/Pyjacker

Neil
  • 3,020
  • 4
  • 25
  • 48
  • Thank you. I know it's caused by my setup, namely container and custom python repl. However this seems to be the easiest way to solve the issue. – rfg Aug 29 '19 at 10:50
  • 1
    @rfg: Adding more jank to a janky setup is unlikely to result in a long-term reduction in the number of problems you experience. – user2357112 Aug 30 '19 at 03:41
0

How do I do that?

You probably shouldn't do that. At least not without more logic. The whole point of doing print(..., end='') is to incrementally construct an output line. If you always mutate it to the form print(..., end='\r\n') you're breaking the intended format of the output. Assuming you really want to do that just override the builtin:

import builtins
import sys

real_print = builtins.print


def my_print(*values, sep=" ", end="", file=sys.stdout, flush=False):
    end += "\r\n"
    real_print(*values, sep=sep, end=end, file=file, flush=flush)


builtins.print = my_print
print("hello", end="")
print("goodbye", end="123")
print("really")
Kurtis Rader
  • 6,734
  • 13
  • 20