Python 의 global과 nonlocal 키워드 사용법

JeBread·2024년 6월 11일
0

프로그래머스 70129. 이진 변환 반복하기 문제를 풀 때 재귀함수를 사용하다가 nonlocal 키워드를 사용하며 기록해두고 싶어 포스팅했습니다.

🔎 변수의 범위(scope)

globalnonlocal 키워드에 대해서 이해하려면 먼저 변수의 범위(scope)에 대한 개념을 간단히 짚고 넘어가야할 것 같습니다.

비단 파이썬 뿐만 아니라 대부분의 프로그래밍 언어에서 변수의 범위라는 것은 해당 변수를 어디에서 선언하느냐에 따라서 결정이 됩니다. 아주 단순하게 두 구역으로 나누면 함수 외부를 전역(global/module) 범위라고 하고, 함수 내부를 지역(local/function) 범위라고 합니다. 또한 함수를 중첩했을 때 외부 함수와 내부 함수의 사이에서 생겨나는 비지역(nonlocal/enclosing) 범위라는 것도 있습니다.

# outer(), inner() 함수 입장에서 전역(global) 범위
def outer():
    # outer() 함수 입장에서 지역(local) 범위
    # inner() 함수 입장에서 비지역(nonlocal) 범위
    def inner():
        # inner 함수 입장에서 지역(local) 범위

같은 범위 내에서는 자유롭게 변수에 접근이 가능하지만 다른 범위에서 선언된 변수에 접근할 때는 정해진 제약을 따르게 되는데요. 기본적으로 바깥 쪽 범위 내에서 선언된 변수를 안 쪽 범위에서는 접근할 수 있지만, 반대로 안 쪽 범위 내에서 선언된 변수를 바깥 쪽 범위에서 접근하는 것은 불가능합니다. 예를 들어, outer() 함수 밖에서 선언한 전역 변수는 outer() 함수 내부와 inner() 함수 내부에서 접근이 가능합니다. 하지만 outer() 함수 안에서 안에서는 선언한 outer() 함수 외부에서는 접근할 수 없으며, outer() 함수와 inner() 함수 안에서는 접근 가능이 가능합니다.

global_var = "전역 변수"
print(global_var) # 가능

def outer():
    nonlocal_var = "비전역 변수"
    print(global_var) # 가능
    print(nonlocal_var) # 가능

    def inner():
        local_var = "지역 변수"
        print(global_var) # 가능
        print(nonlocal_var) # 가능
        print(local_var) # 가능

    print(local_var) # 불가능 (NameError: name 'local_var' is not defined)

print(nonlocal_var) # 불가능 (NameError: name 'nonlocal_var' is not defined)
print(local_var) # 불가능 (NameError: name 'local_var' is not defined)

🎈 Variable Shadowing

변수의 범위의 다른 중요한 특성은 서로 다른 범위에서는 변수 이름 충돌이 발생하지 않으며 안 쪽 범위에서 바깥 쪽 범위에서 선언된 변수와 똑같은 이름의 변수를 생성할 수 있다는 것입니다. 예를 들어, 아래에 선언된 3개의 var 변수는 이름만 같을 뿐 서로 다른 값을 저장할 수 있는 엄연히 다른 변수입니다.

var = "전역 변수"
print(var)

def outer():
    var = "비지역 변수"
    print(var)

    def inner():
        var = "지역 변수"
        print(var)

    inner()

outer()
## 출력 결과
전역 변수
비지역 변수
지역 변수

🎯 global 키워드

함수 안에서 변수 앞에 global 키워드를 붙여주면 해당 변수는 함수 내에서 값을 변경하더라도 새로운 지역 변수가 되지 않고 함수 밖에서 이미 선언된 전역 변수를 가리키게 됩니다.

num = 0

def change_num():
    global num
    num = 100
    print(num)

change_num()

print(num)
## 출력 결과
100
100

🎯 nonlocal 키워드

nonlocal 키워드도 global 키워드와 같이 동일한 이름의 새로운 변수가 생성되는 것을 방지하기 위해서 사용됩니다. 이 두 키워드의 차이점은 global 키워드는 일반 함수 내에서 전역(global/module) 변수를 대상으로 사용하는 반면에 nonlocal 키워드는 중첩 함수 내에서 비지역(nonlocal/closing) 변수를 대상으로 사용한다는 것입니다.

def print_num():
    num = 0

    def change_num():
        nonlocal num
        num = 100
        print(num)

    change_num()

    print(num)

print_num()
## 출력 결과
100
100

변수 앞에 nonlocal 키워드를 붙여주면 해당 변수는 중첩 함수 내에서 값을 변경하더라도 새로운 지역 변수가 되지 않고 함수 밖에서 이미 선언된 비전역 변수를 가리키게 됩니다.

✨ 이진 변환 반복하기 나의 풀이

def solution(s):
    ans = []
    total = 0   # 이진 변환의 횟수
    ln = 0   # 길이 담아줄 변수
    cnt = 0   # 제거된 모든 0의 개수 담을 변수
    
    def replay(st):
        nonlocal cnt, total
        if st == "1":  # 최종 탈출 조건
            return
             
        for x in st:   # 제거할 0의 개수 세기
            if x == "0":
                cnt += 1
                
        st = st.replace("0","")   # 0 제거
        st = bin(len(st))[2:]     # 길이 담아주기
        total += 1                # 이진 변환 횟수 증가
        ln = len(st)
        replay(st)             # 재귀
        
    replay(s)
    
    ans.append(total)
    ans.append(cnt)
    return ans

0개의 댓글