inherit from file and create stdout instance?

1 view
Skip to first unread message

MisterPete

unread,
May 15, 2007, 6:18:18 PM5/15/07
to
How can I inherit from file but stil create an instance that writes to
stdout?
-----------
I'm writing a file-like object that has verbosity options (among
some other things). I know I could just set self.file to a file object
rather than inheriting from file. I started with something like this
(simplified for clarity):

class Output(object):
def __init__(self, file=sys.stdout, verbosity=1):
self.verbosity = verbosity
self.file = file

def write(self, string, messageVerbosity=1):
if messageVerbosity <= self.verbosity:
self.file.write(string)
...

but it is frustrating me that if I try to inherit from file it
works fine for regular files but I can't figure out a clean way to
instantiate an object that writes to stdout using sys.stdout.
something like the following:


class Output(object):
def __init__(self, file=sys.stdout, verbosity=1):
self.verbosity = verbosity
self.file = file

def write(self, string, messageVerbosity=1):
if messageVerbosity <= self.verbosity:
self.file.write(string)
...

I hope that's clear. Is it just a bad idea to inherit from file to
create a class to write to stdout or am I missing something? Any
insight is appreciated.

Thanks,
Pete

7stud

unread,
May 15, 2007, 7:02:58 PM5/15/07
to

Your code works for me:


import sys

class Output(file):


def __init__(self, file=sys.stdout, verbosity=1):
self.verbosity = verbosity
self.file = file

def write(self, string, messageVerbosity=1):
if messageVerbosity <= self.verbosity:
self.file.write(string)

o = Output()
o.write("this goes to a console window")

f = open("aaa.txt", "w")
o = Output(f)
o.write("this goes to a file")

MisterPete

unread,
May 15, 2007, 7:38:14 PM5/15/07
to
> Your code works for me:
>
> import sys
>
> class Output(file):
> def __init__(self, file=sys.stdout, verbosity=1):
> self.verbosity = verbosity
> self.file = file
>
> def write(self, string, messageVerbosity=1):
> if messageVerbosity <= self.verbosity:
> self.file.write(string)
>
> o = Output()
> o.write("this goes to a console window")
>
> f = open("aaa.txt", "w")
> o = Output(f)
> o.write("this goes to a file")

I could make wrappers around all of the file methods but that kind
of defeats the purpose of inheriting from file. It's kind of odd to
inherit from file but then keep a file object (although then it would
at least pass any isinstance(object, file) tests at least) and
overwrite every single method. I'd prefer that I inherit from file
and just get flush and next and everything for free (and any new
methods if they were added).

What I'm really looking for is to make a copy of the sys.stdout
object but make it an Output object. If the file object just had a
__dict__ with a buffer I could grab or something like that it wouldn't
be too tough. Unfortunately I don't even know how I could make a copy
of sys.stdout since the copy module doesn't work for file objects.

Thanks,
Pete

Gabriel Genellina

unread,
May 15, 2007, 9:43:49 PM5/15/07
to pytho...@python.org
En Tue, 15 May 2007 20:38:14 -0300, MisterPete <pete.lo...@gmail.com>
escribió:

> I could make wrappers around all of the file methods but that kind
> of defeats the purpose of inheriting from file. It's kind of odd to
> inherit from file but then keep a file object (although then it would
> at least pass any isinstance(object, file) tests at least) and
> overwrite every single method. I'd prefer that I inherit from file
> and just get flush and next and everything for free (and any new
> methods if they were added).

Instead of inheriting from file, you can delegate to a file instance.
Python makes it rather easy:

py> import sys
py>
py> class Output:
... file = None
... verbosity = 1
... def __init__(self, file=None, verbosity=1):
... if file is None: file = sys.stdout
... self.file = file
... self.verbosity = verbosity
... def write(self, string, messageVerbosity=1):
... if messageVerbosity <= self.verbosity:
... self.file.write(string)
... def __getattr__(self, name):
... return getattr(self.file, name)
... def __setattr__(self, name, value):
... if name in dir(self): self.__dict__[name] = value
... else: setattr(self.file, name, value)
...
py> f1 = Output(verbosity=100)
py> f1.write("Console output\n")
Console output
py> f1.flush()
py> print f1.isatty()
True
py> print f1.verbosity
100
py> f1.verbosity = 5
py> print f1.verbosity
5
py>
py> f2 = Output(open("aaa.txt","w"))
py> f2.write("Goes to another file\n")
py> f2.flush()
py> print f2.isatty()
False
py> print f2.tell()
22
py> f2.close()

As you can see, I'm using file methods and attributes that I didn't
redefine explicitely. See the section "Customizing attribute access" on
the Python Reference Manual about __getattr__ and __setattr__

--
Gabriel Genellina

7stud

unread,
May 15, 2007, 9:50:23 PM5/15/07
to
>but it is frustrating me that if I try to inherit from file it
>works fine for regular files

I don't think that is correct characterization at all. What really
happens is that when you inherit from file, your class works when you
send the __init__ method a string, i.e. a filename. sys.stdout is not
a string. Presumably, when you have a file object like sys.stdout
already, you don't need to turn it into a file object, and therefore
file's init() method is not defined to accept a file object.

>Is it just a bad idea to inherit from file to
>create a class to write to stdout or am I missing something?

It seems to me that the very nature of a file object is to read and
write to itself. Yet, in some cases you want your file object to be
able to write to another file object. Why would you want your object
to be a file object if you can't use any of its methods?

7stud

unread,
May 15, 2007, 9:56:56 PM5/15/07
to
On May 15, 7:43 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:

>>... def __getattr__(self, name):
>>... return getattr(self.file, name)

Nice.

MisterPete

unread,
May 15, 2007, 11:08:39 PM5/15/07
to

7stud,
I don't really want it to write to another file object, I'd like it to
work just like a file object except for some extra options like
verbosity. Similar to how sys provides stdout and stderr file objects
I would like to provide Output objects for stdout and stderr... but
without accepting a file object I'm not sure how I would instantiate
an Output object that writes to anything like stdout or stderr without
special casing them

Gabriel,
thanks for the suggestion! I think I'll go with an approach similar to
that :) I guess I can't really get around using the stdout/stderr
file objects for writing to those buffers.

=============
oops, not that it really matters but I just realized that I cut and
pasted the same code twice in my original post. I had meant to put
this as the second chunk of code

class Output(file):
def __init__(self, name, mode='w', buffering=None, verbosity=1):
super(Output, self).__init__(name, mode, buffering)
self.verbosity = 1

def write(self, string, messageVerbosity=1):
if messageVerbosity <= self.verbosity

super(Output, self).write(string)

MisterPete

unread,
May 15, 2007, 11:22:29 PM5/15/07
to
> class Output(file):
> def __init__(self, name, mode='w', buffering=None, verbosity=1):
> super(Output, self).__init__(name, mode, buffering)
> self.verbosity = verbosity

>
> def write(self, string, messageVerbosity=1):
> if messageVerbosity <= self.verbosity
> super(Output, self).write(string)

I may have to just accept name as a string or as a file object so that
I can still provide the same interface as a file object. It'll just
store and use a separate file object when it needs to handle writing
to stdout and sterr. This way it should always be able to be used in
place of a file object.

err, and again, not that it matters but in the code above verbosity
should of course get the value passed in, not 1 :/

Reply all
Reply to author
Forward
0 new messages