如何用 name 属性实例化一个 io.TextIOWrapper 对象?

How to instantiate an io.TextIOWrapper object with a name attribute?

import sys

print(sys.stdin)
print(type(sys.stdin))
print(sys.stdin.name)
print(sys.stdin.__dict__)

以上执行后,输出结果如下:

<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
<class '_io.TextIOWrapper'>
<stdin>
{'mode': 'r'}

所以从上面的代码片段和输出中,我可以看到 name 是表示 sys.stdin_io.TextIOWrapper 实例的一个属性。从 io.TextIOWrapper 上的文档(例如,通过 $ pydoc io.TextIOWrapper),它确实将 name 列为数据描述符。但是,无论出于何种原因,name 都没有在其 __dict__.

中显示为项目

当我手动创建 io.TextIOWrapper 的实例时使用例如:

import io

a = io.TextIOWrapper(io.BytesIO())
print(a)
a.name

<_io.TextIOWrapper encoding='UTF-8'> 被打印出来。但是 a.name 行抛出错误:AttributeError: '_io.BytesIO' object has no attribute 'name'AttributeError 是我预料的,没想到它说是一个 _io.BytesIO 对象。

然后我尝试创建一个子类并手动附加一个 name 属性,如下所示:

import io


class NamedTextIOWrapper(io.TextIOWrapper):

    def __init__(self, buffer, name=None, **kwargs):
        self.name = name
        io.TextIOWrapper.__init__(self, buffer, **kwargs)


input = io.BytesIO('abc')
stdin = NamedTextIOWrapper(input, name='<stdin>', encoding='utf-8')

print(stdin.name)

然而这会遇到:AttributeError: attribute 'name' of '_io.TextIOWrapper' objects is not writable.

理想情况下,我还希望能够在手动实例化的 io.TextIOWrapper 对象中维护 sys.stdin 实例中看似可用的 mode 属性。并且对于 sys.stdout 等价物,我认为除了 name 应该设置为 '<stdout>'mode 应该设置为 'w' 之外,它们是一样的。

当请求 name 属性时,您可以使用 returns 对象属性字典的 name 键覆盖 __getattribute__ 方法:

class NamedTextIOWrapper(io.TextIOWrapper):
    def __init__(self, buffer, name=None, **kwargs):
        vars(self)['name'] = name
        super().__init__(buffer, **kwargs)

    def __getattribute__(self, name):
        if name == 'name':
            return vars(self)['name']
        return super().__getattribute__(name)

这样:

input = io.BytesIO(b'abc')
stdin = NamedTextIOWrapper(input, name='<stdin>', encoding='utf-8')
print(stdin.name)

输出:

<stdin>