수색…


소개

Python의 함수는 체계적이고 재사용 가능한 모듈 식 코드를 제공하여 일련의 특정 작업을 수행합니다. 함수는 코딩 프로세스를 단순화하고 중복 논리를 방지하며 코드를 쉽게 따르도록합니다. 이 주제는 Python에서 함수의 선언과 활용에 대해 설명합니다.

파이썬에는 print() , input() , len() 과 같은 많은 내장 함수print() . 내장 기능 외에도 특정 작업을 수행하는 고유 한 기능을 만들 수도 있습니다. 이러한 기능을 사용자 정의 기능 이라고 합니다 .

통사론

  • def function_name ( arg1, ... argN, * args, kw1, kw2 = default, ..., ** kwargs ) : 명령문
  • 람다 arg1, ... argN, * args, kw1, kw2 = 기본, ..., ** kwargs : 표현

매개 변수

매개 변수 세부
arg1 , ..., argN 정규 인수
* args 이름없는 위치 인수
kw1 , ..., kwN 키워드 전용 인수
** kwargs 나머지 키워드 인수

비고

기능으로 할 수있는 5 가지 기본 사항 :

  • 변수에 함수 지정

    def f():
      print(20)
    y = f
    y()
    # Output: 20
    
  • 다른 함수 내의 함수 정의 ( 중첩 함수 )

    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
    
  • 함수는 다른 함수를 반환 할 수 있습니다.

    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
    
  • 함수는 다른 함수에 매개 변수로 전달 될 수 있습니다.

    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
    
  • 내부 함수는 내부 범위 ( Closure )에 액세스 할 수 있습니다.

    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!
    

추가 리소스

간단한 함수 정의 및 호출

def 문을 사용하는 것은 파이썬에서 함수를 정의하는 가장 일반적인 방법입니다. 이 문은 다음 구문을 사용하는 소위 단일 절 복합 문 입니다.

def function_name(parameters):
    statement(s)

function_namefunction_name식별자 로 알려져 있습니다. 함수 정의는 실행 문이므로 해당 함수 이름을 나중에 식별자로 호출 할 수있는 함수 객체에 바인딩 합니다.

parameters 는 함수가 호출 될 때 인수로 제공된 값에 바인딩되는 식별자의 선택적 목록입니다. 함수는 쉼표로 구분 된 임의의 수의 인수를 가질 수 있습니다.

statement(s) - 또한 함수 본문으로 알려진 - 함수가 호출 될 때마다 실행 문 비어 있지 않은 순서입니다. 즉, 들여 쓰기 된 블록 과 마찬가지로 함수 본문을 비울 수 없습니다.

다음은 호출 될 때마다 Hello 를 출력하는 간단한 함수 정의의 예입니다.

def greet():
    print("Hello")

이제 정의 된 greet() 함수를 호출 해 보겠습니다.

greet()
# Out: Hello

이것은 하나의 인수를 취하여 함수가 호출 될 때마다 전달 된 값을 표시하는 함수 정의의 다른 예입니다.

def greet_two(greeting):
    print(greeting)

그런 다음 greet_two() 함수를 인수와 함께 호출해야합니다.

greet_two("Howdy")
# Out: Howdy

또한 해당 함수 인수에 기본값을 제공 할 수 있습니다.

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

이제 값을주지 않고 함수를 호출 할 수 있습니다.

greet_two()
# Out: Howdy 

다른 많은 언어와 달리 함수의 반환 형식을 명시 적으로 선언 할 필요가 없습니다. 파이썬 함수는 return 키워드를 통해 모든 유형의 값을 반환 할 수 있습니다. 하나의 함수는 여러 가지 다른 유형을 반환 할 수 있습니다!

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

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

# Output:
0
Hello!

이것은 호출자가 올바르게 처리하는 한 완벽하게 유효한 Python 코드입니다.

return 문없이 실행의 끝 부분에 도달하는 함수는 항상 None 반환합니다.

def do_nothing():
    pass

print(do_nothing())
# Out: None

