100

I'm using the following code to hide stderr on Linux/OSX for a Python library I do not control that writes to stderr by default:

f = open("/dev/null","w")
zookeeper.set_log_stream(f)

Is there an easy cross platform alternative to /dev/null? Ideally it would not consume memory since this is a long running process.

Tristan
  • 6,776
  • 5
  • 40
  • 63
  • 1
    possible duplicate of [/dev/null in Windows?](http://stackoverflow.com/questions/313111/dev-null-in-windows) – msw May 28 '10 at 14:39
  • 9
    @msw: I don't think so, Python has more ways you can deal with this issue. – Andrew Aylett May 28 '10 at 14:45
  • **note**: ■ hand-written null file object might actually be **slower** than `open(os.devnull)` according to user https://stackoverflow.com/a/13944391/5267751 ■ if you want to redirect stdout there's a special solution https://stackoverflow.com/a/47419332/5267751 – user202729 Nov 16 '22 at 09:54

6 Answers6

176

How about os.devnull ?

import os
f = open(os.devnull,"w")
zookeeper.set_log_stream(f)
msanders
  • 5,739
  • 1
  • 29
  • 30
48
class Devnull(object):
    def write(self, *_): pass

zookeeper.set_log_stream(Devnull())

Opening os.devnull is fine too of course, but this way every output operation occurs (as a noop) "in process" -- no context switch to the OS and back, and also no buffering (while some buffering is normally used by an open) and thus even less memory consumption.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 6
    I understand that using os.devnull may produce some overhead. But if one uses your object what if the zookeeper object calls other methods then `write` of its log_stream file object? Maybe it calls the `writelines` method? Then there is an exception. – miracle173 Apr 05 '14 at 09:50
  • 5
    This doesn't work when you need a *real* file, e.g. one with `fileno()`. – Jonathon Reinhart Apr 07 '15 at 22:48
  • @JonathonReinhart For that, I suppose you could create the file descriptor lazily on request, using `os.open(os.devnull, os.O_RDWR)` and yielding the same fd for subsequent calls to `fileno` (since all data are discarded anyway) – minmaxavg Aug 29 '17 at 10:08
  • You'll also need `close()` – shoosh Feb 20 '19 at 09:19
  • @shoosh Would inhering from `io.IOBase` and just overwrite `write()` as above do the trick? That would provide all the methods clients might expect. – joanis Dec 06 '21 at 21:51
7
>>> import os
>>> os.devnull
'nul'
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
5

Create your own file-like object which doesn't do anything?

class FakeSink(object):
    def write(self, *args):
        pass
    def writelines(self, *args):
        pass
    def close(self, *args):
        pass
Andrew Aylett
  • 39,182
  • 5
  • 68
  • 95
3

Cheap solution warning!

class DevNull():
  def __init__(self, *args):
    self.closed = False
    self.mode = "w"
    self.name = "<null>"
    self.encoding = None
    self.errors = None
    self.newlines = None
    self.softspace = 0
  def close(self):
    self.closed == True
  @open_files_only
  def flush(self):
    pass
  @open_files_only
  def next(self):
    raise IOError("Invalid operation")
  @open_files_only
  def read(size = 0):
    raise IOError("Invalid operation")
  @open_files_only
  def readline(self):
    raise IOError("Invalid operation")
  @open_files_only
  def readlines(self):
    raise IOError("Invalid operation")
  @open_files_only
  def xreadlines(self):
    raise IOError("Invalid operation")
  @open_files_only
  def seek(self):
    raise IOError("Invalid operation")
  @open_files_only
  def tell(self):
    return 0
  @open_files_only
  def truncate(self):
    pass
  @open_files_only
  def write(self):
    pass
  @open_files_only
  def writelines(self):
    pass

def open_files_only(fun):
  def wrapper(self, *args):
    if self.closed:
      raise IOError("File is closed")
    else:
      fun(self, *args)
  return wrapper
badp
  • 11,409
  • 3
  • 61
  • 89
0

Also return the amount of bytes "written" (like write does):

import types

f = types.SimpleNamespace(write=len)
zookeeper.set_log_stream(f)
idanp
  • 973
  • 12
  • 18