Szukaj…


Wprowadzenie

Funkcje w Pythonie zapewniają zorganizowany, wielokrotnego użytku i modułowy kod do wykonywania zestawu określonych akcji. Funkcje upraszczają proces kodowania, zapobiegają redundantnej logice i ułatwiają śledzenie kodu. W tym temacie opisano deklarację i wykorzystanie funkcji w języku Python.

Python ma wiele wbudowanych funkcji, takich jak print() , input() , len() . Oprócz wbudowanych możesz także tworzyć własne funkcje do wykonywania bardziej szczegółowych zadań - są to tak zwane funkcje zdefiniowane przez użytkownika .

Składnia

  • def function_name (arg1, ..., * args argN, kw1, kw2 = domyślne, ..., ** kwargs): Sprawozdania
  • lambda arg1, ... argN, * args, kw1, kw2 = default, ..., ** kwargs : wyrażenie

Parametry

Parametr Detale
arg1 , ..., argN Regularne argumenty
* argumenty Nienazwane argumenty pozycyjne
kw1 , ..., kwN Argumenty zawierające tylko słowa kluczowe
** kwargs Reszta argumentów słów kluczowych

Uwagi

5 podstawowych rzeczy, które możesz zrobić za pomocą funkcji:

  • Przypisz funkcje do zmiennych

    def f():
      print(20)
    y = f
    y()
    # Output: 20
    
  • Zdefiniuj funkcje w ramach innych funkcji ( Funkcje zagnieżdżone )

    def f(a, b, y):
        def inner_add(a, b):      # inner_add is hidden from outer code
            return a + b
        return inner_add(a, b)**y
    
  • Funkcje mogą zwracać inne funkcje

    def f(y):
        def nth_power(x):
            return x ** y
        return nth_power    # returns a function
    
    squareOf = f(2)         # function that returns the square of a number           
    cubeOf = f(3)           # function that returns the cube of a number
    squareOf(3)             # Output: 9
    cubeOf(2)               # Output: 8
    
  • Funkcje mogą być przekazywane jako parametry do innych funkcji

    def a(x, y):
        print(x, y)
    def b(fun, str):        # b has two arguments: a function and a string 
        fun('Hello', str)
    b(a, 'Sophia')           # Output: Hello Sophia
    
  • Funkcje wewnętrzne mają dostęp do obejmującego zakresu ( zamknięcie )

    def outer_fun(name):
        def inner_fun():     # the variable name is available to the inner function
            return "Hello "+ name + "!"
        return inner_fun
    greet = outer_fun("Sophia")
    print(greet())            # Output: Hello Sophia!
    

Dodatkowe zasoby

Definiowanie i wywoływanie prostych funkcji

Użycie instrukcji def jest najczęstszym sposobem definiowania funkcji w pythonie. Ta instrukcja jest tak zwaną instrukcją złożoną z pojedynczą klauzulą o następującej składni:

def function_name(parameters):
    statement(s)

function_name jest znana jako identyfikator funkcji. Ponieważ definicja funkcji jest instrukcją wykonywalną, jej wykonanie wiąże nazwę funkcji z obiektem funkcji, który można później wywołać za pomocą identyfikatora.

parameters to opcjonalna lista identyfikatorów, które zostają powiązane z wartościami podanymi jako argumenty podczas wywoływania funkcji. Funkcja może mieć dowolną liczbę argumentów oddzielonych przecinkami.

statement(s) - zwana także ciałem funkcji - jest niepustą sekwencją instrukcji wykonywanych przy każdym wywołaniu funkcji. Oznacza to, że ciało funkcji nie może być puste, podobnie jak każdy wcięty blok .

Oto przykład prostej definicji funkcji, której celem jest wypisywanie Hello każdym razem, gdy się nazywa:

def greet():
    print("Hello")

Teraz wywołajmy zdefiniowaną funkcję greet() :

greet()
# Out: Hello

