Печатание утки и использование hasattr
Я видел много раз что-то вроде:
def parse(text):
if hasattr(text, 'read'):
text = text.read()
# Parse the text here...
но если я передам экземпляр следующего класса, он обязательно потерпит неудачу:
class X(object):
def __init__(self):
self.read = 10
Мой вопрос: какой самый питонический способ справиться с этим?
Я думал о двух основных способах:
if hasattr(text, 'read') and callable(text.read):
text = text.read()
а также
try:
text = text.read()
except ...
2 ответа
Питонический способ вообще не проверяет тип объекта. С одной стороны, язык достаточно сложен, так что вам будет трудно убедиться, что вы не включите какие-либо объекты, которые в любом случае позже потерпят неудачу (очевидный пример из вашего поста: вы не проверяете, принимает ли функция 0 аргументов, даже не подумайте о типе возврата), и, что еще хуже, вы можете легко исключить допустимый код по ошибке.
Гораздо лучше просто предположить, что входные значения будут в порядке и позже потерпят неудачу, если окажется, что это не так.
На самом деле есть только одно исключение: скажем, у вас разные пути кода для разных типов (скажем, строк / списков), в этом случае вам нужно проверить тип, чтобы решить, какой путь выбрать. Но опять же: попробуйте самую общую проверку, которая будет работать для вас (т.е. не проверяйте isinstance(l, list)
если isinstance(l, collections.Iterable)
также сделал бы работу). Если позже выясняется, что "строка" не была достаточно жесткой, вы всегда можете потерпеть неудачу.
Питонический путь заключается в предположении text
любого типа, который подходит. Использовать только try-except
/ hasattr
если ты это знаешь text
будут совершенно разные вещи в разное время
Другими словами, не проверяйте. Использовать только if
если вы собираетесь else
, а также try
если вы действительно хотите особую обработку в except
,