앞서 언급했듯이 함수 정의에는 비어 있지 않은 명령문 시퀀스 인 함수 본문이 있어야합니다. 따라서 pass 문은 함수 본문으로 사용되며 null 연산입니다. 실행될 때 아무 것도 발생하지 않습니다. 그것은 그것이 의미하는 바를 수행합니다. 명령문이 구문 적으로 필요하지만 코드를 실행할 필요가없는 경우 자리 표시 자로 유용합니다.

함수에서 값 반환

함수는 직접 사용할 수있는 값을 return 할 수 있습니다.

def give_me_five():
    return 5

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

또는 나중에 사용할 수 있도록 값을 저장하십시오.

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

또는 모든 연산에 값을 사용하십시오.

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

함수에서 return 이 발생하면 함수는 즉시 종료되고 이후 작업은 평가되지 않습니다.

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

print(give_me_another_five())
# Out: 5

튜플 형태 return 여러 값을 return 할 수도 있습니다.

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

return 문이 없는 함수는 암시 적으로 None 반환합니다. 마찬가지로 return 문이 있지만 반환 값이나 변수가없는 함수는 None 반환합니다.

인수를 사용하여 함수 정의

인수는 함수 이름 뒤의 괄호 안에 정의됩니다.

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)

함수 이름과 인수 목록은 함수의 서명 이라고합니다. 각 명명 된 인수는 사실 함수의 로컬 변수입니다.

함수를 호출 할 때 순서대로 나열하여 인수 값을 제공하십시오.

divide(10, 2)
# output: 5

또는 함수 정의의 이름을 사용하여 순서에 관계없이 지정할 수 있습니다.

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

선택적 인수를 사용하여 함수 정의

선택적 인수는 argument-name에 ( = 사용하여) 기본값을 할당하여 정의 할 수 있습니다.

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

이 기능을 호출하는 방법은 3 가지가 있습니다.

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

경고

변경할 수있는 유형 ( list , dict , set 등)은 기본 속성으로 지정할 때주의해서 다루어야합니다. 기본 인수가 변경되면 영구적으로 변경됩니다. 선택적으로 변경할 수있는 인수가있는 함수 정의를 참조하십시오.

여러 인수를 갖는 함수 정의하기

하나의 함수가 원하는만큼 많은 인자를 줄 수있다. 유일하게 고정 된 규칙은 각 인자 이름이 유일해야하고 선택적 인자는 선택 사항이 아닌 것들 다음에 와야한다는 것이다.

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

함수를 호출 할 때 이름없이 각 키워드를 제공 할 수 있지만 순서는 중요합니다.

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

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

또는 인수를 이름과없는 것으로 결합하십시오. 그렇다면 이름이있는 사람은 이름을 가진 사람을 따라야하지만 이름이있는 사람의 순서는 중요하지 않습니다.

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

임의의 수의 인수로 함수 정의하기

임의 인수의 위치 인수 :

임의의 수의 인수를 취할 수있는 함수를 정의하려면 인수 중 하나 앞에 *

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 

args 에 대한 기본값을 제공 할 수 없습니다. 예를 들어 func(*args=[1, 2, 3]) 은 구문 오류를 발생시킵니다 (컴파일하지 않습니다).

함수를 호출 할 때 이름을 제공 할 수 없습니다. 예를 들어 func(*args=[1, 2, 3])TypeError 시킵니다.

그러나 배열 (또는 다른 Iterable )에 인수가 이미있는 경우 func(*my_stuff) 와 같은 함수를 호출 할 수 있습니다 .

이러한 인수 ( *args )는 인덱스에 의해 액세스 할 수 있습니다. 예를 들어, args[0] 는 최초의 인수를 돌려줍니다

임의의 수의 키워드 인수

이름 앞에 임의의 수의 인수를 취할 수 있습니다. 정의 앞에 인수가 2 개 * 정의되어 있습니다.

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

이름 없이 이들을 제공 할 수 없습니다. 예를 들어 func(1, 2, 3)TypeError 시킵니다.

kwargs 는 일반 원시 파이썬 사전입니다. 예를 들어, args['value1'] 는 인수 value1 의 값을 제공합니다. 이러한 인수가 있거나 KeyError 가 발생했는지 미리 확인하십시오.

경고

이들을 다른 선택적 및 필수 인수와 함께 사용할 수 있지만 정의 내에서의 순서는 중요합니다.

