Wieloplatformowy / dev / null w Pythonie

85

Używam następującego kodu, aby ukryć stderr w systemie Linux / OSX dla biblioteki Python, której nie kontroluję, która domyślnie zapisuje do stderr:

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

Czy istnieje łatwa wieloplatformowa alternatywa dla / dev / null? Idealnie byłoby, gdyby nie zużywał pamięci, ponieważ jest to długotrwały proces.

Tristan
źródło
1
możliwy duplikat / dev / null w systemie Windows?
msw
8
@msw: Nie sądzę, Python ma więcej sposobów radzenia sobie z tym problemem.
Andrew Aylett

Odpowiedzi:

150

A co z os.devnull ?

import os
f = open(os.devnull,"w")
zookeeper.set_log_stream(f)
msanders
źródło
47
class Devnull(object):
    def write(self, *_): pass

zookeeper.set_log_stream(Devnull())

Otwarcie też os.devnulljest w porządku, ale w ten sposób każda operacja wyjściowa jest wykonywana (jako noop) „w toku” - bez przełączania kontekstu na system operacyjny iz powrotem, a także bez buforowania (podczas gdy pewne buforowanie jest normalnie używane przez an open), a zatem jeszcze mniejsze zużycie pamięci.

Alex Martelli
źródło
6
Rozumiem, że używanie os.devnull może powodować pewne obciążenie. Ale jeśli ktoś użyje twojego obiektu, co jeśli obiekt zookeeper writewywoła inne metody niż jego obiekt pliku log_stream? Może wywołuje writelinesmetodę? Wtedy jest wyjątek.
cud173
5
To nie działa, gdy potrzebujesz prawdziwego pliku, np fileno(). Z rozszerzeniem .
Jonathon Reinhart
@JonathonReinhart W tym celu przypuszczam, że możesz leniwie utworzyć deskryptor pliku na żądanie, używając os.open(os.devnull, os.O_RDWR)tego samego fd dla kolejnych wywołań fileno(ponieważ i tak wszystkie dane są odrzucane)
minmaxavg
Będziesz także potrzebowaćclose()
shoosh
5
>>> import os
>>> os.devnull
'nul'
SilentGhost
źródło
11
Dla wyjaśnienia: w systemie Windows podano „nul”. Linux zwróci „/ dev / null”.
Walter
5

Utworzyć własny obiekt przypominający plik, który nic nie robi?

class FakeSink(object):
    def write(self, *args):
        pass
    def writelines(self, *args):
        pass
    def close(self, *args):
        pass
Andrew Aylett
źródło
1
Idiomatycznie masz rację, ale „self” to tylko kolejny parametr i zostanie przekazany jako pierwszy element funkcji args. Ponieważ nie stosujemy żadnego z parametrów, jedynym powodem do dbałości jest estetyka. Naprawię to ...
Andrew Aylett
2
Niektóre operacje wymagają również „fileno”
Jonathan Hartley
2

Ostrzeżenie o niedrogim rozwiązaniu!

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
źródło
Dla zabawy dorzuciłem dekorator: D
badp
Potrzebujesz też wejść i wyjść ?
user48956