pexpect.interact()报TypeError及重复输出问题求助
解决pexpect执行npm login时的两个常见问题
问题1:设置encoding='utf-8'和logfile_read=sys.stdout后,interact()触发TypeError
修复方案
自定义一个兼容文本(str)和字节(bytes)的写入类,替换直接使用sys.stdout作为logfile_read。这个类会自动判断输入数据类型,调用对应流的写入方法:
import sys import pexpect class UniversalWriter: def __init__(self, stream): self.stream = stream def write(self, data): if isinstance(data, bytes): self.stream.buffer.write(data) else: self.stream.write(data) self.stream.flush() # 确保内容立即输出 # 初始化子进程并应用自定义Writer child = pexpect.spawn('npm login', encoding='utf-8') child.logfile_read = UniversalWriter(sys.stdout) child.interact()
原理:当设置encoding='utf-8'时,pexpect会将子进程输出解码为字符串,但interact()内部可能仍会传递部分字节流数据。自定义类通过适配两种数据类型,避免了文本流(sys.stdout)写入字节的类型错误。
问题2:不设置encoding、用sys.stdout.buffer作为logfile_read时,interact()后消息重复输出
修复方案
重复输出的原因是interact()会默认将子进程输出打印到终端,同时logfile_read又会把相同内容写入stdout,导致重复。解决方式是在调用interact()前临时关闭logfile_read:
import sys import pexpect child = pexpect.spawn('npm login') # 非交互阶段用logfile_read记录输出 child.logfile_read = sys.stdout.buffer # (可选)自动处理npm login的前置步骤,比如输入用户名、密码 # child.expect('Username:') # child.sendline('your_username') # child.expect('Password:') # child.sendline('your_password') # 进入交互模式前关闭logfile_read,避免重复输出 child.logfile_read = None child.interact() # 若交互结束后需要继续记录,可重新开启logfile_read # child.logfile_read = sys.stdout.buffer
如果需要在交互期间同时记录日志但不重复输出,可以将logfile_read指向文件而非stdout:
# 日志写入文件,终端只显示interact的交互内容 with open('npm_login.log', 'wb') as f: child.logfile_read = f child.interact()
内容的提问来源于stack exchange,提问作者Qiulang
相关产品推荐
相关产品推荐

