Python2 file派生类移植至Python3的问题咨询
解决Python2到Python3的myfile类移植问题
嘿,我帮你搞定这个移植问题!首先得搞清楚:Python3里的io.FileIO是底层的文件描述符操作类,它确实不支持buffering参数——这个参数是上层缓冲类(比如io.BufferedReader、io.TextIOWrapper)才会处理的,而io.FileIO只负责原始字节的读写,所以直接继承它肯定会报错。
而且你提到的继承open是行不通的,因为open是个工厂函数,不是类,没法直接继承。不过我们可以用「组合替代继承」的思路,完美解决这个问题,还能保留原来的所有用法。
最优解决方案:包装open创建的文件对象
我们可以创建一个包装器类,内部调用Python3标准的open函数(它会自动处理buffering、mode等参数,返回合适的文件对象),然后代理原文件对象的所有方法,只重写read方法来返回create_string_buffer的结果。代码如下:
import ctypes import io class myfile: """Wrapper for file object whose read member returns a string buffer""" def __init__(self, name, mode='r', buffering=-1, *args, **kwargs): # 用标准open创建文件对象,自动处理buffering和mode self._file = open(name, mode, buffering=buffering, *args, **kwargs) # 代理原文件对象的所有属性和方法(除了我们要重写的read) self.__dict__.update(self._file.__dict__) def read(self, size=-1): # 读取原始数据 data = self._file.read(size) # 兼容文本模式:如果返回的是字符串,转成字节(和Python2的file.read行为对齐) if isinstance(data, str): data = data.encode() # 返回ctypes字符串缓冲区 return ctypes.create_string_buffer(data) # 支持上下文管理器(with语句) def __enter__(self): self._file.__enter__() return self def __exit__(self, exc_type, exc_val, exc_tb): return self._file.__exit__(exc_type, exc_val, exc_tb)
为什么这个方案好用?
- 完全支持
buffering参数:因为我们直接用了Python3的open函数,它会根据你传入的参数自动选择缓冲策略(比如buffering=1是行缓冲,buffering=-1用系统默认缓冲大小)。 - 保留所有原文件方法:通过
self.__dict__.update把原文件对象的方法(比如seek、write、close等)都代理过来,你原来的代码:
完全不用修改就能正常运行。self._file = myfile(name, mode, buffering) self._file.seek(self.si*self.blocksize) - 兼容文本/二进制模式:自动处理文本模式返回的字符串,转成字节后再传给
create_string_buffer,和Python2的file类行为保持一致。 - 支持上下文管理器:可以用
with myfile(...) as f:的写法,更符合Python3的最佳实践。
为什么不建议用PyFile_FromFd?
你提到的PyFile_FromFd是Python的C API函数,Python层面几乎用不到它,而且它需要先拿到文件描述符,还要手动处理缓冲、编码等细节,很容易出现行为不一致的问题,完全没必要走这条路。
用上面的包装器方案,既简单又能完美匹配你原来的需求,还符合Python3的生态规范。
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