위치 / 키워드 인수가 먼저옵니다. (필수 인수).
그런 다음 임의의 *arg 인수가옵니다. (선택 과목).
그러면 키워드 전용 인수가 다음에옵니다. (필수).
마지막으로 임의 키워드 **kwargs 옵니다. (선택 과목).

#       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass
  • arg1 해야하며, 그렇지 않으면 TypeError 가 발생합니다. 위치 지정 ( func(10) ) 또는 키워드 인수 ( func(arg1=10) )로 제공 될 수 있습니다.
  • kwarg1 도 지정해야하지만 keyword-argument : func(kwarg1=10) 로만 제공 할 수 있습니다.
  • arg2kwarg2 는 선택 사항입니다. 값을 변경하려는 경우 arg1 (위치 또는 키워드) 및 kwarg1 (키워드 만)과 동일한 규칙이 적용됩니다.
  • *args 추가 위치 매개 변수를 포착합니다. 그러나 arg1arg2 는 인수를 *args : func(1, 1, 1, 1) 에 전달하기위한 위치 인수로 제공되어야합니다.
  • **kwargs 모든 추가 키워드 매개 변수를 포착합니다. 이 경우 arg1 , arg2 , kwarg1 또는 kwarg2 가 아닌 매개 변수. 예 : func(kwarg3=10) .
  • 파이썬 3에서는 * 를 사용하여 모든 후속 인수가 키워드로 지정되어야 함을 나타낼 수 있습니다. 예를 들어, 파이썬 3.5 이상의 math.isclose 함수는 def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) 사용하여 정의됩니다. 즉 처음 두 개의 인수는 위치 적으로 제공 될 수 있지만 옵션 세 번째 및 네 번째 매개 변수는 키워드 인수로만 제공 될 수 있습니다.

Python 2.x는 키워드 전용 매개 변수를 지원하지 않습니다. 이 동작은 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 ...

이름 지정에 대한 참고 사항

선택 위치 인수의 이름의 규칙 args 및 선택적 키워드 인수 kwargs 당신이 당신이 원하는 이름을 사용할 수있는 규칙이지만, 다른 사람들이 당신이하고, 심지어 자신 나중에 그렇게하십시오있는 것을 알 수 있도록 규칙을 따라하는 데 유용합니다.

고유성에 대한 참고 사항

모든 함수는 none 또는 하나의 *argsnone 또는 **kwargs 로 정의 될 수 있지만 둘 중 하나 이상 으로는 정의 될 수 없습니다. 또한 *args 마지막 위치 인수 여야하며 **kwargs 는 마지막 매개 변수 여야합니다. 구문 오류 예외가 발생합니다 중 하나 이상을 사용하려고.

선택적 인수로 중첩 함수에 대한 참고 사항

이러한 함수를 중첩하는 것이 가능하며 코드가 이미 처리 한 항목을 제거하는 것이 일반적인 규칙 이지만 매개 변수를 전달하는 경우 선택적 접두어로 * 접두사를 사용하고 선택적 키워드 args에 ** 접두어를 전달해야합니다 그렇지 않으면 args는리스트 또는 튜플로 전달되고 kwargs는 하나의 사전으로 전달됩니다. 예 :

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

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

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

선택적으로 변경할 수있는 인수를 사용하여 함수 정의

(설명 변경 가능한 기본 유형과 선택적 인수를 사용할 때 문제가 선택적 인수로 함수를 정의 잠재적으로 예상치 못한 동작이 발생할 수 있습니다).

설명

함수가 호출 될 때 함수의 기본 인수 (다른 많은 언어 같은) 함수가 정의 될 때 시점에서 한번 초기화하고 있지 않기 때문에이 문제가 발생합니다. 기본값은 함수 객체의 __defaults__ 멤버 변수 내에 저장됩니다.

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

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

불변 형의 경우 ( 인수 전달 및 가변성 참조) 변수를 변형 할 방법이 없기 때문에 이것은 문제가되지 않습니다. 원래 값을 변경하지 않고 다시 할당 할 수 있습니다. 따라서 이후에는 동일한 기본값이 보장됩니다. 그러나 가변 유형의 경우 다양한 멤버 함수를 호출하여 원래 값을 변경할 수 있습니다. 따라서 함수를 연속적으로 호출 할 때 초기 기본값이 보장되지는 않습니다.

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]

