Python 为什么在I';你把它拆开了?
我编写了一个Python 为什么在I';你把它拆开了?,python,python-3.x,spyder,Python,Python 3.x,Spyder,我编写了一个tee() 它在我的程序运行的前几次运行时起作用,但在第三次运行时: File "C:\Users\Dave\data\Code\Python\lib\nerdlib.py", line 351, in write with open(self.name, "a", encoding="utf-8") as f: TypeError: expected str, bytes or os.PathLike object, not NoneType 似乎即使在我执行了s
tee()
它在我的程序运行的前几次运行时起作用,但在第三次运行时:
File "C:\Users\Dave\data\Code\Python\lib\nerdlib.py", line 351, in write
with open(self.name, "a", encoding="utf-8") as f:
TypeError: expected str, bytes or os.PathLike object, not NoneType
似乎即使在我执行了sys.stdout=self.old_stdout(将执行向量恢复到它开始的位置)之后,我的write方法仍然会被调用(在这种情况下,错误是意料之中的)
但是为什么我的方法仍然被调用
此错误发生在开发环境中-不确定是否相关
代码如下-它足够简单
# based on Triptych's answer at https://stackoverflow.com/questions/616645/how-do-i-duplicate-sys-stdout-to-a-log-file-in-python
class tee():
''' Tees stdout to both a log file and the terminal.
if append is True (default), appends to existing file
if stderr is True (default), tees stederr to same file
Usage:
t = tee("filename.txt")
...
print(1, 2, 3)
...
t.__del__() # returns sys.stdout to original state
'''
def __init__(self, filepath, append=True, stderr=True):
self.old_stdout = sys.stdout
self.old_stderr = sys.stderr
self.name = filepath
if (not append) or (not os.path.exists(self.name)):
makeEmptyFile(self.name)
sys.stdout = self
if stderr:
sys.stderr = self
def write(self, text):
self.old_stdout.write(text)
# open file, write, then close it again (slow, but safe - permits other processes to write to same file)
with open(self.name, "a", encoding="utf-8") as f:
f.write(text)
def flush(self):
pass
def stop(self):
sys.stdout = self.old_stdout
sys.stdout = self.old_stderr
self.name = None
def __del__(self):
self.stop()
这里的危险在于设置sys.stdout=sys.old\u stdout
会阻止代码在本地替换上获得新句柄,但不会阻止任何旧句柄工作
作为一个人为的例子:
class MyThread(threading.Thread):
def __init__(self, log_dest=sys.stdout):
self.log_dest = log_dest
def run(self):
# ...do something-or-other, and occasionally...
self.log_dest.write('Hey, something happened')
由于MyThread初始化时,log\u dest
会被分配一个值,因此将sys.stdout
更改回其旧值并不能阻止它继续尝试使用您现在已失效的对象。@CharlesDuffy但是self.name=None
仅在sys.stdout=self.old\u stdout
之后发生,它恢复标准输出以运行旧代码。在那之后,我的write方法就不应该被调用了。(除非我非常困惑)啊,明白了。问题是,sys.stdout=self.old\u stdout
仅适用于每次要执行写入操作时都要通过sys
模块的代码。假设您有一个以类似于类MyThread(threading.thread):def\u init(self,log\u dest=sys.stdout,…)的初始值设定项启动的线程
——对于任何已启动的线程副本,log\u dest
不会神奇地变回。这只是一个示例,旨在演示在更改sys模块的引用后,假设没有剩余句柄是不安全的。@CharlesDuffy Ya,可能就是这样。有道理。我会在心里测试一个mod,如果它有效的话,你应该给出一个答案。是的,就是这样。如果self.name为None,将write方法更改为只执行print(text)
,似乎可以解决这个问题。要让它可靠地工作,这是一件棘手的事情。