为什么一个文件对象刷新,但另一个没有? [英] Why does one file object flush, but the other one doesn't?
问题描述
class FlushingFileObject (file):
def write(self,* args,** kwargs):
return_val = file.write(self,* args,** kwargs)
self.flush()
return return_val
$ b $ def writelines(self,* args,** kwargs):
return_val = file.writelines(self,* args,** kwargs)
self .flush()
return return_val
但有趣的是,所以我尝试了一些东西,包括:
$ b $ $ pre $ class $ {$ b $ def $ _ $ __(self, * args,** kwargs):
self.file_object = file(* args,** kwargs)
$ b $ def __getattr __(self,item):
return getattr(self。 file_object,item)
def write(self,* args,** kwargs):
return_val = self.file_object.write(* args,** kwargs)
self。 FIL e_object.flush()
return return_val
$ b $ def writelines(self,* args,** kwargs):
return_val = self.file_object.writelines(* args,** kwargs )
self.file_object.flush()
return return_val
。
$ b 为什么在这个实例中不能继承文件
?
write
方法并调用 fputs,在 file
$ cat file_subclass.py
import sys
class FileSubclass(file):
def write(self,* a,** kw):
raise Exception (write write!)
writelines = write
sys.stdout = FileSubclass(/ dev / null,w)
printfoo
sys.stderr 。写(打印成功!\\\
)
$ python print_magic.py
打印成功!
write
/ p> 现在,当对象不是文件
的子类时,事情就像预期的那样工作:
$ cat object_subclass.py
import sys $ b $ class ObjectSubclass(object):
def __init __(self):
传递
def write(self,* a,** kw):
raise Exception(write called!)
writelines = write
sys.stdout = ObjectSubclass()
printfoo
sys.stderr.write(print succeeded!\\\
)
$ python object_subclass.py
Traceback(最近一次调用的最后一个) :
在< module>中,第13行的文件x.py
打印foo
文件x.py,第8行写入
抛出异常(write called!)
异常:写入!
挖掘Python源代码,看起来像罪魁祸首是 PyFile_WriteString
函数,由 print
语句调用,它检查正在写入的对象是否是文件的一个实例
,如果是的话,绕过对象的方法直接调用 fputs
:
<$ p如果(f == NULL){
)
$ Py $ / * ... snip ... * /
}
if(PyFile_Check(f)){// - `isinstance(f,file)`
PyFileObject * fobj =(PyFileObject *)f ;
FILE * fp = PyFile_AsFile(f);
if(fp == NULL){
err_closed();
返回-1;
FILE_BEGIN_ALLOW_THREADS(fobj)
fputs(s,fp); // fputs,完全绕过Python对象
FILE_END_ALLOW_THREADS(fobj)
return 0;
if(!PyErr_Occurred()){
PyObject * v = PyString_FromString(s);
int err;
if(v == NULL)
return -1;
err = PyFile_WriteObject(v,f,Py_PRINT_RAW);
Py_DECREF(v);
返回错误;
}
else
return -1;
}
I wanted a file object that flushes out straight to file as data is being written, and wrote this:
class FlushingFileObject(file):
def write(self,*args,**kwargs):
return_val= file.write(self,*args,**kwargs)
self.flush()
return return_val
def writelines(self,*args,**kwargs):
return_val= file.writelines(self,*args,**kwargs)
self.flush()
return return_val
but interestingly it doesn't flush as I write to it, so I tried a few things including this:
class FlushingFileObject(object):
def __init__(self,*args,**kwargs):
self.file_object= file(*args,**kwargs)
def __getattr__(self, item):
return getattr(self.file_object,item)
def write(self,*args,**kwargs):
return_val= self.file_object.write(*args,**kwargs)
self.file_object.flush()
return return_val
def writelines(self,*args,**kwargs):
return_val= self.file_object.writelines(*args,**kwargs)
self.file_object.flush()
return return_val
which does flush.
Why doesn't subclassing file
work in this instance?
Great question.
This happens because Python optimizes calls to write
on file
objects by bypassing the Python-level write
method and calling fputs
directly.
To see this in action, consider:
$ cat file_subclass.py
import sys
class FileSubclass(file):
def write(self, *a, **kw):
raise Exception("write called!")
writelines = write
sys.stdout = FileSubclass("/dev/null", "w")
print "foo"
sys.stderr.write("print succeeded!\n")
$ python print_magic.py
print succeeded!
The write
method was never called!
Now, when the object isn't a subclass of file
, things work as expected:
$ cat object_subclass.py
import sys
class ObjectSubclass(object):
def __init__(self):
pass
def write(self, *a, **kw):
raise Exception("write called!")
writelines = write
sys.stdout = ObjectSubclass()
print "foo"
sys.stderr.write("print succeeded!\n")
$ python object_subclass.py
Traceback (most recent call last):
File "x.py", line 13, in <module>
print "foo"
File "x.py", line 8, in write
raise Exception("write called!")
Exception: write called!
Digging through the Python source a bit, it looks like the culprit is the PyFile_WriteString
function, called by the print
statement, which checks to see whether the object being written to is an instance of file
, and if it is, bypasses the object's methods and calls fputs
directly:
int
PyFile_WriteString(const char *s, PyObject *f)
{
if (f == NULL) {
/* … snip … */
}
else if (PyFile_Check(f)) { //-- `isinstance(f, file)`
PyFileObject *fobj = (PyFileObject *) f;
FILE *fp = PyFile_AsFile(f);
if (fp == NULL) {
err_closed();
return -1;
}
FILE_BEGIN_ALLOW_THREADS(fobj)
fputs(s, fp); //-- fputs, bypassing the Python object entirely
FILE_END_ALLOW_THREADS(fobj)
return 0;
}
else if (!PyErr_Occurred()) {
PyObject *v = PyString_FromString(s);
int err;
if (v == NULL)
return -1;
err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
Py_DECREF(v);
return err;
}
else
return -1;
}
这篇关于为什么一个文件对象刷新,但另一个没有?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!