참고 : PyCharm과 같은 일부 IDE는 변경 가능한 유형이 기본 속성으로 지정된 경우 경고를 발행합니다.

해결책

기본 인수는 항상 함수 정의에서 지정한 하나인지 확인하려면, 다음 솔루션은 항상 기본 인수로 불변의 유형을 사용하는 것입니다.

변경 가능한 유형은 기본적으로 필요한 경우 일반적인 관용구 이것을 달성하기 위해, 사용되지하는 None 기본 인수 (불변)과 같이면 인수 변수 실제 디폴트 값을 지정 None .

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

    to.append(elem)
    return to

람다 (인라인 / 익명) 함수

lambda 키워드는 단일 표현식을 포함하는 인라인 함수를 만듭니다. 이 표현식의 값은 호출 될 때 함수가 리턴하는 값입니다.

다음 함수를 고려하십시오.

def greeting():
    return "Hello"

어느 때, 전화 :

print(greeting())

인쇄물:

Hello

이것은 다음과 같이 람다 함수로 작성 될 수 있습니다 :

greet_me = lambda: "Hello"

변수에 람다 할당에 관해서는이 절의 하단에있는 주석을 참조하십시오. 일반적으로하지 마십시오.

Hello 를 리턴하는 greet_me 라는 이름의 인라인 함수를 작성합니다. 람다 함수를 만들 때는 return 을 쓰지 않습니다. 값 후에는 : 자동으로 반환됩니다.

변수에 할당되면 일반 함수처럼 사용할 수 있습니다.

print(greet_me())

인쇄물:

Hello

lambda 는 인수도 취할 수 있습니다.

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

strip_and_upper_case("  Hello   ")

다음 문자열을 반환합니다.

HELLO

또한 일반 함수처럼 임의의 수의 인수 / 키워드 인수를 사용할 수 있습니다.

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

인쇄물:

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

lambda 는 일반적으로 소위 함수 (예 : sorted , filtermap )가 호출되는 지점에서 정의하는 것이 편리합니다.

예를 들어,이 행은 대소 문자를 무시하고 처음과 끝에 공백을 무시한 문자열 목록을 정렬합니다.

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

공백을 무시하고 목록 정렬 :

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

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']

숫자 목록이있는 예 :

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]

람다 함수 내부에서 다른 함수 (인수가 있거나없는)를 호출 할 수 있습니다.

def foo(msg):
    print(msg)

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

인쇄물:

hello world

lambda 에는 하나의 표현식 만 포함될 수 있고 보조 함수를 사용하면 여러 구문을 실행할 수 있기 때문에 유용합니다.


노트

PEP-8 (공식 파이썬 스타일 가이드)은 람다를 변수에 할당하는 것을 권장하지 않는다는 점을 명심하십시오 (처음 두 예제에서와 같이) :

람다 표현식을 식별자에 직접 바인드하는 할당 문 대신 항상 def 문을 사용하십시오.

예:

def f(x): return 2*x

아니:

f = lambda x: 2*x

첫 번째 형식은 결과 함수 객체의 이름이 제네릭 <lambda> 대신에 특별히 f 라는 것을 의미합니다. 이는 일반적으로 추적 및 문자열 표현에 더 유용합니다. 할당 문을 사용하면 람다 표현식이 명시적인 def 문 (즉, 더 큰 표현식에 포함될 수 있음)을 통해 제공 할 수있는 유일한 이점이 제거됩니다.

인수 전달 및 가변성

첫째, 일부 용어는 다음과 같습니다.

  • 인수 ( 실제 매개 변수) : 함수에 전달되는 실제 변수.
  • 매개 변수 ( 형식 매개 변수) : 함수에서 사용되는 수신 변수.

파이썬에서는 인수가 할당에 의해 전달됩니다 (다른 언어와 달리 인수는 값 / 참조 / 포인터로 전달 될 수 있음).

  • 매개 변수를 변경하면 인수가 변경됩니다 (인수의 유형이 변경 가능한 경우).

    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
    
  • 매개 변수를 재 할당해도 인수가 재 할당되지 않습니다.

    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]
    

