Is there any way to redirect output with reduce but not using print?

I’m working with an IO to read whole content of file and print it with reduce.

from functools import reduce

with open("test.py") as f:
    reduce(print, (line for line in f))

Output:

from functools import reduce


None with open("test.py") as f:

None     reduce(print, (line for line in f))

None

I assume that the “None” is caused by print function. How to redirect output with reduce and show it but not show “None”? Thanks in advance.

You can use the write method of any file object opened for write or append. You might need to write a wrapper function if you want print-like behavior. Your example should work fine unwrapped, something like (untested) this with sys.stdout:

import sys
from functools import reduce
with open("test.py") as f:
    reduce(sys.stdout.write, (line for line in f))
  1. The function print() has side-effects (writes text to a stream) so it is not something you should use in functional style. See my recent post:
  1. reduce(function, iterable) calls the function with two arguments: the previous return value of the function and an item from the iterable.[1] None you see are the return values of the previous print() calls.

  2. You are not “redirecting” the output. You are calling something like:

print(
    print(
        print(
            None,
            line1),
        line2),
    line3)
    )
  1. (line for line in f) is redundant. You can use f directly. It is already an iterable.

  1. This is the principle how it “reduces” the items to a single item: functools — Higher-order functions and operations on callable objects — Python 3.10.5 documentation ↩︎

1 Like

It didn’t work to me.

Traceback (most recent call last):
  File "C:\Users\hungpham\Python_projects\Practice\test.py", line 5, in <module>
    reduce(sys.stdout.write, f)
TypeError: TextIOWrapper.write() takes exactly one argument (2 given)
shell returned 1

As Skip wrote:

The error message tells tou that write()takes exactly one argument”.

Anyway as I wrote, I do not think this is functional style.

Why are you doing this?

This is like hammering in a screw using the handle of a saw. You should
use the right tool for the job, and that is not reduce!

with open("test.py") as f:
    print(f.read())

Or if you want to do it line by line (in case the file is huge):

with open("test.py") as f:
    for line in f:
        print(line, end='')

If you are doing this to win a bet, you could do this:

reduce(lambda a, b: print(b, end=''), f, reduce)

Which has the advantage of being even more cryptic than normal one-liners, perfect to win a bet at the pub.

3 Likes