To prawda, większość języków programowania sprawia, że kolejność parametrów jest częścią kontraktu wywołania funkcji, ale nie musi tak być. Dlaczego miałoby to robić? Rozumiem zatem, czy Python różni się pod tym względem od innych języków programowania. Oprócz innych dobrych odpowiedzi dotyczących języka Python 2, weź pod uwagę następujące kwestie:
__named_only_start = object()
def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1):
if _p is not __named_only_start:
raise TypeError("info() takes at most 3 positional arguments")
return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse)
Jedynym sposobem, w jaki wywołujący mógłby podać argumenty spacing
i collapse
pozycjonować (bez wyjątku), byłoby:
info(arg1, arg2, arg3, module.__named_only_start, 11, 2)
Konwencja nie używania prywatnych elementów należących do innych modułów jest już bardzo podstawowa w Pythonie. Podobnie jak w przypadku samego Pythona, ta konwencja parametrów byłaby tylko częściowo wymuszona.
W przeciwnym razie wezwania musiałyby mieć postać:
info(arg1, arg2, arg3, spacing=11, collapse=2)
Wezwanie
info(arg1, arg2, arg3, 11, 2)
przypisze parametrowi wartość 11 _p
i wyjątek podniesiony przez pierwszą instrukcję funkcji.
Charakterystyka:
- Parametry przed
_p=__named_only_start
są dopuszczane pozycyjnie (lub według nazwy).
- Parametry po
_p=__named_only_start
muszą być podane tylko z nazwy (chyba że __named_only_start
uzyskano i wykorzystano wiedzę o specjalnym obiekcie wartowniczym ).
Plusy:
- Parametry są jednoznaczne co do liczby i znaczenia (oczywiście później, jeśli wybrano również dobre nazwy).
- Jeśli wartownik jest określony jako pierwszy parametr, wszystkie argumenty muszą być określone według nazwy.
- Podczas wywoływania funkcji można przełączyć się do trybu pozycyjnego przy użyciu obiektu wartownika
__named_only_start
w odpowiedniej pozycji.
- Można oczekiwać lepszej wydajności niż inne alternatywy.
Cons:
Sprawdzanie odbywa się w czasie wykonywania, a nie w czasie kompilacji.
- Użycie dodatkowego parametru (choć nie argumentu) i dodatkowej kontroli. Niewielkie pogorszenie wydajności w stosunku do zwykłych funkcji.
- Funkcjonalność to hack bez bezpośredniego wsparcia ze strony języka (patrz uwaga poniżej).
- Wywołując funkcję, można przejść do trybu pozycyjnego, używając obiektu wartownika
__named_only_start
w odpowiedniej pozycji. Tak, to również może być postrzegane jako profesjonalista.
Pamiętaj, że ta odpowiedź dotyczy tylko Pythona 2. Python 3 implementuje podobny, ale bardzo elegancki, obsługiwany przez język mechanizm opisany w innych odpowiedziach.
Odkryłem, że kiedy otwieram umysł i myślę o tym, żadne pytanie ani decyzja innej osoby nie wydaje się głupia, głupia lub po prostu głupia. Wręcz przeciwnie: zazwyczaj dużo się uczę.
_named_only_start
, niemożliwe będzie odwołanie się do niej z modułu zewnętrznego, który usuwa zalety i wady. (pojedyncze wiodące podkreślenia w zakresie modułu są prywatne, IIRC)__named_only_start
i anamed_only_start
(bez początkowego podkreślenia), drugie oznaczające, że nazwany tryb jest „zalecany”, ale nie do poziomu „aktywnego promowania” (ponieważ jeden jest publiczny, a inne nie). Jeśli chodzi o „prywatność”_names
rozpoczynania od podkreślenia, nie jest ona zbyt silnie wymuszana przez język: można ją łatwo obejść, używając określonych (innych niż *) importu lub nazw kwalifikowanych. Z tego powodu kilka dokumentów Pythona woli używać terminu „niepubliczny” zamiast „prywatny”.Możesz to zrobić w sposób, który działa zarówno w Pythonie 2, jak i Pythonie 3 , tworząc „fałszywy” argument pierwszego słowa kluczowego z wartością domyślną, która nie pojawi się „naturalnie”. Ten argument słowa kluczowego może być poprzedzony jednym lub większą liczbą argumentów bez wartości:
Pozwoli to na:
ale nie:
Jeśli zmienisz funkcję na:
wtedy wszystkie argumenty muszą mieć słowa kluczowe i
info(odbchelper)
nie będą już działać.Umożliwi to umieszczenie dodatkowych argumentów słów kluczowych w dowolnym miejscu po
_kw
, bez konieczności umieszczania ich po ostatnim wpisie. Często ma to sens, np. Logiczne grupowanie rzeczy lub alfabetyczne układanie słów kluczowych może pomóc w utrzymaniu i rozwoju.Nie ma więc potrzeby powracania do używania
def(**kwargs)
i utraty informacji o podpisie w inteligentnym edytorze. Twoja umowa społeczna ma na celu dostarczenie pewnych informacji, zmuszając (niektóre z nich) do wymagania słów kluczowych, kolejność, w jakiej są one przedstawiane, stała się nieistotna.źródło
Aktualizacja:
Zdałem sobie sprawę, że użycie
**kwargs
nie rozwiąże problemu. Jeśli twoi programiści zmieniają argumenty funkcji według własnego uznania, można na przykład zmienić funkcję na następującą:a stary kod znowu by się zepsuł (ponieważ teraz każde wywołanie funkcji musi zawierać pierwszy argument).
To naprawdę sprowadza się do tego, co mówi Bryan.
Ogólnie przy zmianie funkcji nowe argumenty powinny zawsze kończyć się na końcu. W przeciwnym razie łamie kod. Powinno być oczywiste.
Jeśli ktoś zmieni funkcję tak, że kod się zepsuje, to ta zmiana musi zostać odrzucona.
(Jak mówi Bryan, to jest jak umowa)
Patrząc na podpis funkcji (tj.
def info(object, spacing=10, collapse=1)
) Od razu widać, że każdy argument, który nie ma wartości domyślnej, jest obowiązkowy.Po co ten argument powinien znaleźć się w dokumentacji.
Stara odpowiedź (zachowana dla kompletności) :
To prawdopodobnie nie jest dobre rozwiązanie:Możesz zdefiniować funkcje w ten sposób:
kwargs
to słownik zawierający dowolny argument ze słowa kluczowego. Możesz sprawdzić, czy obecny jest obowiązkowy argument, a jeśli nie, zgłosić wyjątek.Wadą jest to, że może nie być już tak oczywiste, które argumenty są możliwe, ale przy odpowiednim dokumencie powinno być dobrze.
źródło
Argumenty (
*
) zawierające tylko słowa kluczowe python3 można symulować w python2.x za pomocą**kwargs
Rozważmy następujący kod python3:
i jego zachowanie:
To może być symulowane przy użyciu następujących, uwaga Wziąłem wolność przełączania
TypeError
sięKeyError
w „wymagane nazwany argument” sprawy, to nie byłoby zbyt wiele pracy, aby to tego samego typu, a także wyjątkówI zachowanie:
Przepis działa równie dobrze w python3.x, ale należy go unikać, jeśli jesteś tylko python3.x
źródło
kwargs.pop('foo')
jest idiomem Pythona 2? Muszę zaktualizować mój styl kodowania. Nadal stosowałem to podejście w Pythonie 3 🤔Możesz zadeklarować swoje funkcje jako
**args
tylko odbierające . Wymagałoby to stosowania argumentów słów kluczowych, ale wymagałoby to dodatkowej pracy, aby upewnić się, że przekazywane są tylko prawidłowe nazwy.źródło
foo(**kwargs)
. Co mam w tym przekazać?foo(killme=True, when="rightnowplease")
dict
.Jak mówią inne odpowiedzi, zmiana sygnatur funkcji to zły pomysł. Albo dodaj nowe parametry na końcu, albo napraw każdego wywołującego, jeśli zostaną wstawione argumenty.
Jeśli nadal chcesz to zrobić, użyj dekoratora funkcji i funkcji inspect.getargspec . Byłoby użyte coś takiego:
Wykonanie
require_named_args
pozostawiono czytelnikowi jako ćwiczenie.Nie zawracałbym sobie głowy. Będzie to powolne za każdym razem, gdy wywoływana jest funkcja, a dokładniejsze pisanie kodu przyniesie lepsze wyniki.
źródło
Możesz użyć
**
operatora:w ten sposób ludzie są zmuszeni do używania nazwanych parametrów.
źródło
w Pythonie, jeśli używasz * args, co oznacza, że możesz przekazać n-liczbę argumentów dla tego parametru - która będzie listą wewnątrz funkcji do uzyskania dostępu
a jeśli używasz ** kw, oznacza to, że jego argumenty słów kluczowych mogą być dostępne jako dict - możesz przekazać n-liczbę argumentów kw, a jeśli chcesz ograniczyć tego użytkownika, musisz wprowadzić sekwencję i argumenty w kolejności, a następnie nie używaj * i ** - (jest to pythonowy sposób dostarczania ogólnych rozwiązań dla dużych architektur ...)
jeśli chcesz ograniczyć swoją funkcję wartościami domyślnymi, możesz sprawdzić w niej
źródło
Nie rozumiem, dlaczego programista w pierwszej kolejności dodaje parametr między dwoma innymi.
Jeśli chcesz, aby parametry funkcji były używane z nazwami (np
info(spacing=15, object=odbchelper)
), Nie powinno mieć znaczenia, w jakiej kolejności są zdefiniowane, więc równie dobrze możesz umieścić nowe parametry na końcu.Jeśli chcesz, aby kolejność miała znaczenie, nie możesz oczekiwać, że cokolwiek zadziała, jeśli je zmienisz!
źródło