By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
464,697 Members | 1,286 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 464,697 IT Pros & Developers. It's quick & easy.

print doesn't respect file inheritance?

P: n/a
I was trying to change the behaviour of print (tee all output to a
temp file) by inheriting from file and overwriting sys.stdout, but it
looks like print uses C-level stuff to do its writes which bypasses
the python object/inhertiance system. It looks like I need to use
composition instead of inheritance, but thought this was strange
enough to note.

$python -V
Python 2.5

"""A short demo script"""
class notafile(file):
def __init__(self, *args, **kwargs):
readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
'newlines', 'softspace']
file.__init__(self, *args, **kwargs)
for attr in dir(file):
if attr in readonly: continue
setattr(self, attr, None)
def main():
n = notafile('/dev/stdout', "w")
print vars(n)

import sys
sys.stdout = n
print "Testing: 1, 2, 3..."
output:
{'__str__': None, 'xreadlines': None, 'readlines': None, 'flush':
None, 'close': None, 'seek': None, '__init__': None, '__setattr__':
None, '__reduce_ex__': None, '__new__': None, 'readinto': None,
'next': None, 'write': None, '__doc__': None, 'isatty': None,
'truncate': None, 'read': None, '__reduce__': None,
'__getattribute__': None, '__iter__': None, 'readline': None,
'fileno': None, 'writelines': None, 'tell': None, '__delattr__': None,
'__repr__': None, '__hash__': None}
Testing: 1, 2, 3...
Jul 26 '08 #1
Share this Question
Share on Google+
7 Replies

P: n/a
bukzor <wo**********@gmail.comwrites:
I was trying to change the behaviour of print (tee all output to a
temp file) by inheriting from file and overwriting sys.stdout
That's not what your code does, though.
def main():
n = notafile('/dev/stdout', "w")
Creates a new instance of the 'notafile' class; the '=' operator then
binds that instance to the name 'n'.
import sys
Imports a module, and binds the module to the name 'sys'. This
includes, usually, the module attribute named by 'sys.stdout'.
sys.stdout = n
Re-binds the name 'sys.stdout' to the object already referenced by the
name 'n'. No objects are changed by this; only bindings of names to
objects.
print "Testing: 1, 2, 3..."
Doesn't rely at all on the name 'sys.stdout', so isn't affected by all
the binding of names above.
In other words, you can't change the object used by the 'print'
statement only by re-binding names (which is *all* that is done by the
'=' operator).

You can, however, specify which file 'print' should use
<URL:http://www.python.org/doc/ref/print.html>.

--
\ “When I wake up in the morning, I just can't get started until |
`\ I've had that first, piping hot pot of coffee. Oh, I've tried |
_o__) other enemas...” —Emo Philips |
Ben Finney
Jul 26 '08 #2

P: n/a


bukzor wrote:
I was trying to change the behaviour of print (tee all output to a
temp file) by inheriting from file and overwriting sys.stdout, but it
looks like print uses C-level stuff to do its writes which bypasses
the python object/inhertiance system. It looks like I need to use
composition instead of inheritance, but thought this was strange
enough to note.

$python -V
Python 2.5

"""A short demo script"""
class notafile(file):
def __init__(self, *args, **kwargs):
readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
'newlines', 'softspace']
file.__init__(self, *args, **kwargs)
for attr in dir(file):
if attr in readonly: continue
setattr(self, attr, None)
Drop the __init__ and give notafile a .write method.
Composition version inheritance is not the the real issue.
>>class nf(object):
def write(s):
print(s)
print(s)
>>print >>nf(), 'testing'
testing
testing

Now change nf.write to put the copy where you want it.

tjr

Jul 26 '08 #3

P: n/a
On Sat, 26 Jul 2008 14:07:52 +1000
Ben Finney <bi****************@benfinney.id.auwrote:
sys.stdout = n

Re-binds the name 'sys.stdout' to the object already referenced by the
name 'n'. No objects are changed by this; only bindings of names to
objects.
I do agree that the object formerly known as sys.stdout hasn't changed.
print "Testing: 1, 2, 3..."

Doesn't rely at all on the name 'sys.stdout', so isn't affected by all
the binding of names above.
Hmm. Are you saying that the following doesn't work?

$ python
>>f = open("test", "w")
import sys
sys.stdout = f
print "test message"
sys.exit(0)
$ cat test
test message
In other words, you can't change the object used by the 'print'
statement only by re-binding names (which is *all* that is done by the
'=' operator).
Apparently I can.
You can, however, specify which file 'print' should use
<URL:http://www.python.org/doc/ref/print.html>.
Which contains this statement.

"Standard output is defined as the file object named stdout in the
built-in module sys."

I suppose that there might be some ambiguity there but the proof, as
they say, is in the pudding.

--
D'Arcy J.M. Cain <da***@druid.net | Democracy is three wolves
http://www.druid.net/darcy/ | and a sheep voting on
+1 416 425 1212 (DoD#0082) (eNTP) | what's for dinner.
Jul 26 '08 #4

P: n/a
Lie
On Jul 26, 8:50*am, bukzor <workithar...@gmail.comwrote:
I was trying to change the behaviour of print (tee all output to a
temp file) by inheriting from file and overwriting sys.stdout, but it
looks like print uses C-level stuff *to do its writes which bypasses
the python object/inhertiance system. It looks like I need to use
composition instead of inheritance, but thought this was strange
enough to note.

$python -V
Python 2.5

"""A short demo script"""
class notafile(file):
* * def __init__(self, *args, **kwargs):
* * * * readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
'newlines', 'softspace']
* * * * file.__init__(self, *args, **kwargs)
* * * * for attr in dir(file):
* * * * * * if attr in readonly: continue
* * * * * * setattr(self, attr, None)

def main():
* * n = notafile('/dev/stdout', "w")
* * print vars(n)

* * import sys
* * sys.stdout = n
* * print "Testing: 1, 2, 3..."

output:
{'__str__': None, 'xreadlines': None, 'readlines': None, 'flush':
None, 'close': None, 'seek': None, '__init__': None, '__setattr__':
None, '__reduce_ex__': None, '__new__': None, 'readinto': None,
'next': None, 'write': None, '__doc__': None, 'isatty': None,
'truncate': None, 'read': None, '__reduce__': None,
'__getattribute__': None, '__iter__': None, 'readline': None,
'fileno': None, 'writelines': None, 'tell': None, '__delattr__': None,
'__repr__': None, '__hash__': None}
Testing: 1, 2, 3...
Use this:

class fakefile(object):
def __init__(self, writeto, transformer):
self.target = writeto
self.transform = transformer
def write(self, s):
s = self.transform(s)
self.target.write(s)
sys.stdout = fakefile(sys.stdout, lambda s: '"' + s + '"')

Inheriting from file is not the best way to do it since there is a
requirement that child class' interface must be compatible with the
parent class' interface, since the file-like object you're creating
must have extremely different interface than regular file, the best
way is to use Duck Typing, i.e. write a class that have .write()
method.
Jul 26 '08 #5

P: n/a
"D'Arcy J.M. Cain" <da***@druid.netwrites:
Hmm. Are you saying that the following doesn't work?

$ python
>f = open("test", "w")
import sys
sys.stdout = f
print "test message"
sys.exit(0)
$ cat test
test message
In other words, you can't change the object used by the 'print'
statement only by re-binding names (which is *all* that is done by
the '=' operator).

Apparently I can.
I admit to not trying any of the above. I was explaining the behaviour
reported by the original poster, without experimenting to see if I
could reproduce the behaviour.

Thanks for being more diligent.

--
\ “All persons, living and dead, are purely coincidental.” |
`\ —_Timequake_, Kurt Vonnegut |
_o__) |
Ben Finney
Jul 27 '08 #6