To kolejny przykład definicji funkcji, która przyjmuje jeden argument i wyświetla przekazaną wartość przy każdym wywołaniu funkcji:

def greet_two(greeting):
    print(greeting)

Następnie należy greet_two() funkcję greet_two() z argumentem:

greet_two("Howdy")
# Out: Howdy

Możesz także nadać domyślną wartość argumentowi tej funkcji:

def greet_two(greeting="Howdy"):
    print(greeting)

Teraz możesz wywołać funkcję bez podawania wartości:

greet_two()
# Out: Howdy 

Zauważysz, że w przeciwieństwie do wielu innych języków, nie musisz jawnie deklarować typu zwracanego przez funkcję. Funkcje języka Python mogą zwracać wartości dowolnego typu za pomocą słowa kluczowego return . Jedna funkcja może zwrócić dowolną liczbę różnych typów!

def many_types(x):
    if x < 0:
        return "Hello!"
    else:
        return 0

print(many_types(1))
print(many_types(-1))

# Output:
0
Hello!

Dopóki jest to obsługiwane przez program wywołujący, jest to całkowicie poprawny kod Pythona.

Funkcja, która osiągnie koniec wykonywania bez instrukcji return, zawsze zwróci None :

def do_nothing():
    pass

print(do_nothing())
# Out: None

Jak wspomniano wcześniej, definicja funkcji musi mieć treść funkcji, niepustą sekwencję instrukcji. Dlatego instrukcja pass jest używana jako treść funkcji, która jest operacją zerową - kiedy jest wykonywana, nic się nie dzieje. Robi to, co znaczy, przeskakuje. Jest przydatny jako symbol zastępczy, gdy instrukcja jest wymagana składniowo, ale nie trzeba wykonywać kodu.

Zwracanie wartości z funkcji

Funkcje mogą return wartość, której można użyć bezpośrednio:

def give_me_five():
    return 5

print(give_me_five())  # Print the returned value
# Out: 5

lub zapisz wartość do późniejszego użycia:

num = give_me_five()
print(num)             # Print the saved returned value
# Out: 5

lub użyj wartości do dowolnych operacji:

print(give_me_five() + 10)
# Out: 15

Jeśli w funkcji wystąpi return funkcja zostanie natychmiast zakończona, a kolejne operacje nie będą oceniane:

def give_me_another_five():
    return 5
    print('This statement will not be printed. Ever.')

print(give_me_another_five())
# Out: 5

Możesz także return wiele wartości (w postaci krotki):

def give_me_two_fives():
    return 5, 5  # Returns two 5

first, second = give_me_two_fives()
print(first)
# Out: 5
print(second)
# Out: 5

Funkcja bez instrukcji return domyślnie zwraca None . Podobnie funkcja z instrukcją return , ale bez zwracanej wartości lub zmiennej zwraca None .

Definiowanie funkcji za pomocą argumentów

Argumenty są zdefiniowane w nawiasach po nazwie funkcji:

def divide(dividend, divisor):  # The names of the function and its arguments
    # The arguments are available by name in the body of the function
    print(dividend / divisor)

Nazwa funkcji i jej lista argumentów nazywane są podpisem funkcji. Każdy nazwany argument jest faktycznie lokalną zmienną funkcji.

Podczas wywoływania funkcji podaj wartości argumentów, wymieniając je w kolejności

divide(10, 2)
# output: 5

lub określ je w dowolnej kolejności, używając nazw z definicji funkcji:

divide(divisor=2, dividend=10)
# output: 5

Definiowanie funkcji z opcjonalnymi argumentami

Opcjonalne argumenty można zdefiniować, przypisując (używając = ) wartość domyślną do nazwy argumentu:

def make(action='nothing'):
    return action

Wywołanie tej funkcji jest możliwe na 3 różne sposoby:

make("fun")
# Out: fun

make(action="sleep")
# Out: sleep

# The argument is optional so the function will use the default value if the argument is 
# not passed in.
make()   
# Out: nothing

Ostrzeżenie

