Czy istnieje sposób przekazania opcjonalnych parametrów do funkcji?

135

Czy w Pythonie jest sposób na przekazanie parametrów opcjonalnych do funkcji podczas jej wywoływania, aw definicji funkcji jest jakiś kod oparty na „tylko jeśli przekazano opcjonalny parametr”

user1795998
źródło

Odpowiedzi:

115

Dokumentacja Pythona 2, 7.6. Definicje funkcji oferują kilka sposobów wykrywania, czy obiekt wywołujący dostarczył opcjonalny parametr.

Po pierwsze, możesz użyć specjalnej formalnej składni parametrów *. Jeśli definicja funkcji ma parametr formalny poprzedzony pojedynczym *, wówczas Python zapełnia ten parametr dowolnymi parametrami pozycyjnymi, które nie są dopasowane przez poprzednie parametry formalne (jako krotka). Jeśli definicja funkcji ma parametr formalny poprzedzony znakiem **, to Python wypełnia ten parametr dowolnymi parametrami słów kluczowych, które nie są dopasowane przez poprzednie parametry formalne (jako dykt). Implementacja funkcji może sprawdzić zawartość tych parametrów pod kątem dowolnych „parametrów opcjonalnych” wybranego rodzaju.

Na przykład, tutaj jest funkcja opt_fun, która przyjmuje dwa parametry pozycyjne x1i x2, i szuka innego parametru kluczowego nazwie „opcjonalne”.

>>> def opt_fun(x1, x2, *positional_parameters, **keyword_parameters):
...     if ('optional' in keyword_parameters):
...         print 'optional parameter found, it is ', keyword_parameters['optional']
...     else:
...         print 'no optional parameter, sorry'
... 
>>> opt_fun(1, 2)
no optional parameter, sorry
>>> opt_fun(1,2, optional="yes")
optional parameter found, it is  yes
>>> opt_fun(1,2, another="yes")
no optional parameter, sorry

Po drugie, możesz podać domyślną wartość parametru o jakiejś wartości, Nonektórej wywołujący nigdy by nie użył. Jeśli parametr ma tę wartość domyślną, wiesz, że obiekt wywołujący nie określił parametru. Jeśli parametr ma wartość inną niż domyślna, wiesz, że pochodzi od wywołującego.

Jim DeLaHunt
źródło
7
positional_parametersjest krotką i keyword_parameterssłownikiem.
Cees Timmerman,
W jaki sposób Python odróżnia formal parameters preceded by * (jak to się nazywa?) Od a keyword parameter? Jak zrozumiałem, parametry słów kluczowych są określane za pomocą =operatora w wywołaniu funkcji (tak więc opt_fun(1,2, optional="yes")zapewnia argument słowa kluczowego „tak” dla funkcji, która przewiduje parametr, ale niekoniecznie go wymaga option).
Minh Tran,
Z drugiej strony rozumiałem formal parameters preceded by * po prostu „argumenty dostarczone przez dzwoniącego, które nie odpowiadają argumentom pozycyjnym, które występują przed jakimikolwiek argumentami słów kluczowych”. Na przykład in opt_fun(1,2, "blah", 3.14, mykey="yes", myyear="2018"), "blah"i 3.14są, forma arguments preceded by *ponieważ znajduje się między dwoma argumentami pozycyjnymi a argumentem używającym =znaku. Powstały krotka positional_parameterbędzie dwudzielny: ("blah", 3.14). Czy to jest poprawne?
Minh Tran,
@MinhTran, pytania w komentarzach nie są najlepszym sposobem na uzyskanie odpowiedzi w Stack Overflow. O wiele lepiej jest kliknąć duży niebieski przycisk „Zadaj pytanie” i napisać swoje żądanie jako „Pytanie”, na które inni mogą „odpowiedzieć”. Ale żeby ci pomóc, a) uwaga, napisałem parameter„nie” parameters„dla„ preceded by *”. Język dopuszcza tylko jeden *identifierna liście parametrów. b) przeczytaj docs.python.org/2/reference/… , c) przeczytaj docs.python.org/2/reference/expressions.html#calls . Przepraszamy, zabrakło znaków dozwolonych w tym komentarzu.
Jim DeLaHunt
82
def my_func(mandatory_arg, optional_arg=100):
    print(mandatory_arg, optional_arg)

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values

