Как выполнять различные действия в зависимости от типа параметра

В языках, которые используют статическое связывание, таких как Java, вы можете определить несколько функций, имеющих одинаковое имя, но разные параметры. Изучая Python, до сих пор я рассматривал отсутствие этого в основном как "проблему безопасности" (например, bool_parameter="False" может быть истолковано как True из-за цитат). Я думал, что мне просто нужно быть более осторожным.

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

var = ((1, "foo"), (2, "bar"), (3, "potato"))

Чтобы удалить элемент из var со статическим связыванием можно сделать что-то вроде этого (псевдокод:

def del_item(int i):
    # search item with (x == i, *)
    # remove this item

def del_item(String s):
    # search item with (*, x == s)
    # remove this item

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

Пытаясь справиться с подобной ситуацией в Python, я нахожу только неудобные решения, такие как некоторые if-предложения, которые проверяют тип.

Есть ли способ лучше?

4 ответа

Решение

В Python нет перегрузки методов, поэтому вам придется проверить тип аргумента извините.

def del_item(item):
    if type(item) is int:
        # search item with (x == item, *)
        # remove this item
    elif type(item) is str:
        # search item with (*, x == s)
        # remove this item
    else:
        # Maybe raise an exception?

Проверьте этот вопрос: Различия между isinstance() и type() в Python

Если вы в конечном итоге делаете предложенный подход типа "тип", вы можете рассмотреть альтернативные варианты типа "утка" или isinstance.

Ваша проблема может быть решена с помощью универсальных методов / функций. Они не встроены в Python, но могут быть добавлены сторонней библиотекой, или вы сами пишете.

Я счастливо работал с правилами PEAK несколько лет назад, но, хотя они все еще должны работать, похоже, они немного потеряли популярность.

Новый PEP 443 (отправка с одним аргументом) сопровождается внешней реализацией, singledispatch. https://pypi.python.org/pypi/singledispatch/3.4.0.3

С этим ваша проблема может быть решена так:

 from functools import partial
 from singledispatch import singledispatch


 var = ((1, "foo"), (2, "bar"), (3, "potato"))


 @singledispatch
 def del_predicate(value):
     pass


 @del_predicate.register(int)
 def _(v, candidate):
     return v == candidate[0]

 @del_predicate.register(str)
 def _(v, candidate):
     return v == candidate[1]


 def neg(f):
     def _f(*args):
         return not f(*args)
     return _f

 print filter(neg(partial(del_predicate, "foo")), var)
 print filter(neg(partial(del_predicate, 2)), var)

Конкретный случай, который вы приводите, выглядит так, как будто перегрузка не нужна.

def del_item(id):
    return tuple(item for item in var if not id in item)

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

def del_item(string_id=None, number_id=None):
    if string_id is not None:
        return tuple(item for item in var if not item[1] == string_id)
    return tuple(item for item in var if not item[0] == number_id)

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

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