Typy zmienne ( list , dict , set itp.) Należy traktować ostrożnie, jeśli podano je jako domyślny atrybut. Każda mutacja domyślnego argumentu zmieni go na stałe. Zobacz Definiowanie funkcji z opcjonalnymi argumentami zmiennymi .

Definiowanie funkcji z wieloma argumentami

Można podać funkcji tyle argumentów, ile się chce, jedynymi ustalonymi regułami jest to, że nazwa każdego argumentu musi być unikalna, a argumenty opcjonalne muszą znajdować się po argumentach nie opcjonalnych:

def func(value1, value2, optionalvalue=10):
    return '{0} {1} {2}'.format(value1, value2, optionalvalue1)

Podczas wywoływania funkcji możesz podać każde słowo kluczowe bez nazwy, ale wtedy kolejność ma znaczenie:

print(func(1, 'a', 100))
# Out: 1 a 100

print(func('abc', 14))
# abc 14 10

Lub połącz podawanie argumentów z nazwą i bez. Zatem ci z imieniem muszą iść za tymi bez, ale kolejność tych z imieniem nie ma znaczenia:

print(func('This', optionalvalue='StackOverflow Documentation', value2='is'))
# Out: This is StackOverflow Documentation

Zdefiniowanie funkcji z dowolną liczbą argumentów

Dowolna liczba argumentów pozycyjnych:

Zdefiniowanie funkcji zdolnej do przyjęcia dowolnej liczby argumentów można wykonać, poprzedzając jeden z argumentów znakiem *

def func(*args):
    # args will be a tuple containing all values that are passed in
    for i in args:
        print(i)

func(1, 2, 3)  # Calling it with 3 arguments
# Out: 1
#      2
#      3

list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values)  # Calling it with list of values, * expands the list
# Out: 1
#      2
#      3 

func()  # Calling it without arguments
# No Output 

Nie możesz podać wartości domyślnej dla args , na przykład func(*args=[1, 2, 3]) wywoła błąd składniowy (nawet się nie skompiluje).

Nie można dostarczyć te nazwy po wywołaniu funkcji, na przykład func(*args=[1, 2, 3]) podniesie TypeError .

Ale jeśli masz już swoje argumenty w tablicy (lub dowolny inny Iterable ), można powołać swoją funkcję tak: func(*my_stuff) .

Do tych argumentów ( *args ) można uzyskać dostęp za pomocą indeksu, na przykład args[0] zwróci pierwszy argument

Dowolna liczba argumentów słów kluczowych

Możesz wziąć dowolną liczbę argumentów o nazwie, definiując argument w definicji z dwoma * przed nim:

def func(**kwargs):
    # kwargs will be a dictionary containing the names as keys and the values as values
    for name, value in kwargs.items():
        print(name, value)

func(value1=1, value2=2, value3=3)   # Calling it with 3 arguments
# Out: value1 1
#      value2 2
#      value3 3

func()                               # Calling it without arguments
# No Out put

my_dict = {'foo': 1, 'bar': 2}
func(**my_dict)                      # Calling it with a dictionary
# Out: foo 1
#      bar 2

Nie można zapewnić bez ich nazw, na przykład func(1, 2, 3) podniesie TypeError .

kwargs jest prostym rodzimym słownikiem Pythona. Na przykład args['value1'] poda wartość argumentu value1 . Pamiętaj, aby wcześniej sprawdzić, czy istnieje taki argument lub w przeciwnym razie zostanie KeyError .

Ostrzeżenie

Można je łączyć z innymi opcjonalnymi i wymaganymi argumentami, ale kolejność w definicji ma znaczenie.

Argumenty pozycyjne / kluczowe są na pierwszym miejscu. (Wymagane argumenty).
Potem przychodzą arbitralne *arg argumenty *arg . (Opcjonalny).
Następnie pojawiają się argumenty zawierające tylko słowa kluczowe . (Wymagany).
Wreszcie **kwargs się dowolne słowo kluczowe **kwargs . (Opcjonalny).