파이썬에서는 변수에 값을 할당하지 않고 대신 변수 ( 이름으로 간주)를 객체에 바인딩 (즉, 할당, 연결)합니다.

  • 변경 불가능 : 정수, 문자열, 튜플 등. 모든 작업이 복사본을 만듭니다.
  • 변경 가능 : 목록, 사전, 세트 등. 작업은 변경 될 수도 있고 변경되지 않을 수도 있습니다.
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]

폐쇄

파이썬의 클로저는 함수 호출에 의해 생성됩니다. 여기에서 makeInc 를 호출하면 함수 inc 내부에서 참조되는 x 대한 바인딩이 생성됩니다. makeInc 를 호출 할 때 makeInc 함수의 새 인스턴스가 만들어 지지만 각 인스턴스에는 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

정규 닫힘에서 둘러싸인 함수는 둘러싸는 환경으로부터 모든 변수를 완전히 상속 받지만,이 생성물에서 닫힌 함수는 상속 된 변수에 대한 읽기 액세스 만 가지고 있지만 할당은 할 수 없습니다

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

파이썬 3은 중첩 된 함수로 전체 클로저를 실현하기위한 nonlocal 지역적 구문 ( Nonlocal Variables )을 제공합니다.

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

재귀 함수

재귀 함수는 정의에서 자신을 호출하는 함수입니다. 예를 들어 factorial(n) = n*(n-1)*(n-2)*...*3*2*1 의해 정의 된 수학 함수, 계승. 다음과 같이 프로그래밍 될 수있다.

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

출력은 다음과 같습니다.

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

예상대로 이 함수는 그 정의에서 스스로를 호출하는 두 번째 return factorial(n-1) 이기 때문에이 함수는 순환 적입니다.

어떤 재귀 함수는 람다를 사용하여 구현 될 수 있습니다. 람다 를 사용하는 계승 함수는 다음과 같습니다.

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

이 함수는 위와 같은 결과를 출력합니다.

재귀 제한

가능한 재귀의 깊이에는 제한이 있습니다. 재귀의 깊이는 Python 구현에 따라 다릅니다. 한계에 도달하면 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!

sys.setrecursionlimit(limit) 를 사용하여 재귀 깊이 제한을 변경하고 sys.getrecursionlimit()sys.getrecursionlimit() 제한을 검사 할 수 있습니다.

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

파이썬 3.5, 예외가있다 RecursionError 로부터 유도된다 RuntimeError .

중첩 된 함수

Python의 함수는 1 급 오브젝트입니다. 모든 범위에서 정의 할 수 있습니다.

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

함수를 둘러싼 캡처 범위는 다른 종류의 객체처럼 전달 될 수 있습니다.

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

반복 가능 및 사전 압축 풀기

함수를 사용하면 position, named, variable position, 키워드 args (kwargs)와 같은 매개 변수 유형을 지정할 수 있습니다. 다음은 각 유형의 명확하고 간결한 사용법입니다.

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'

명명 된 매개 변수 사용 강제

함수 시그니처의 첫 번째 별표 뒤에 지정된 모든 매개 변수는 키워드 전용입니다.

def f(*a, b):
    pass

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

파이썬 3에서는 함수 아규먼트에 하나의 별표 (*)를 넣으면서 나머지 인자가 키워드 인자를 통해서만 전달 될 수있다.

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

할당 된 변수를 사용하는 재귀 적 람다

재귀 람다 함수를 만드는 한 가지 방법은 함수에 변수를 할당 한 다음 함수 자체에서 해당 변수를 참조하는 것입니다. 이에 대한 일반적인 예는 숫자의 계승을 재귀 적으로 계산하는 것입니다 (예 : 다음 코드와 같이).

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

코드 설명

람다 함수는 변수 할당을 통해 값 (4)를 전달하고, 값이 0이면 1을 반환하고 그렇지 않으면 현재 값 ( i )을 반환합니다. * 값 1의 람다 함수에 의한 다른 계산 ( i-1 ). 이 값은 전달 된 값이 0 ( return 1 )으로 감소 할 때까지 계속됩니다. 다음과 같이 시각화 할 수있는 프로세스 :

recursive_lambda_path



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow