부모 함수의 변수에 접근할 때 유의할 점

개발공부를해보자·2025년 1월 21일

공부 정리

목록 보기
15/33
  • 변수의 scope 개념이 확실하지 않아서

  • 함수를 중첩하여 사용할 때

  • 어떤 경우엔 부모 함수의 변수를 그냥 쓸 수 있고

  • 어떤 경우엔 그냥 쓰면 에러가 나서 왜 그런지 찾아보았다.

  • mutableimmutable을 구분하는 것이 핵심이었다.

  • mutable 예를들어 list는 값을 추가하거나 삭제하더라도 참조 ID는 유지되기 때문에 자식 함수에서 부모 함수의 mutable 변수를 접근하고 업데이트 할 수 있다.

  • immutable 변수는 그렇지 못하다. 새롭게 할당하게 되면 연결이 끊어진다. 부모 함수의 변수를 새로 할당하려면 nonlocal 선언을 해야한다. 아, 물론 mutable 변수도 업데이트가 아닌 새롭게 할당하면 마찬가지이다.

  • 그리고 nonlocalgloabal은 다르다. nonlocal은 바로 위 부모 함수를 범위로 한다.

  • 아래 내용은 GPT의 도움을 받아 정리한 내용이다.

부모 함수의 변수

# 중첩 함수에서 mutable(가변)과 immutable(불변)의 차이가 있는 이유:
# 1. 스코프 규칙: 중첩 함수에서 immutable 변수는 재할당 시 새로운 로컬 변수가 생성되며, 부모 변수와의 연결이 끊어짐. 
#    이를 해결하려면 `nonlocal` 키워드를 사용해야 함.
# 2. 참조 방식 차이: mutable 객체는 함수 내부에서 직접 수정이 가능하며, 부모 함수의 변수에 영향을 미침.
#    하지만 immutable 객체는 수정이 불가능하고 재할당해야 함.
# 3. 메모리 참조: mutable 객체는 부모 함수의 메모리 주소를 공유하므로 내부 요소 수정이 가능하지만, 
#    immutable 객체는 새로운 객체가 생성되므로 원래 변수가 변경되지 않음.

def outer_function():
    # immutable 변수 (불변 객체)
    num = 10  # 정수 (immutable)
    text = "hello"  # 문자열 (immutable)

    # mutable 변수 (가변 객체)
    lst = [1, 2, 3]  # 리스트 (mutable)
    dct = {'a': 1}  # 딕셔너리 (mutable)

    def inner_function():
        # 불변 객체 사용 시
        print("Before changing num:", num)  # Before changing num: 10
        print("Before changing text:", text)  # Before changing text: hello

        # num = num + 1  # 주석 해제 시 UnboundLocalError 발생
        # text = text + " world"  # 주석 해제 시 UnboundLocalError 발생

        nonlocal num  # 부모 함수의 불변 변수 재할당 시 필요
        num = num + 1  # 이제 정상 작동

        nonlocal text
        text = text + " world"  # 문자열 재할당 가능

        print("After changing num:", num)  # After changing num: 11
        print("After changing text:", text)  # After changing text: hello world

        # 가변 객체 사용 시
        print("Before modifying lst:", lst)  # Before modifying lst: [1, 2, 3]
        print("Before modifying dct:", dct)  # Before modifying dct: {'a': 1}

        lst.append(4)  # 부모 함수의 lst에 영향을 줌
        dct['b'] = 2  # 부모 함수의 dct에 영향을 줌

        print("After modifying lst:", lst)  # After modifying lst: [1, 2, 3, 4]
        print("After modifying dct:", dct)  # After modifying dct: {'a': 1, 'b': 2}

    inner_function()
    print("Final num:", num)  # Final num: 11
    print("Final text:", text)  # Final text: hello world
    print("Final lst:", lst)  # Final lst: [1, 2, 3, 4]
    print("Final dct:", dct)  # Final dct: {'a': 1, 'b': 2}

outer_function()

nonlocalgloabal

# nonlocal과 global의 차이점
# 1. nonlocal:
#    - 중첩 함수에서 부모 함수의 변수를 수정할 때 사용.
#    - 가장 가까운 부모 함수의 변수를 수정하며, 상위 함수에 해당 변수가 없으면 오류 발생.
#    - 함수 내부에서 immutable 객체(숫자, 문자열 등)를 재할당하려면 반드시 필요.
#
# 2. global:
#    - 함수 내부에서 전역 변수를 수정할 때 사용.
#    - 전역 범위의 변수를 직접 수정하며, 존재하지 않으면 새로운 전역 변수를 생성.

# 전역 변수
x = 100  # global 변수

def outer():
    x = 50  # 부모(outer) 스코프의 변수

    def inner():
        nonlocal x  # 가장 가까운 부모 함수(outer)의 x를 수정
        x = 20  # outer()의 x가 변경됨
        print("Inner x:", x)  # 출력: Inner x: 20

        global y  # 전역 변수를 선언
        y = 30  # 새로운 전역 변수 y 생성
        print("Inner y:", y)  # 출력: Inner y: 30

    inner()
    print("Outer x:", x)  # 출력: Outer x: 20 (nonlocal을 사용하여 변경됨)

outer()
print("Global x:", x)  # 출력: Global x: 100 (전역 x는 변경되지 않음)
print("Global y:", y)  # 출력: Global y: 30 (global로 인해 전역 변수가 생성됨)

# nonlocal 사용 예제 (immutable 변수)
def counter():
    count = 0  # 부모 스코프 변수

    def increment():
        nonlocal count
        count += 1  # nonlocal 없으면 에러 발생 (UnboundLocalError)
        print("Count:", count)  # 출력: Count: 1 (첫 번째 호출), Count: 2 (두 번째 호출)

    increment()  # 첫 번째 호출 -> 출력: Count: 1
    increment()  # 두 번째 호출 -> 출력: Count: 2

counter()

# global 사용 예제 (전역 변수 수정)
global_var = 10

def modify_global():
    global global_var
    global_var += 5  # 전역 변수 변경
    print("Global_var:", global_var)  # 출력: Global_var: 15

modify_global()

# 정리:
# - `nonlocal`은 가장 가까운 부모 함수의 변수를 수정할 때 사용.
# - `global`은 전역 변수를 수정하거나 새로 생성할 때 사용.
# - 불변(immutable) 객체는 nonlocal/global이 필요하며, 가변 객체는 참조를 통해 수정 가능.

nonlocal vs global 비교

구분nonlocalglobal
적용 범위가장 가까운 부모 함수의 변수전역 스코프의 변수
변수 위치함수 내부의 중첩된 범위모듈 전체(스크립트의 전역)
새로운 변수상위 스코프에 없으면 에러 발생전역에 없으면 새로 생성됨
사용 예시중첩 함수에서 부모 변수 조작전역 변수 수정 필요 시 사용
profile
개발 공부하는 30대 비전공자 직장인

0개의 댓글