#       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • arg1 musi zostać podany, w przeciwnym razie wywoływany jest błąd TypeError . Można go podać jako argument pozycyjny ( func(10) ) lub jako argument słowa kluczowego ( func(arg1=10) ).
  • należy również podać kwarg1 , ale można go podać tylko jako słowo-argument: func(kwarg1=10) .
  • arg2 i kwarg2 są opcjonalne. Jeśli wartość ma zostać zmieniona, obowiązują takie same zasady jak dla arg1 (pozycyjne lub słowo kluczowe) i kwarg1 (tylko słowo kluczowe).
  • *args wyłapuje dodatkowe parametry pozycyjne. Zauważ jednak, że arg1 i arg2 muszą być dostarczone jako argumenty pozycyjne, aby przekazać argumenty do *args : func(1, 1, 1, 1) .
  • **kwargs przechwytuje wszystkie dodatkowe parametry słów kluczowych. W tym przypadku każdy parametr, który nie jest arg1 , arg2 , kwarg1 lub kwarg2 . Na przykład: func(kwarg3=10) .
  • W Pythonie 3 możesz użyć samego * , aby wskazać, że wszystkie kolejne argumenty muszą być określone jako słowa kluczowe. Na przykład funkcja math.isclose w Pythonie 3.5 i nowszych jest zdefiniowana za pomocą def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) , co oznacza, że dwa pierwsze argumenty mogą być podane pozycjonalnie, ale opcjonalnie trzeci i czwarty parametr można podać tylko jako argumenty słów kluczowych.

Python 2.x nie obsługuje parametrów zawierających tylko słowa kluczowe. To zachowanie można emulować za pomocą programu kwargs :

def func(arg1, arg2=10, **kwargs):
    try:
        kwarg1 = kwargs.pop("kwarg1")
    except KeyError:
        raise TypeError("missing required keyword-only argument: 'kwarg1'")

    kwarg2 = kwargs.pop("kwarg2", 2)
    # function body ...

Uwaga na temat nazewnictwa

Konwencja nazywania opcjonalnych argumentów pozycyjnych args i opcjonalnych argumentów słów kluczowych kwargs to tylko konwencja, w której możesz używać dowolnych nazw, które lubisz, ale warto postępować zgodnie z konwencją, aby inni wiedzieli, co robisz, a nawet sam później, więc proszę.

Uwaga na temat wyjątkowości

Dowolną funkcję można zdefiniować za pomocą żadnego lub jednego *args i żadnego lub jednego **kwargs ale nie więcej niż jednym z nich. Również *args musi być ostatnim argumentem pozycyjnym, a **kwargs musi być ostatnim parametrem. Próba użycia więcej niż jednego z nich spowoduje wyjątek błędu składni.

Uwaga na temat funkcji zagnieżdżania z opcjonalnymi argumentami

Możliwe jest zagnieżdżanie takich funkcji, a zwykłą konwencją jest usuwanie elementów, które kod już obsługiwał, ale jeśli przekazujesz parametry, musisz przekazać opcjonalne argumenty pozycyjne z prefiksem * i opcjonalne args słowa kluczowego z prefiksem ** , w przeciwnym razie argumenty zostaną przekazane jako lista lub krotka, a kwargs jako pojedynczy słownik. na przykład:

def fn(**kwargs):
    print(kwargs)
    f1(**kwargs)

def f1(**kwargs):
    print(len(kwargs))

fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2

Definiowanie funkcji z opcjonalnymi argumentami zmiennymi

Występuje problem podczas używania opcjonalnych argumentów ze zmiennym typem domyślnym (opisanym w Definiowaniu funkcji z opcjonalnymi argumentami ), który może potencjalnie prowadzić do nieoczekiwanego zachowania.

Wyjaśnienie

