Как создать экземпляр объекта io.TextIOWrapper с атрибутом name? - PullRequest
1 голос
/ 10 марта 2020
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 является атрибутом _io.TextIOWrapper экземпляр, представляющий sys.stdin. А из документации на 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.

В идеале, я также хотел бы иметь возможность поддерживать атрибут mode, который, казалось бы, доступен в экземпляре sys.stdin в экземпляр io.TextIOWrapper, созданный вручную, а также. А также для sys.stdout эквивалента, который, как я предполагаю, будет таким же, за исключением того, что name должен быть просто установлен в '<stdout>' и mode в 'w'.

1 Ответ

1 голос
/ 10 марта 2020

Вы можете переопределить метод __getattribute__ на метод, который возвращает ключ name в словаре атрибутов объекта при запросе атрибута name:

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>
...