Python 3: определить, поддерживает ли объект IO - PullRequest
2 голосов
/ 02 мая 2011

Некоторые методы Python работают с различными источниками ввода. Например, метод дерева элементов XML parse принимает объект, который может быть либо строкой (в этом случае API обрабатывает его как имя файла), либо объектом, поддерживающим интерфейс ввода-вывода, например объектом файла или * 1002. *.

Итак, очевидно, что метод parse выполняет какое-то прослушивание интерфейса, чтобы выяснить, какие действия предпринять. Я предполагаю, что самый простой способ добиться этого - проверить, является ли входной параметр строкой, говоря «1006», и, если это так, трактовать его как имя файла, иначе обработать его как объект ввода-вывода.

Но для лучшей проверки ошибок, я думаю, было бы лучше проверить, поддерживает ли x интерфейс IO. Каков стандартный идиоматический способ проверки, поддерживает ли объект указанный интерфейс?

Один из способов, я полагаю, был бы просто сказать:

if "read" in x.__class__.__dict__: # check if object has a read method

Но то, что x имеет метод «чтения», не обязательно означает, что он поддерживает интерфейс ввода-вывода, поэтому я предполагаю, что мне следует также проверить все методы интерфейса ввода-вывода. Это обычно лучший способ сделать это? Или я должен просто забыть о проверке интерфейса и просто позволить обработать AttributeError дальше по стеку?

Ответы [ 3 ]

3 голосов
/ 02 мая 2011

Python настоятельно рекомендует печатать на утках: просто предположите, что переданный объект действителен, и попробуйте его использовать. Таким образом, ваш код будет максимально гибким. Конечно, если действия вашего кода зависят от типа передаваемого объекта, вам нужна какая-то проверка типа. Тем не менее, я рекомендую свести эту проверку к минимуму и перейти на isinstance(x, str).

Если вы передадите объект, который не является ни строкой, ни поддерживает интерфейс ввода-вывода, это приведет к AttributeError. Если это происходит, это ошибка в вызывающем коде. Это исключение нигде не должно обрабатываться - вместо этого должна быть исправлена ​​ошибка!

Тем не менее, вы могли бы использовать

isinstance(x, io.IOBase)

для проверки встроенных классов, поддерживающих протокол ввода / вывода. Это ограничит ваш код классами, которые на самом деле являются производными от io.IOBase - поверхностное и ненужное ограничение.

1 голос
/ 02 мая 2011

Или я должен просто забыть о проверке интерфейса и просто позволить возможной AttributeError получить дальнейшую обработку по стеку?

Общий питонический принцип, кажется, делает все, что выхотите сделать с полученным объектом и просто захватить любое исключение, которое оно может вызвать.Это так называемая утка, набирающая .Это не обязательно означает, что вы должны позволить этим исключениям перейти от вашей функции к вызывающему коду.Вы можете обрабатывать их в самой функции, если она способна сделать это осмысленно.

0 голосов
/ 02 мая 2011

Да, python - это все о типизировании утки, и вполне приемлемо проверить несколько методов, чтобы решить, поддерживает ли объект интерфейс ввода-вывода. Иногда даже имеет смысл просто попытаться вызвать ваши методы в блоке try / Кроме и поймать TypeError или ValueError, чтобы вы знали, поддерживает ли он действительно тот же интерфейс (но используйте это редко). Я бы сказал, что используйте hasattr вместо того, чтобы смотреть на __class__.__dict__, но в противном случае я бы выбрал такой подход.

(В общем, сначала я бы проверил, не существует ли где-нибудь в стандартной библиотеке какого-либо метода для обработки подобных вещей, поскольку он может быть подвержен ошибкам, чтобы самостоятельно определить, что представляет собой «интерфейс ввода-вывода». Например, в модулях types и inspect есть несколько удобных гемов для связанной проверки интерфейса.)

...