Ten problem powstaje, ponieważ domyślne argumenty funkcji są inicjowane jeden raz , w momencie zdefiniowania funkcji, a nie (jak wiele innych języków), gdy funkcja jest wywoływana . Domyślne wartości są przechowywane w zmiennej __defaults__ obiektu funkcji.

def f(a, b=42, c=[]):
    pass

print(f.__defaults__)
# Out: (42, [])

W przypadku typów niezmiennych (patrz Przekazywanie i modyfikowanie argumentów ) nie stanowi to problemu, ponieważ nie ma możliwości zmutowania zmiennej; można go tylko przypisać ponownie, pozostawiając pierwotną wartość bez zmian. W związku z tym kolejne gwarantują, że będą miały tę samą wartość domyślną. Jednak w przypadku typu zmiennego oryginalna wartość może mutować, wywołując różne funkcje składowe. Dlatego nie ma gwarancji, że kolejne wywołania funkcji będą miały początkową wartość domyślną.

def append(elem, to=[]):
    to.append(elem)      # This call to append() mutates the default variable "to"
    return to

append(1)
# Out: [1]

append(2)  # Appends it to the internally stored list
# Out: [1, 2]

append(3, [])  # Using a new created list gives the expected result
# Out: [3]

# Calling it again without argument will append to the internally stored list again
append(4)   
# Out: [1, 2, 4]

Uwaga: Niektóre IDE, takie jak PyCharm, będą wyświetlać ostrzeżenie, gdy typ zmienny zostanie określony jako domyślny atrybut.

Rozwiązanie

Jeśli chcesz się upewnić, że domyślnym argumentem jest zawsze argument określony w definicji funkcji, rozwiązaniem jest zawsze użycie niezmiennego typu jako domyślnego argumentu.

Powszechnym idiomem służącym do osiągnięcia tego, gdy domyślnym typem jest zmienny typ, jest użycie None (niezmienny) jako domyślny argument, a następnie przypisanie rzeczywistej wartości domyślnej do zmiennej argumentu, jeśli jest ona równa None .

def append(elem, to=None):
    if to is None:
        to = []

    to.append(elem)
    return to

Funkcje Lambda (wbudowane / anonimowe)

lambda kluczowe lambda tworzy funkcję wbudowaną, która zawiera pojedyncze wyrażenie. Wartością tego wyrażenia jest to, co funkcja zwraca po wywołaniu.

Rozważ funkcję:

def greeting():
    return "Hello"

który, nazywany jako:

print(greeting())

drukuje:

Hello

Można to zapisać jako funkcję lambda w następujący sposób:

greet_me = lambda: "Hello"

Patrz uwaga na dole tego rozdziału dotycząca przypisywania lambda do zmiennych. Ogólnie nie rób tego.

To tworzy funkcję wbudowaną o nazwie greet_me która zwraca Hello . Zauważ, że nie piszesz return podczas tworzenia funkcji z lambda. Wartość po : jest automatycznie zwracana.

Po przypisaniu do zmiennej może być używana tak jak zwykła funkcja:

print(greet_me())

drukuje:

Hello

lambda może przyjmować argumenty:

strip_and_upper_case = lambda s: s.strip().upper()

strip_and_upper_case("  Hello   ")

zwraca ciąg:

HELLO

Mogą również przyjmować dowolną liczbę argumentów / argumentów słów kluczowych, tak jak normalne funkcje.

greeting = lambda x, *args, **kwargs: print(x, args, kwargs)
greeting('hello', 'world', world='world')

drukuje:

hello ('world',) {'world': 'world'}

lambda są powszechnie używane do krótkich funkcji, które są wygodne do zdefiniowania w punkcie, w którym są wywoływane (zwykle z sorted , filter i map ).

Na przykład ten wiersz sortuje listę ciągów, ignorując ich wielkość liter i ignorując białe znaki na początku i na końcu:

sorted( [" foo ", "    bAR", "BaZ    "], key=lambda s: s.strip().upper())
# Out:
# ['    bAR', 'BaZ    ', ' foo ']

Sortuj listę ignorując białe spacje:

