Dodanie domyślnej wartości parametru z podpowiedzi typu w Pythonie


236

Jeśli mam taką funkcję:

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

I chcę dodać podpowiedzi do parametrów, jak to zrobić? Sposób, w jaki zakładałem, powoduje błąd składniowy:

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

Następujące polecenie nie zgłasza błędu składniowego, ale nie wydaje się intuicyjnym sposobem obsługi tego przypadku:

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

Nic nie mogę znaleźć w typingdokumentacji ani w wyszukiwarce Google.

Edycja: Nie wiedziałem, jak działają domyślne argumenty w Pythonie, ale ze względu na to pytanie zachowam powyższe przykłady. Ogólnie o wiele lepiej jest wykonać następujące czynności:

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

4
Ostatnia funkcja to właściwy sposób. To samo scaladzieje się z językiem.
Israel Unterman

14
masz zmienny typ domyślny - który doprowadzi do problemów
noɥʇʎԀʎzɐɹƆ

zobacz moją odpowiedź na aktualizację, @josh
noɥʇʎԀʎzɐɹƆ

@ noɥʇʎԀʎzɐɹƆ Nie, chyba że używasz go np. do zapamiętywania. : P
Mateen Ulhaq

Odpowiedzi:


281

Twój drugi sposób jest poprawny.

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

print(foo.__annotations__)

to wychodzi

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

To prawda, że ​​nie ma go w PEP 484 , ale podpowiedzi są aplikacjami adnotacji funkcji, które są udokumentowane w PEP 3107. Sekcja składniowa wyjaśnia, że ​​argumenty słów kluczowych działają w ten sposób z adnotacjami funkcji.

Zdecydowanie odradzam stosowanie zmiennych argumentów słów kluczowych. Więcej informacji tutaj .


1
Zobacz legacy.python.org/dev/peps/pep-3107/#syntax . Podpowiedzi typu to po prostu zastosowanie adnotacji funkcji.
chepner

@chepner true. nie wiedziałem, że PEP 3107 ma coś na temat argumentów słów kluczowych.
noɥʇʎԀʎzɐɹƆ

2
Wow, nie wiedziałem o zmiennych domyślnych argumentach w Pythonie ... zwłaszcza pochodzących z Javascript / Ruby, gdzie domyślne argumenty działają inaczej. Nie zamierzam przerabiać tego, co zostało już powiedziane na ten temat w reklamie SO, po prostu cieszę się, że dowiedziałem się o tym, zanim mnie ugryzło. Dzięki!
josh

6
Zawsze radzono mi używać opcji None zamiast zmiennego typu, takiego jak {} lub [], lub domyślnego obiektu, ponieważ mutacje w tym obiekcie bez głębokiej kopii będą się utrzymywać między iteracjami.
MrMesees

2
zdefiniuj wystarczającą liczbę funkcji za pomocą modyfikowalnych argumentów słów kluczowych i to tylko kwestia czasu, zanim spojrzysz wstecz na 4-godzinną sesję debugowania kwestionującą twoje życiowe wybory
Joseph Sheedy

20

Jeśli używasz pisania (wprowadzonego w Pythonie 3.5), możesz użyć typing.Optional, gdzie Optional[X]jest równoważne Union[X, None]. Służy do sygnalizowania, że Nonedozwolona jest jawna wartość parametru . Od pisania. Opcjonalnie :

def foo(arg: Optional[int] = None) -> None:
    ...

2
Czy nie powinno być żadnych białych znaków wokół, jak =w Optional[int] = Nonekonwencji argumentów słów kluczowych bez podpowiedzi?
actual_panda

7

Niedawno widziałem ten jednowarstwowy:

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

Cześć @Kirkalicious, dziękuję za odpowiedź. Czy możesz wyjaśnić, jak to działa?
Nathan

1
Pusty dykt przekazany jako parametr domyślny jest tym samym dykta dla każdego połączenia. Więc jeśli funkcja mutuje to, domyślnym następnym razem będzie zmutowana wartość z ostatniego razu. Ustawienie Nonewartości domyślnej, a następnie sprawdzenie wewnątrz metody pozwala uniknąć tego problemu, przydzielając nowy słownik za każdym razem, gdy metoda jest wywoływana.
Ian Goldby
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.