<p>好问题。在</p>
<p>这是因为Python通过绕过Python级别的<code>write</code>方法并直接调用<code>fputs</code>来优化对<code>file</code>对象的调用。在</p>
<p>要了解这一点,请考虑:</p>
<pre><code>$ 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!
</code></pre>
<p>从未调用<code>write</code>方法!在</p>
<p>现在,当对象不是<code>file</code>的子类时,一切都按预期工作:</p>
^{pr2}$
<p>仔细研究一下Python源代码,看起来罪魁祸首是<code>PyFile_WriteString</code>函数,它由<code>print</code>语句调用,它检查要写入的对象是否是<code>file</code>的实例,如果是,则绕过对象的方法并直接调用<code>fputs</code>:</p>
<pre><code>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;
}
</code></pre>