sorted( [" foo ", "    bAR", "BaZ    "], key=lambda s: s.strip())
# Out:
# ['BaZ    ', '    bAR', ' foo ']

Przykłady z map :

sorted( map( lambda s: s.strip().upper(), [" foo ", "    bAR", "BaZ    "]))
# Out:
# ['BAR', 'BAZ', 'FOO']

sorted( map( lambda s: s.strip(), [" foo ", "    bAR", "BaZ    "]))
# Out:
# ['BaZ', 'bAR', 'foo']

Przykłady z listami numerycznymi:

my_list = [3, -4, -2, 5, 1, 7]
sorted( my_list, key=lambda x: abs(x))
# Out:
# [1, -2, 3, -4, 5, 7]

list( filter( lambda x: x>0, my_list))
# Out:
# [3, 5, 1, 7]

list( map( lambda x: abs(x), my_list))
# Out:
[3, 4, 2, 5, 1, 7]

Można wywoływać inne funkcje (z / bez argumentów) z wnętrza funkcji lambda.

def foo(msg):
    print(msg)

greet = lambda x = "hello world": foo(x)
greet()

drukuje:

hello world

Jest to przydatne, ponieważ lambda może zawierać tylko jedno wyrażenie, a za pomocą funkcji pomocniczej można uruchamiać wiele instrukcji.


UWAGA

Pamiętaj, że PEP-8 (oficjalny przewodnik po stylu Python) nie zaleca przypisywania lambd do zmiennych (tak jak to zrobiliśmy w dwóch pierwszych przykładach):

Zawsze używaj instrukcji def zamiast instrukcji przypisania, która wiąże wyrażenie lambda bezpośrednio z identyfikatorem.

Tak:

def f(x): return 2*x

Nie:

f = lambda x: 2*x

Pierwsza forma oznacza, że nazwą wynikowego obiektu funkcji jest konkretnie f zamiast ogólnego <lambda> . Jest to bardziej przydatne w przypadku śledzenia wstecznego i reprezentacji ciągów w ogóle. Zastosowanie instrukcji przypisania eliminuje jedyną korzyść, jaką wyrażenie lambda może zaoferować w stosunku do jawnej instrukcji def (tzn. Że można ją osadzić w większym wyrażeniu).

Przekazywanie argumentów i zmienność

Po pierwsze, trochę terminologii:

  • argument ( aktualny parametr): rzeczywista zmienna przekazywana do funkcji;
  • parametr (parametr formalny ): zmienna odbiorcza używana w funkcji.

W Pythonie argumenty są przekazywane przez przypisanie (w przeciwieństwie do innych języków, w których argumenty mogą być przekazywane przez wartość / referencję / wskaźnik).

  • Mutowanie parametru spowoduje mutację argumentu (jeśli typ argumentu jest zmienny).

    def foo(x):        # here x is the parameter
        x[0] = 9       # This mutates the list labelled by both x and y
        print(x)
    
    y = [4, 5, 6]
    foo(y)             # call foo with y as argument
    # Out: [9, 5, 6]   # list labelled by x has been mutated
    print(y)           
    # Out: [9, 5, 6]   # list labelled by y has been mutated too
    
  • Ponowne przypisanie parametru nie spowoduje ponownego przypisania argumentu.

    def foo(x):        # here x is the parameter, when we call foo(y) we assign y to x
        x[0] = 9       # This mutates the list labelled by both x and y
        x = [1, 2, 3]  # x is now labeling a different list (y is unaffected)
        x[2] = 8       # This mutates x's list, not y's list
      
    y = [4, 5, 6]      # y is the argument, x is the parameter
    foo(y)             # Pretend that we wrote "x = y", then go to line 1
    y
    # Out: [9, 5, 6]
    

W Pythonie, tak naprawdę nie należy przypisać wartości do zmiennych, zamiast tego bind (tj assign, dołącz) zmienne (uważane za nazwami) do obiektów.

  • Niezmienne: liczby całkowite, łańcuchy, krotki i tak dalej. Wszystkie operacje wykonują kopie.
  • Zmienne: listy, słowniki, zestawy i tak dalej. Operacje mogą mutować, ale nie muszą.