P: n/a
On Jul 26, 7:08*am, "D'Arcy J.M. Cain" <da...@druid.netwrote:
On Sat, 26 Jul 2008 14:07:52 +1000

Ben Finney <bignose+hates-s...@benfinney.id.auwrote:
* * sys.stdout = n
Re-binds the name 'sys.stdout' to the object already referenced by the
name 'n'. No objects are changed by this; only bindings of names to
objects.

I do agree that the object formerly known as sys.stdout hasn't changed.
* * print "Testing: 1, 2, 3..."
Doesn't rely at all on the name 'sys.stdout', so isn't affected by all
the binding of names above.

Hmm. *Are you saying that the following doesn't work?

$ python>>f = open("test", "w")
>import sys
sys.stdout = f
print "test message"
sys.exit(0)

$ cat test
test message
In other words, you can't change the object used by the 'print'
statement only by re-binding names (which is *all* that is done by the
'=' operator).

Apparently I can.
You can, however, specify which file 'print' should use
<URL:http://www.python.org/doc/ref/print.html>.

Which contains this statement.

"Standard output is defined as the file object named stdout in the
built-in module sys."

I suppose that there might be some ambiguity there but the proof, as
they say, is in the pudding.

--
D'Arcy J.M. Cain <da...@druid.net* * * * | *Democracy is three wolveshttp://www.druid.net/darcy/* * * * * * * *| *and a sheep voting on
+1 416 425 1212 * * (DoD#0082) * *(eNTP) * | *what's for dinner.
Thanks for backing me up.

Nobody here thinks it's strange that print uses *none* of the
attributes or methods of sys.stdout to do its job? The implementation
seems to bypass the whole python system and use C-level FILE* pointers
directly instead.
Jul 28 '08 #7

P: n/a
bukzor wrote:
I was trying to change the behaviour of print (tee all output to a
temp file) by inheriting from file and overwriting sys.stdout, but it
looks like print uses C-level stuff to do its writes which bypasses
the python object/inhertiance system. It looks like I need to use
composition instead of inheritance, but thought this was strange
enough to note.

$python -V
Python 2.5

"""A short demo script"""
class notafile(file):
def __init__(self, *args, **kwargs):
readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
'newlines', 'softspace']
file.__init__(self, *args, **kwargs)
for attr in dir(file):
if attr in readonly: continue
setattr(self, attr, None)
def main():
n = notafile('/dev/stdout', "w")
print vars(n)

import sys
sys.stdout = n
print "Testing: 1, 2, 3..."
output:
{'__str__': None, 'xreadlines': None, 'readlines': None, 'flush':
None, 'close': None, 'seek': None, '__init__': None, '__setattr__':
None, '__reduce_ex__': None, '__new__': None, 'readinto': None,
'next': None, 'write': None, '__doc__': None, 'isatty': None,
'truncate': None, 'read': None, '__reduce__': None,
'__getattribute__': None, '__iter__': None, 'readline': None,
'fileno': None, 'writelines': None, 'tell': None, '__delattr__': None,
'__repr__': None, '__hash__': None}
Testing: 1, 2, 3...
I tried the code (on Windows, so had to change /dev/stdout to
/temp/notafile.txt) and it worked just fine. Perhaps the issue is that
n is being set to /dev/stdout instead of some other file so no
difference is apparent?

In other words, you're assigning stdout to stdout.

~Ethan~
Sep 5 '08 #8

This discussion thread is closed

Replies have been disabled for this discussion.