Как добавить параметр по умолчанию к функциям при использовании подсказки типа?

Если у меня есть такая функция:

def foo(name, opts={}):
  pass

И я хочу добавить подсказки типа к параметрам, как мне это сделать? То, как я предполагал, дает мне синтаксическую ошибку:

def foo(name: str, opts={}: dict) -> str:
  pass

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

def foo(name: str, opts: dict={}) -> str:
  pass

Я ничего не могу найти в typing документации или в поиске Google.

Изменить: я не знал, как аргументы по умолчанию работают в Python, но ради этого вопроса я сохраню приведенные выше примеры. В общем, гораздо лучше сделать следующее:

def foo(name: str, opts: dict=None) -> str:
  if not opts:
    opts={}
  pass

person josh    schedule 02.08.2016    source источник
comment
Последняя функция - правильный путь. Точно так же scala язык делает это.   -  person Israel Unterman    schedule 02.08.2016
comment
у вас есть изменяемый тип по умолчанию - это приведет к проблемам   -  person noɥʇʎԀʎzɐɹƆ    schedule 02.08.2016
comment
см. мой ответ на обновление, @josh   -  person noɥʇʎԀʎzɐɹƆ    schedule 02.08.2016
comment
@ noɥʇʎԀʎzɐɹƆ Нет, если вы не используете его, например мемоизация. :П   -  person Mateen Ulhaq    schedule 27.09.2018


Ответы (3)


Ваш второй способ верен.

def foo(opts: dict = {}):
    pass

print(foo.__annotations__)

это выводит

{'opts': <class 'dict'>}

Это правда, что это не указано в PEP 484, но подсказки типов являются приложением аннотаций функций, которые документированы в PEP 3107. Раздел синтаксиса поясняет, что аргументы ключевых слов работают с аннотациями функций в этом случае.

Я настоятельно не рекомендую использовать изменяемые аргументы ключевого слова. Дополнительную информацию см. здесь.

person noɥʇʎԀʎzɐɹƆ    schedule 02.08.2016
comment
См. legacy.python.org/dev/peps/pep-3107/#syntax. Подсказка типов - это просто применение аннотаций функций. - person chepner; 02.08.2016
comment
@chepner правда. не знал, что в PEP 3107 есть что-то об аргументах ключевых слов. - person noɥʇʎԀʎzɐɹƆ; 02.08.2016
comment
Вау, я не знал об изменяемых аргументах по умолчанию в Python ... особенно из Javascript / Ruby, где аргументы по умолчанию работают по-другому. Не собираюсь перефразировать то, что уже было сказано до тошноты по этому поводу, ТАК, я просто рад, что узнал об этом до того, как это меня укусило. Спасибо! - person josh; 02.08.2016
comment
Мне всегда советовали использовать None вместо изменяемого типа, такого как {} или [], или объекта по умолчанию, поскольку изменения этого объекта без глубокой копии будут сохраняться между итерациями. - person MrMesees; 25.10.2018
comment
определите достаточное количество функций с изменяемыми ключевыми аргументами, и это только вопрос времени, когда вы обнаружите, что оглядывались на 4-часовой сеанс отладки, ставя под сомнение свой жизненный выбор - person Joseph Sheedy; 10.06.2019
comment
Разве не должно быть пробелов вокруг = в dict = {}, как будто это соглашение для аргументов ключевого слова без подсказки типа? - person actual_panda; 24.03.2020

Если вы используете ввод (введенный в Python 3.5), вы можете использовать typing.Optional, где Optional[X] эквивалентно Union[X, None]. Он используется для обозначения того, что явное значение None разрешено. Из typing.Optional:

def foo(arg: Optional[int] = None) -> None:
    ...
person Tomasz Bartkowiak    schedule 19.06.2019
comment
Разве не должно быть пробелов вокруг = в Optional[int] = None, как будто это соглашение для аргументов ключевого слова без подсказки типа? - person actual_panda; 24.03.2020
comment
@actual_panda, ответ правильный. стиль отличается, когда есть подсказки типа. есть примеры в PEP 484 - person joel; 03.07.2020

Я недавно видел этот однострочный:

def foo(name: str, opts: dict=None) -> str:
    opts = {} if not opts else opts
    pass
person Kirkalicious    schedule 05.06.2019
comment
Привет, @Kirkalicious, спасибо за ответ. Не могли бы вы объяснить, как это работает? - person Nathan; 06.06.2019
comment
Пустой dict, переданный в качестве параметра по умолчанию, является одним и тем же dict для каждого вызова. Поэтому, если функция изменяет его, то в следующий раз по умолчанию будет измененное значение из прошлого раза. Установка None по умолчанию с последующей проверкой внутри метода позволяет избежать этой проблемы, выделяя новый dict каждый раз при вызове метода. - person Ian Goldby; 21.06.2019
comment
Можете ли вы обновить свой ответ (без Edit :, Update: , или похожие)? Комментарии могут исчезнуть в любой момент. - person Peter Mortensen; 14.07.2020
comment
Как насчет opts = opts or {} - person run_the_race; 19.09.2020
comment
Одна проблема с этим - если opts является изменяемым параметром, в котором вызывающие абоненты захотят видеть измененные значения, он потерпит неудачу при передаче {}. Вероятно, безопаснее придерживаться традиционного двухстрочного if opts is None: opts = {}. Если вам нужен однострочный текст, я бы предпочел opts = {} if opts is None else opts. - person Gavin S. Yancey; 22.07.2021