programing

중첩 함수는 Python에서 어떻게 작동합니까?

nasanasas 2020. 12. 30. 08:14
반응형

중첩 함수는 Python에서 어떻게 작동합니까?


def maker(n):
    def action(x):
        return x ** n
    return action

f = maker(2)
print(f)
print(f(3))
print(f(4))

g = maker(3)
print(g(3))

print(f(3)) # still remembers 2

중첩 된 함수 는 시간 이 호출 될 때 반환되고 종료 2되었지만 첫 번째 값을 기억하는 이유는 무엇 입니까?maker()action()


부모 함수에서 시작된 모든 변수가 자식 함수 내부의 실제 값으로 대체되는 것을 볼 수 있습니다. 이렇게하면 자식 함수가 올바르게 실행되도록 부모 함수의 범위를 추적 할 필요가 없습니다.

"함수를 동적으로 생성"이라고 봅니다.

def maker(n):
  def action(x):
    return x ** n
  return action

f = maker(2)
--> def action(x):
-->   return x ** 2

이것은 파이썬의 기본 동작이며 여러 할당으로 동일합니다.

a = 1
b = 2
a, b = b, a

파이썬은 이것을 다음과 같이 읽습니다.

a, b = 2, 1

기본적으로 값을 삽입하기 전에 값을 삽입합니다.


기본적으로 클로저를 생성합니다 .

컴퓨터 과학에서 클로저는 어휘 환경에 묶여있는 자유 변수가있는 일류 함수입니다. 이러한 함수는 자유 변수에 "닫힌"다고합니다.

관련 자료 : 클로저 : 왜 그렇게 유용할까요?

클로저는 단순히 함수에 로컬 상태에 대한 액세스를 제공하는 더 편리한 방법입니다.

에서 http://docs.python.org/reference/compound_stmts.html :

프로그래머의 주 : 함수는 일류 객체입니다. 함수 정의 내에서 실행되는 'def'형식은 반환되거나 전달 될 수있는 로컬 함수를 정의합니다. 중첩 함수에 사용되는 자유 변수는 def를 포함하는 함수의 지역 변수에 액세스 할 수 있습니다. 자세한 내용은 이름 지정 및 바인딩 섹션을 참조하십시오.


두 가지 기능을 정의하고 있습니다. 전화 할 때

f = maker(2)

두 배의 숫자를 반환하는 함수를 정의하고 있으므로

f(2) --> 4
f(3) --> 6

그런 다음 다른 다른 기능을 정의합니다.

g = maker(3)

그 숫자의 세 배를 반환

g(3) ---> 9

그러나 그것들은 서로 다른 두 개의 함수이며, 참조 된 동일한 함수가 아닙니다. 각각은 독립적 인 함수입니다. 스코프 내부에서도 'maker'라는 함수는 동일하게 호출되며 동일한 함수가 아닙니다. 호출 maker()때마다 다른 함수를 정의합니다. 함수를 호출 할 때마다 동일한 이름을 사용하지만 다른 값을 포함 할 수있는 지역 변수와 같습니다. 이 경우 변수 'action'에는 함수가 포함됩니다 (다를 수 있음).


그것이 " 클로저 " 라고 불리는 것 입니다. 간단히 말해서, 함수를 일급 객체 로 취급하는 프로그래밍 언어는 전부는 아니더라도 대부분의 경우 함수 객체 내에서 사용되는 모든 변수는 함수가 아직 살아있는 한 둘러싸여 있습니다 (즉, 기억됩니다). 사용 방법을 안다면 강력한 개념입니다.

귀하의 예에서 중첩 action함수는 변수를 사용 n하므로 해당 변수 주변에 클로저를 형성하고 나중에 함수 호출을 위해이를 기억합니다.


내부 함수를 작성하는 세 가지 일반적인 이유를 살펴 보겠습니다.

1. 폐쇄 및 공장 기능

둘러싸는 범위의 값은 변수가 범위를 벗어나거나 함수 자체가 현재 네임 스페이스에서 제거 된 경우에도 기억됩니다.

def print_msg(msg):
    """This is the outer enclosing function"""

    def printer():
        """This is the nested function"""
        print(msg)

    return printer  # this got changed

이제이 함수를 호출 해 봅시다.

>>> another = print_msg("Hello")
>>> another()
Hello

이례적인 일입니다. print_msg()함수는 문자열로 불렸다 "Hello"하고 반환 된 함수는 이름에 바인드되었다 another. 을 호출 another()할 때 이미 print_msg()함수 실행을 완료했지만 메시지는 여전히 기억되었습니다 . 일부 데이터 ( "Hello")가 코드에 첨부 되는이 기술을 Python에서 클로저라고합니다.

클로저를 언제 사용합니까?

그렇다면 클로저는 무엇에 좋은가요? 클로저는 전역 값의 사용을 피할 수 있으며 데이터 숨김을 제공합니다. 또한 문제에 대한 객체 지향 솔루션을 제공 할 수 있습니다. 클래스에서 구현할 메서드가 거의 없을 때 (대부분의 경우 하나의 메서드) 클로저는 대체적이고 우아한 솔루션을 제공 할 수 있습니다. 참고

2. 캡슐화 :

General concept of encapsulation is to hide and protect inner world from Outer one, Here inner functions can be accessed only inside the outer one and are protected from anything happening outside of the function.

3. Keepin’ it DRY

Perhaps you have a giant function that performs the same chunk of code in numerous places. For example, you might write a function which processes a file, and you want to accept either an open file object or a file name:

def process(file_name):
    def do_stuff(file_process):
        for line in file_process:
            print(line)
    if isinstance(file_name, str):
        with open(file_name, 'r') as f:
            do_stuff(f)
    else:
        do_stuff(file_name)

For more you can refer this blog.


Because at the time when you create the function, n was 2, so your function is:

def action(x):
    return x ** 2

When you call f(3), x is set to 3, so your function will return 3 ** 2


People answered correctly about the closure, that is: the valid value for "n" inside action is the last value it had whenever "maker" was called.

One ease way to overcome this is to make your freevar (n) a variable inside the "action" function, which receives a copy of "n" in the moment it is run:

The easiest way to do this is to set "n" as a parameter whose default value is "n" at the moment of creation. This value for "n" stays fixed because default parameters for a function are stored in a tuple which is an attribute of the function itself (action.func_defaults in this case):

def maker(n):
    def action(x, k=n):
        return x ** k
    return action

Usage:

f = maker(2) # f is action(x, k=2)
f(3)   # returns 3^2 = 9
f(3,3) # returns 3^3 = 27

One use is to return a function that maintains a parameter.

def outer_closure(a):
    #  parm = a               <- saving a here isn't needed
    def inner_closure():
        #return parm
        return a              # <- a is remembered 
    return inner_closure

# set parm to 5 and return address of inner_closure function
x5 = outer_closure(5)
x5()
>5

x6 = outer_closure(6)
x6()
>6

# x5 inner closure function instance of parm persists 
x5()
>5

When you create a function with the def keyword, you are doing exactly that: you are creating a new function object and assigning it to a variable. In the code you gave you are assigning that new function object to a local variable called action.

WHen you call it a second time you are creating a second function object. So f points to the first function object (square-the-value) and g points to the second function object (cube-the-value). When Python sees "f(3)" it takes it to means "execute the function object pointed to be variable f and pass it the value 3". f and g and different function objects and so return different values.

ReferenceURL : https://stackoverflow.com/questions/2005956/how-do-nested-functions-work-in-python

반응형