Добавление значения параметра по умолчанию с подсказкой типа в Python

236

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

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
мистифицировать
источник
4
Последняя функция - правильный путь. То же самое scalaделает язык.
Израиль Унтерман
14
у вас есть изменяемый тип по умолчанию - это приведет к проблемам
noɥʇʎԀʎzɐɹƆ
см. мой обновленный ответ, @josh
noɥʇʎԀʎzɐɹƆ
@ noɥʇʎԀʎzɐɹƆ Нет, если вы не используете его, например, для запоминания. : P
Mateen Ulhaq

Ответы:

281

Ваш второй путь правильный.

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

print(foo.__annotations__)

это выводы

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

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

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

noɥʇʎԀʎzɐɹƆ
источник
1
См. Legacy.python.org/dev/peps/pep-3107/#syntax . Подсказка типов - это просто применение аннотаций функций.
chepner
@chepner верно. не знал, что у PEP 3107 было что-то об аргументах ключевых слов.
noɥʇʎԀʎzɐɹƆ
2
Ого, я не знал об изменяемых аргументах по умолчанию в Python ... особенно из Javascript / Ruby, где аргументы по умолчанию работают по-разному. Не буду перефразировать то, что уже было сказано до тошноты вокруг ТАК об этом, я просто рад, что узнал об этом до того, как он укусил меня. Спасибо!
Джош
6
Мне всегда советовали использовать None, а не изменяемый тип, такой как {} или [] или объект по умолчанию, поскольку мутации этого объекта без глубокой копии будут сохраняться между итерациями.
MrMesees
2
определите достаточное количество функций с изменяемыми аргументами ключевых слов, и это всего лишь вопрос времени, когда вы
Джозеф Шиди
20

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

def foo(arg: Optional[int] = None) -> None:
    ...
Томаш Бартковяк
источник
2
Не должны там быть не пробелы вокруг =в , Optional[int] = Noneкак это соглашение для именованных аргументов нетиповых-намекали?
актуальная_панда
7

Я недавно видел эту однострочную:

def foo(name: str, opts: dict=None) -> str:
    opts = {} if not opts else opts
    pass
Kirkalicious
источник
Привет @Kirkalicious, спасибо за ваш ответ. Не могли бы вы объяснить, как это работает?
Натан,
1
Пустой dict, передаваемый в качестве параметра по умолчанию, является тем же dict для каждого вызова. Так что, если функция изменяет его, то по умолчанию в следующий раз будет измененное значение с прошлого раза. Установка Noneзначения по умолчанию и последующая проверка внутри метода позволяет избежать этой проблемы, выделяя новый dict при каждом вызове метода.
Ян Голдби