AD JB Toolbox 01

Python 강좌 / 변수의 범위와 변경 가능한 객체의 동작 이해하기

변수의 범위는 이름을 어디에서 찾을지 정하고, 객체의 변경 가능성은 같은 값을 가리키는 이름 사이에 어떤 변화가 보일지 정합니다. 대입과 객체 변경을 구분하면 함수 호출 뒤 데이터가 뜻밖에 바뀌는 원인을 이해할 수 있습니다.

지역 이름과 외부 이름

함수 안에서 대입하는 이름은 별도 선언이 없다면 지역 변수로 취급됩니다. 함수에서 외부 값을 읽는 것과 외부 이름에 새 값을 대입하는 것은 다릅니다. 전역 변수에 의존하기보다 필요한 값을 인수로 받고 결과를 반환하면 테스트하기 쉽습니다.

관련 동작과 지원 조건은 변수의 범위와 변경 가능한 객체의 동작 이해하기 관련 공식 문서에서 확인할 수 있습니다.

global은 모듈 수준 이름, nonlocal은 바깥 함수의 이름 연결을 바꿀 때 사용합니다. 모든 상태 문제를 이 선언으로 해결하려 하지 말고 데이터 전달 구조를 먼저 검토합니다.

전체 예제와 실행 결과

별도의 실습 폴더에서 아래 파일을 UTF-8로 저장합니다. 가상환경을 선택한 터미널에서 python scope.py 명령으로 실행합니다. macOS·Ubuntu에서 가상환경을 사용하지 않는 경우 명령 이름을 python3으로 바꿉니다.

scope.py 파일의 전체 내용입니다.

def add_fee(items, fee):
    items.append(fee)

original = [3500, 8000]
alias = original
copy = original.copy()
add_fee(alias, 500)
print(original)
print(copy)

nested = [[1], [2]]
shallow = nested.copy()
shallow[0].append(9)
print(nested)

예상 결과는 다음과 같습니다.

[3500, 8000, 500]
[3500, 8000]
[[1, 9], [2]]

대입·얕은 복사·깊은 복사

alias = original은 같은 리스트를 가리키는 이름을 하나 더 만듭니다. copy()는 바깥 리스트를 새로 만들지만 내부 항목의 객체는 공유하는 얕은 복사입니다. 중첩 예제에서 안쪽 리스트가 같이 바뀌는 이유입니다.

copy.deepcopy는 내부 구조를 재귀적으로 복사하는 데 사용할 수 있으나 파일·연결·공유가 필요한 객체까지 무조건 독립 복제하는 만능 해결책은 아닙니다. 변경해야 하는 범위만 새로 구성하거나 불변 데이터 구조를 선택하는 편이 계약을 명확히 할 수 있습니다.

함수 계약에 변경 여부 드러내기

함수가 입력 리스트를 바꾸는지 문서와 이름에서 알 수 있게 합니다. 원본을 유지하는 함수라면 새 리스트를 반환하는 구현으로 바꿀 수 있습니다. 결과와 부수 효과를 모두 시험하지 않으면 반환값이 맞아도 원본 손상을 놓칠 수 있습니다.

  1. add_fee(copy, 100)을 호출해 original에는 100이 추가되지 않는지 확인합니다.
  2. 함수 안의 append를 items = items + [fee]로 바꾸면 외부 리스트가 그대로인지 확인합니다.
  3. 원래 코드로 되돌리고 바깥 객체와 내부 객체의 공유를 각각 설명합니다.
같은 카테고리의 다른 글
Python 강좌 / for·range·enumerate·zip으로 반복하기

Python 강좌 / for·range·enumerate·zip으로 반복하기

for·range·enumerate·zip의 용도를 비교합니다. 번호와 지출 항목을 함께 출력하며 범위의 끝 제외, zip의 길이 불일치와 반복 중 변경 문제를 확인합니다.

Python 강좌 / 튜플과 시퀀스 언패킹 이해하기

Python 강좌 / 튜플과 시퀀스 언패킹 이해하기

튜플 생성과 언패킹, 별표 수집과 값 교환을 익힙니다. 불변성의 범위와 항목 수 오류, 리스트·딕셔너리와의 선택 기준을 설명합니다.

Python 강좌 / 숫자 자료형과 연산: 정수·실수·형 변환

Python 강좌 / 숫자 자료형과 연산: 정수·실수·형 변환

int·float·Decimal의 차이와 나눗셈·형 변환을 설명합니다. 음수와 십진 소수 예제로 금액 계산에서 정확도를 선택하는 방법을 확인합니다.

Python 강좌 / 문자열 다루기: 인덱싱·슬라이싱·메서드·f-string

Python 강좌 / 문자열 다루기: 인덱싱·슬라이싱·메서드·f-string

문자열의 인덱싱·슬라이싱과 strip·split·join·f-string을 익힙니다. 원본이 변경되지 않는 특성과 CSV·SQL 처리에서 구분할 점을 설명합니다.

Python 강좌 / 딕셔너리로 키와 값 관리하기

Python 강좌 / 딕셔너리로 키와 값 관리하기

딕셔너리의 키·값 접근과 항목 갱신을 설명합니다. 분류별 지출 집계 예제로 get·items·정렬과 필수 키 누락 처리의 차이를 확인합니다.

Python 강좌 / Python이란? 특징과 활용 분야

Python 강좌 / Python이란? 특징과 활용 분야

Python의 역할과 활용 범위를 이해하고 소스 파일·터미널·인터프리터를 구분합니다. 간단한 합산 예제를 실행하며 강좌의 실습 방식을 익힐 수 있습니다.

Python 강좌 / 위치·키워드 인수와 기본값 사용하기

Python 강좌 / 위치·키워드 인수와 기본값 사용하기

위치·키워드·키워드 전용 인수와 기본값을 익힙니다. 변경 가능한 기본값의 공유 문제와 None 검사로 호출별 상태를 분리하는 방법을 설명합니다.

Python 강좌 / 리스트·딕셔너리·집합 컴프리헨션 사용하기

Python 강좌 / 리스트·딕셔너리·집합 컴프리헨션 사용하기

리스트·딕셔너리·집합 컴프리헨션의 변환과 필터를 비교합니다. 중복 키, 빈 결과와 부수 효과를 확인하며 일반 반복문과의 선택 기준을 익힙니다.

Python 강좌 / 변수·주석·입력과 출력으로 첫 프로그램 만들기

Python 강좌 / 변수·주석·입력과 출력으로 첫 프로그램 만들기

변수 대입과 주석, input·print의 역할을 익힙니다. 입력 문자열을 금액으로 변환하고 f-string으로 출력하며 잘못된 입력의 원인을 확인합니다.

Python 강좌 / 가변 인수와 언패킹: *args·**kwargs

Python 강좌 / 가변 인수와 언패킹: *args·**kwargs

*args·**kwargs의 수집과 호출 시 언패킹을 비교합니다. 금액 합산과 옵션 출력 예제로 중복 인수, 문자열 펼치기와 인터페이스 설계 기준을 설명합니다.