Pythonic способ сравнить ненадежные простые аргументы

Я понимаю основную философию: не проси разрешения, просто сделай это и попроси прощения. Например, это не обязательно должен быть файл для метода.read(), вы поблагодарите себя позже, когда обнаружите, что все "просто работает", когда вы хотите прочитать файлоподобный объект. Тем не менее, мне легче разобраться со сложными объектами, такими как файлы, чем с простыми объектами, такими как числа.

Поэтому я пытаюсь написать очень простой класс. Детали не имеют значения, но у них есть внутренний счетчик, и он должен что-то делать, когда счетчик превышает предел. Предел предоставляется в качестве аргумента при создании объекта.

Сейчас я думаю об оборонительном программировании. Очевидно, я хотел бы, чтобы мой предел был целым числом или хотя бы чем-то, что сравнивается как целое число. Это может быть слабее, потому что тест>=, который я делаю, все равно будет обеспечивать правильное поведение, если он является float.

Хотя пользователь класса будет знать, что этот аргумент должен быть целым числом, я бы хотел, чтобы объект делал что-то неудивительное, если это не так. Моей первой мыслью было проверить, что у меня на самом деле был номер

if isinstance(limit,(int,long,float)):

но здесь есть множество ответов "не тестируйте, попробуйте кроме", так что я знаю, что это не пифонично. Лучше использовать лимит и дождаться исключения. Так что я попробовал это внутри попытки: за исключением различных типов ограничений

if counter >= limit:

Это работает нормально, как и ожидалось, если лимит является int или float. Затем я установил ограничение на строку или кортеж, для которых объекты сравниваются с числом, не имеет никакого очевидного или разумного определения, и ждал, чтобы поймать исключение. Но он выполняется, возвращает логическое значение и хранит молчание.

Так что я RTFM, и получается, что сравнение не вызывает исключения для смешанных типов, что-то связанное с операцией "x in container", для которой равенство проверяется на произвольных типах. Он всегда возвращает not_equal для разных типов, но сравнение величин, хотя и непротиворечиво, является произвольным. Возможно, я мог бы использовать его, если сравнение величин смешанного типа всегда возвращало False, но оно также с радостью вернет True.

Если я пытаюсь использовать другое целочисленное поведение для нечисловых чисел, я получаю ожидаемое исключение, например, эта строка + число выбрасывает TypeError

limit+0

Так что я могу сказать

if counter >= (limit+0)

и это выдает желаемое исключение, если предел - это что-то кроме числа. Но это кажется почти запутанным. Я делаю что-то лишнее с выражением, чтобы провести тест типа у задней двери. Любой оптимизатор кода или другой редактор удалил бы явно избыточную арифметическую операцию. Это все равно, что видеть, весит ли объект столько же, сколько утка, чтобы увидеть, сделан ли он из дерева, и поэтому может быть сожжен как ведьма (своего рода).

Более ясная возможность

if counter >= int(limit)

в котором, по крайней мере, есть некоторые объяснения. Это не совсем то, что я хотел бы при любых обстоятельствах, но на данный момент этого достаточно, и это никого не удивит.

Так что WWGD? Какой питонный способ безопасно использовать ненадежный аргумент, когда все, что вы хотите сделать, это сравнить его по величине?

1 ответ

Если вы действительно хотите убедиться, что аргумент имеет подходящий числовой тип, то проверьте, является ли он экземпляром соответствующего числового абстрактного базового класса, возможно:

    import numbers
    ...
    if not isinstance(limit, numbers.Real):
        ... # react to the bad argument type

Предположительно в этом случае вы бросите TypeError исключение.

Делай это в своем классе __init__ метод так, чтобы проблема была обнаружена и сообщена как можно ближе к исходной ошибке звонящего. Это гораздо приятнее, чем ждать какое-то неопределенное количество времени и, в конечном итоге, взорваться, когда программа приступит к игре со счетчиком, и в этом случае отслеживание исключений будет гораздо менее полезно для определения происхождения проблемы.

Если вы чувствуете себя параноиком, вы можете также проверить в конструкторе, что значение этого аргумента больше нуля, и бросить ValueError исключение, если это не так.

Другие вопросы по тегам