Uważam to za bardziej czytelne niż używanie **kwargs.

Aby określić, czy argument został w ogóle przekazany, używam niestandardowego obiektu narzędzia jako wartości domyślnej:

MISSING = object()

def func(arg=MISSING):
    if arg is MISSING:
        ...
warvariuc
źródło
-Dzięki, czy istnieje sposób na określenie wartości domyślnej tego parametru jako kolejnej zmiennej w kodzie?
user1795998
tak. default_value=100; def my_func(mandatory_argument, optional_argument_with_default_value=default_value): ...
warvariuc
Wydaje się, że pokazuje, jak używać parametrów opcjonalnych, ale nie pokazuje, jak sprawdzić, czy jeden z nich został zaliczony, o co prosi OP.
Mawg mówi, że przywróć Monikę
4
W większości przypadków jest to prostsze i prostsze rozwiązanie niż rozwiązanie Jima. Jeśli ustawisz wartość domyślną na Brak, możesz sprawdzić, czy parametr został przekazany, czy nie. Jedynym przypadkiem, w którym rozwiązanie Jima jest lepsze, jest rozróżnienie między przekazaniem None jako argumentu a nieprzekazywaniem argumentu w ogóle.
Arnon Axelrod,
19
def op(a=4,b=6):
    add = a+b
    print add

i)op() [o/p: will be (4+6)=10]
ii)op(99) [o/p: will be (99+6)=105]
iii)op(1,1) [o/p: will be (1+1)=2]
Note:
 If none or one parameter is passed the default passed parameter will be considered for the function. 
Sanyal
źródło
1
Czy istnieje sposób na przekazanie tylko drugiego parametru (b), a nie pierwszego (a)?
Djidiouf
4
@Djidiouf Tak, jestop(b=2)
Jürg Merlin Spaak
7

Jeśli chcesz, podaj jakąś domyślną wartość parametrowi, przypisz wartość w (). jak (x = 10). Ale ważne jest, aby najpierw obowiązkowy argument, a następnie wartość domyślna.

na przykład.

(y, x = 10)

ale

(x = 10, y) jest błędne

sumit
źródło
Dzięki, czy istnieje sposób na określenie domyślnej wartości tego parametru jako kolejnej zmiennej w kodzie?
user1795998
Tak, możesz użyć czegoś, co nazywa się *arg **kargargumentami funkcji. Wyszukaj w google.
sumit
Wydaje się, że pokazuje, jak używać parametrów opcjonalnych, ale nie pokazuje, jak sprawdzić, czy jeden z nich został zaliczony, o co prosi OP.
Mawg mówi, że przywróć Monikę
2

Możesz określić domyślną wartość opcjonalnego argumentu z czymś, co nigdy nie zostałoby przekazane do funkcji i sprawdzić to za pomocą isoperatora:

class _NO_DEFAULT:
    def __repr__(self):return "<no default>"
_NO_DEFAULT = _NO_DEFAULT()

def func(optional= _NO_DEFAULT):
    if optional is _NO_DEFAULT:
        print("the optional argument was not passed")
    else:
        print("the optional argument was:",optional)

wtedy tak długo, jak tego nie zrobisz func(_NO_DEFAULT), możesz dokładnie wykryć, czy argument został przekazany, czy nie, iw przeciwieństwie do zaakceptowanej odpowiedzi nie musisz się martwić o skutki uboczne notacji **:

# these two work the same as using **
func()
func(optional=1)

# the optional argument can be positional or keyword unlike using **
func(1) 

#this correctly raises an error where as it would need to be explicitly checked when using **
func(invalid_arg=7)
Tadhg McDonald-Jensen
źródło
Po prostu zrób _NO_DEFAULT = object().
Aran-Fey
Warto dodać 2 dodatkowe wiersze, aby zapewnić lepszą introspekcję. Dzięki temu, jeśli uruchomisz help(func), uzyskasz jaśniejsze pojęcie, jak argument jest interpretowany, jeśli nie jest jawnie przekazywany.
Tadhg McDonald-Jensen