91

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,556
  • 4
  • 37
  • 62

5 Answers5

162

How about os.devnull ?

import os
f = open(os.devnull,"w")
zookeeper.set_log_stream(f)
msanders
  • 5,499
  • 1
  • 27
  • 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
  • 811,175
  • 162
  • 1,198
  • 1,373
  • 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
6
>>> import os
>>> os.devnull
'nul'
SilentGhost
  • 287,765
  • 61
  • 300
  • 288
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
  • 37,919
  • 5
  • 65
  • 94
2

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,236
  • 3
  • 57
  • 86