x = [3, 1, 9]
y = x
x.append(5)    # Mutates the list labelled by x and y, both x and y are bound to [3, 1, 9]
x.sort()       # Mutates the list labelled by x and y (in-place sorting)
x = x + [4]    # Does not mutate the list (makes a copy for x only, not y)
z = x          # z is x ([1, 3, 9, 4])
x += [6]       # Mutates the list labelled by both x and z (uses the extend function).
x = sorted(x)  # Does not mutate the list (makes a copy for x only).
x
# Out: [1, 3, 4, 5, 6, 9]
y
# Out: [1, 3, 5, 9]
z
# Out: [1, 3, 5, 9, 4, 6]

Zamknięcie

Zamknięcia w Pythonie są tworzone przez wywołania funkcji. W tym przypadku wywołanie makeInc tworzy powiązanie dla x którego odwołuje się funkcja inc . Każde wywołanie makeInc tworzy nowe wystąpienie tej funkcji, ale każde wystąpienie ma link do innego wiązania x .

def makeInc(x):
  def inc(y):
     # x is "attached" in the definition of inc
     return y + x

  return inc

incOne = makeInc(1)
incFive = makeInc(5)

incOne(5) # returns 6
incFive(5) # returns 10

Zauważ, że podczas gdy w zwykłym zamknięciu zamknięta funkcja w pełni dziedziczy wszystkie zmienne z otaczającego ją środowiska, w tej konstrukcji zamknięta funkcja ma dostęp tylko do odczytu do odziedziczonych zmiennych, ale nie może im przypisywać przypisań

def makeInc(x):
  def inc(y):
     # incrementing x is not allowed
     x += y  
     return x

  return inc

incOne = makeInc(1)
incOne(5) # UnboundLocalError: local variable 'x' referenced before assignment

Python 3 oferuje instrukcję nonlocal ( Zmienne nonlocal ) umożliwiającą pełne zamknięcie funkcji zagnieżdżonych.

Python 3.x 3.0
def makeInc(x):
  def inc(y):
     nonlocal x
     # now assigning a value to x is allowed
     x += y  
     return x

  return inc

incOne = makeInc(1)
incOne(5) # returns 6

Funkcje rekurencyjne

Funkcja rekurencyjna to funkcja, która wywołuje się w swojej definicji. Na przykład funkcja matematyczna, silnia, zdefiniowana przez factorial(n) = n*(n-1)*(n-2)*...*3*2*1 . można zaprogramować jako

def factorial(n):
    #n here should be an integer
    if n == 0:
        return 1
    else:
        return n*factorial(n-1)

dane wyjściowe są następujące:

factorial(0)
#out 1
factorial(1)
#out 1
factorial(2)
#out 2
factorial(3)
#out 6

zgodnie z oczekiwaniami. Zauważ, że ta funkcja jest rekurencyjna, ponieważ drugi return factorial(n-1) , w którym funkcja wywołuje się w swojej definicji.

Niektóre funkcje rekurencyjne można zaimplementować za pomocą lambda , funkcja silnia za pomocą lambda byłaby mniej więcej taka:

factorial = lambda n: 1 if n == 0 else n*factorial(n-1)

Funkcja generuje to samo co powyżej.

Limit rekurencji

Istnieje limit głębokości możliwej rekurencji, który zależy od implementacji Pythona. Po osiągnięciu limitu zgłaszany jest wyjątek RuntimeError:

def cursing(depth):
  try:
    cursing(depth + 1) # actually, re-cursing
  except RuntimeError as RE:
    print('I recursed {} times!'.format(depth))

cursing(0)
# Out: I recursed 1083 times!

Można zmienić limit głębokości rekurencji za pomocą sys.setrecursionlimit(limit) i sprawdzić ten limit za pomocą sys.getrecursionlimit() .

