ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Variable Scope
    언어/파이썬 2021. 1. 30. 14:48

    파이썬에서 변수의 scope에 대해서 궁금한게 계속 쌓인 상태였다.

    이번기회에 확실히 정리 하는게 좋을 것 같다고 생각하여 정리 하고자 한다. 

     

    스코핑 룰 

    변수의 생존범위에 관련도니 규칙이다. 파이썬에서의 함수는 별도의 namespace를 가지며, 이 namespace라는 것은 말 그대로 이름이 모여있는 공간을 의미한다. 예를 들어서 변수를 선언하면 그 변수의 이름이 namespace에 생성된다. 파이썬에서 변수명을 가지고 값을 얻어낼 수 있던 것은 사실 이름공간에 있는 이름을 가지고 특정 객체에 접근하여 얻어오는 것이었다. 

     

    scope of various variable

    namespace는 위처럼 총 3가지의 공간으로 나뉜다. 함수 내부의 공간은 지역(local) 영역이라 하고, 함수 외부의 공간은 전역(Global) 영역이라고 하고, 파이썬 자체에서 정의된 공간은 내장(built-in) 영역이라고 할 수 있다. 여기서 이름을 검색하는 규칙은 지역,전역,내장 순서로 검색하게 된다.

     

    순서

    첫번째 sum은 내장함수 그 자체임을 의미하고 2번째는 global namespace에 저장된 sum을 의미하고 3번째는 함수내에 선언된 sum즉 local namespace에 저장된 것을 의미한다.  만약 내가 여기서 sum에 1을 더하고 싶으면 어떻게 하면 될까?

     

    당연히 sum+=1 을 생각하겠지만 내부 namespace에는 sum이 선언된 적이 없기 때문에 sum에 1을 더할 수가 없다.

    이럴 때는 "내가 탐색하려고 하는것은 global에 있는 sum이야" 를 미리 알려주어 함수 안에 global sum 을 쓰고 연산을 진행하면 된다.

     

    이제 여기서 조금 더 복잡하게 closure라는 개념이 있다. 함수를 둘러싼 환경(지역변수, 코드 등)을 계속 유지하다가, 함수를 호출할 때 다시 꺼내서 사용하는 함수를 클로저(closure)라고 한다.

    파란색 점선 부분이 클로저이다.

     

    우선 밑의 예제를 보자.

     

    start_at의 매개변수로 1과 2를 각각 넣었고 closure 1과 2에는 각각 함수 객체가 담기는 것을 예상할 수 있다. 여기서 외부 함수인 start_at의 역할이 끝남과 동시에 매개변수 x의 값도 메모리상에서 사라지는것이 아닐까? 라는 생각을 할 수 있다. 하지만 내부 함수인 increment_by 외부 함수에는 사용된 변수 x의 값을 그대로 기억하고 있다. 

     

    이런 행동을 하는 함수를 클로저라고 부른다. 클로저는 내부 함수가 메모리에는 존재하지 않는 경우에도, 호출될 때 주변 환경을 기억한다. 외부 함수인 start_at과 함께 매개변수 x도 사라졌지만 내부 함수에 쓰인 x에는 우리가 호출할 때 외부 함수로 넘겨줬던 값이 묶였다. 

    x 확인

    위와 같이 __closure__ 멤버로 직접 확인해볼 수 있다. 자유 변수란 '코드 영역에서 사용되지만 전역 변수도 아니며 그 영역 내에서도 정의하지 않는 변수' 를 말한다. 파이썬 셀 객체는 클로저의 자유변수를 저장하기 위해 사용된다. 

     

     

    여기서는 함수 inner를 기준으로 b가 자유변수라고 할 수 있다. inner의 코드 영역에서는 a는 전역 변수이며 c는 지역변수인데 변수 b는 함수 inner 내부에서 정의된것이 아니기 때문이다. 

     

    마지막으로 nonlocal에 대해 알아보자

     

    중첩 함수의 관계에서, 내부 함수가 외부 함수의 지역 변수의 값을 다시 할당하려고 하면 어떻게 해야 할까? 

     


    이렇게 하면 될것 같지만 이러면 UnboundLocalError: local variable 'a' referenced before assignment를 만나게 된다. 내부 함수에서 외부 함수의 지역변수인 a를 못찾고 있다는 이야기다. 이러한 문제를 해결하기 위해서는 a를 아래와 같이 nonlocal로 선언하면 된다 .

     

     

     

    위와 같이 nonlocal로 선언하면 가장 가까이서 둘러싸는 함수 영역에서 주어진 이름을 찾는다. 

     

     

     

     

     

     

    '언어 > 파이썬' 카테고리의 다른 글

    __init__.py 톺아보기  (0) 2023.08.12
    bisect  (0) 2021.03.08
    중첩 함수(Nested Function)  (0) 2021.01.24
    가변객체 불변객체  (0) 2021.01.24
    파이썬은 왜 느릴까?  (0) 2021.01.21

    댓글