sys.setrecursionlimit(2000)
cursing(0)
# Out: I recursed 1997 times!

Od wersji Python 3.5 wyjątkiem jest RecursionError , który pochodzi z RuntimeError .

Funkcje zagnieżdżone

Funkcje w pythonie są obiektami pierwszej klasy. Można je zdefiniować w dowolnym zakresie

def fibonacci(n):
    def step(a,b):
        return b, a+b
    a, b = 0, 1
    for i in range(n):
        a, b = step(a, b)
    return a

Funkcje przechwytują otaczający ich zakres, który można przekazywać jak każdy inny obiekt

def make_adder(n):
    def adder(x):
        return n + x
    return adder
add5 = make_adder(5)
add6 = make_adder(6)
add5(10)
#Out: 15
add6(10)
#Out: 16

def repeatedly_apply(func, n, x):
    for i in range(n):
        x = func(x)
    return x

repeatedly_apply(add5, 5, 1)
#Out: 26

Rozpakowywanie iterowalne i słownikowe

Funkcje pozwalają określić następujące typy parametrów: pozycyjny, nazwany, zmienny pozycyjny, słowa kluczowe args (kwargs). Oto jasne i zwięzłe użycie każdego rodzaju.

def unpacking(a, b, c=45, d=60, *args, **kwargs):
    print(a, b, c, d, args, kwargs)

>>> unpacking(1, 2)
1 2 45 60 () {}
>>> unpacking(1, 2, 3, 4)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, c=3)
1 2 3 4 () {}


>>> pair = (3,)
>>> unpacking(1, 2, *pair, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, *pair, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, c=3, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'

>>> args_list = [3]
>>> unpacking(1, 2, *args_list, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, *args_list, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'


>>> pair = (3, 4)
>>> unpacking(1, 2, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *pair)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *pair, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'



>>> args_list = [3, 4]
>>> unpacking(1, 2, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *args_list)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *args_list, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'


>>> arg_dict = {'c':3, 'd':4}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'d':4, 'c':3}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'c':3, 'd':4, 'not_a_parameter': 75}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {'not_a_parameter': 75}


>>> unpacking(1, 2, *pair, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, 3, 4, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'

# Positional arguments take priority over any other form of argument passing
>>> unpacking(1, 2, **arg_dict, c=3)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, 3, **arg_dict, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'

Wymuszenie użycia nazwanych parametrów

Wszystkie parametry określone po pierwszej gwiazdce w podpisie funkcji są tylko słowami kluczowymi.

def f(*a, b):
    pass

f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'

W Pythonie 3 można wstawić pojedynczą gwiazdkę do podpisu funkcji, aby pozostałe argumenty mogły być przekazywane tylko za pomocą argumentów słów kluczowych.

def f(a, b, *, c):
    pass

f(1, 2, 3)
# TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)
# No error

Rekurencyjna Lambda przy użyciu przypisanej zmiennej

Jedna metoda tworzenia rekurencyjnych funkcji lambda obejmuje przypisanie funkcji do zmiennej, a następnie odwołanie się do tej zmiennej w samej funkcji. Typowym przykładem tego jest rekurencyjne obliczanie silni liczby - takie jak pokazano w poniższym kodzie:

lambda_factorial = lambda i:1 if i==0 else i*lambda_factorial(i-1)
print(lambda_factorial(4)) # 4 * 3 * 2 * 1 = 12 * 2 = 24

Opis kodu

Funkcja lambda, poprzez swoje przypisanie zmiennej, przekazuje wartość (4), którą ocenia i zwraca 1, jeśli wynosi 0, w przeciwnym razie zwraca bieżącą wartość ( i ) * kolejne obliczenie przez funkcję lambda wartości - 1 ( i-1 ). Trwa to do momentu zmniejszenia wartości przekazywanej do 0 ( return 1 ). Proces, który można wizualizować jako:

recursive_lambda_path



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow