[포스코 신재생에너지 IoT 개발자 5기] Python 12편 — 함수(하)

Doohee·2025년 11월 29일
post-thumbnail

파이썬 함수의 실행 모델과 관련된 심화 개념을 정리한다.

함수 호출 시 이름 탐색 규칙(LEGB), 전역·지역 스코프 처리,

객체 참조 기반 인자 전달 방식, 재귀 구조, 람다 표현식 등을 중심으로 정리한다.

하편에서는 함수 내부 동작 원리와 실행 환경을 명확하게 이해하기 위해 다음 항목을 다룬다.

  • LEGB 규칙에 따른 스코프 탐색 과정

  • 전역 상태 수정(global)과 중첩 스코프 수정(nonlocal)

  • 재귀 함수 구조 및 적용 사례

  • 람다 표현식과 map/filter/sorted 활용

  • 데이터 처리용 실무 함수 패턴

함수의 실행 메커니즘까지 포함한 실무적 함수 사용 능력을 목표로 한다.

1. 변수의 유효 범위(Scope)와 전역변수

1) 스코프(Scope)와 LEGB Rule

  • Scope: 어떤 이름(변수, 함수)을 참조할 수 있는 코드의 범위

  • 파이썬의 이름 탐색 순서 - LEGB 룰

    • L - Local: 현재 함수 내부

    • E - Enclosing: 내포된 바깥 함수의 스코프

    • G - Global: 모듈(파일) 단위 최상위

    • B - Built-in: 파이썬이 제공하는 내장 이름들 (len, sum 등)

2) 메모리 관점 (스택 / 힙)

  • 스택(Stack) 영역: 지역변수, 매개변수 등이 저장되는 공간

  • 힙(Heap) 영역: 파이썬에서 생성되는 모든 객체(숫자, 문자열, 리스트, 딕셔너리, 인스턴스 등)가 저장되는 공간

3) 지역 변수

  • 함수 내부에서 선언된 변수

  • 함수가 호출될 때 생성되고, 함수가 끝나면 소멸

func_26

⇒ message는 greet() 함수 내부에서만 유효함

⇒ 함수 바깥에서 접근 시 NameError 발생

4) 전역 변수

  • 함수 외부(모듈 최상단)에서 선언된 변수

  • 모듈 전체에서 접근 가능(단, 함수 내부에서 수정은 주의)

func_27

5) 전역 변수 수정 시 문제와 global

⇒ 함수 내에서 x = x + 5로 할당하려는 순간 파이썬은 x를 지역 변수로 간주

⇒ 하지만 할당 전에 값을 참조하려고 했기 때문에 UnboundLocalError 발생

func_28

  • global 키워드 사용: 함수 내부에서 전역 변수 수정이 필요할 때

func_29

  • global 키워드의 주의점

    • 전역 상태를 남발하면 코드가 읽기 어렵고 버그가 많아진다.

    • 가능하면 전역변수는 읽기 전용으로 사용하고, 값 변경은 매개변수 / 반환값으로 전달하는 패턴을 권장

6) nonlocal 키워드

  • 중첩 함수(함수 안의 함수)에서 바깥 함수의 지역 변수를 수정해야 할 때 사용

func_30

실습1. 전역 변수 연습하기

⇒ 이 실습은 전역 상태 관리와 global 키워드의 동작 방식을 익히기 위한 기본 예제이다.

문제) 로그인 / 로그아웃 전역 상태 관리

  • 전역 변수로 로그인한 사용자 저장 및 로그아웃 기능을 구현해 봅시다.

  • 전역 변수 current_user는 로그인한 사용자의 이름을 저장합니다.

  • login(name) 함수는 사용자를 로그인시키고, logout() 함수는 로그아웃 상태로 만듭니다.

  • 이미 로그인된 상태에서 다시 로그인하면 "이미 로그인되어 있습니다."를 출력합니다.

  • 로그아웃하지 않고, 로그인을 여러 번 시도할 수 없도록 합니다.

func_31

2. 재귀 함수

1) 재귀 함수란?

  • 자기 자신을 다시 호출하는 함수

  • 반복문 없이 특정 작업을 반복 수행할 수 있음

  • 재귀는 수학과 프로그래밍에서 흔한 개념이며, 함수가 자기 자신을 호출하는 것을 의미한다.

2) 재귀 함수의 기본 구조

func_32

  • 함수가 자기 자신을 호출하면서 문제를 더 작은 문제로 분해

  • 기본조건(Base Case)을 만족할 때까지 재귀 호출을 반복한다.

  • 기본조건을 만나면 재귀가 멈추고, 반환 값이 역순으로 쌓이며 계산이 끝난다.

  • Base Case 없이 재귀를 쓰면 ⇒ 무한 재귀스택 오버플로(stack overflow) 발생

func_33

3) 재귀 함수의 장점

  • 코드 간결성, 구조적 문제 표현에 용이

func_34

4) 재귀 함수의 단점

  • 성능 저하 가능, 깊은 호출 시 RecursionError 발생

func_35

5) 재귀 함수와 반복문 비교

func_36

실습2. 재귀 함수 연습하기

⇒ 재귀 호출의 base case와 호출 스택 흐름을 시각적으로 이해하는 데 적합한 예제이다.

문제1) 거듭 제곱

  • 자연수 ab가 주어졌을 때, ab제곱을 계산하는 재귀 함수를 만들어 봅시다.

func_37

문제2) 팩토리얼(Factorial)

  • 먼저 반복문을 활용하여 팩토리얼을 구현합니다.

func_38

  • 1번을 바탕으로 작동 원리를 파악하고, 재귀 함수를 이용해서 팩토리얼을 구현합니다.

  • 디버거를 이용해 재귀 함수의 작동을 확인합니다.

func_39

문제3) 피보나치 수열(Fibonacci Numbers)

  • 먼저 반복문을 활용해서 피보나치 수열을 구현합니다.

func_40

  • 1번을 바탕으로 작동 원리를 파악하고, 재귀 함수를 이용해서 피보나치 수열을 구현합니다.

func_41

3. 람다 함수

1) 정의

  • 이름 없이 정의되는 익명 함수

  • 간단한 연산을 한 줄로 표현할 때 사용

  • lambda 라는 이름은 수학에서 함수 정의를 표현하는 방식인 λ-계산법(Lambda Calculus)에서 유래했다.

2) 문법 특징

  • lambda 키워드로 시작

  • 함수 이름이 없다.

  • 람다에서는 문장을 사용할 수 없으며, 표현식(expression)만 사용할 수 있다.

    즉, return, 할당문, 제어문은 람다 내부에 포함될 수 없다.

  • 표현식의 결과가 자동으로 반환된다. (return 키워드 없음)

func_42

3) 일반 함수 VS 람다 함수

func_43

  • 코드 예시

func_44

4) 람다 함수 사용 예제

  • 매개변수가 1개인 람다 함수

func_45

  • 매개변수가 2개인 람다 함수

func_46

  • map(function, iterable) ⇒ iterable의 각 요소에 function을 적용한 결과를 반환

  • filter(function, iterable) ⇒ iterable의 요소 중 function의 조건을 만족하는 것만 남김

func_47

  • sorted와 함께 사용 ⇒ sorted함수의 key에는 각 요소에 대해 정렬 기준이 될 값을 반환하는 함수를 넣을 수 있음

func_48

5) 람다 함수 사용 시 주의 사항

  • 문장 사용 금지

    • return, if, for 문 등을 그대로 쓸 수 없음

    • 복잡한 조건 / 로직이 필요하면 일반 함수(def)로 작성하는 것이 좋다.

  • 디버깅 어려움

    • 이름이 없어서 에러 메시지 분석이 어렵다.
  • 남용 금지

    • 한 줄로 안 예쁘게 우겨넣으면 가독성 급격히 하락

    • 짧고 단순한 연산 정도에서만 활용

실습3. 람다 함수 연습하기

문제1) 특정 조건을 만족하는 튜플만 추출

  • 아래 학생 튜플 리스트에서 평균 점수가 70점 이상인 학생만 추출하세요.

  • students = [("Alice", [80, 90]), ("Bob", [60, 65]), ("Charlie", [70, 70])]

func_49

✔ 출력 결과

[('Alice', [80, 90]), ('Charlie', [70, 70])]

문제2) 키워드 추출 리스트 만들기

  • 아래와 같은 문자열 리스트가 있을 때, 각 문장에서 맨 앞 단어만 추출한 리스트를 만들어보세요.

  • sentences = ["Python is fun", "Lambda functions are powerful", "Coding is creative"]

func_50

✔ 출력 결과

['Python', 'Lambda', 'Coding']

문제3) 튜플 리스트를 정렬하기

  • 이름과 나이로 구성된 튜플 리스트를 나이를 기준으로 오름차순 정렬하세요

  • people = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]

func_51

✔ 출력 결과

[('Bob', 25), ('Alice', 30), ('Charlie', 35)]

4. 실무 예시

예제1) 전력 사용량 로깅 시스템(지역변수 / 전역변수)

  • 상황: 건물에서 시간대별 전력 사용량을 받아 로그로 저장하는 기능

    • 전역변수: 전체 누적 로그 저장

    • 지역변수: 한 번의 측정값을 log_entry로 임시 구성

func_52

✔ 실무 포인트

  • 실시간 전력 로깅 구조

  • 지역변수 / 전역변수 사용 의도가 매우 명확

  • BEMS·스마트미터 데이터 수집 흐름과 거의 동일함

예제2) 센서 데이터 전처리(람다 함수 + map / filter)

  • 상황: IoT 센서에서 들어오는 데이터 중 숫자만 정규화하고, 잘못된 값(N/A, None 등)은 제거하는 과정

func_53

✔ 실무 포인트

  • 에너지 데이터 분석에서 가장 자주 나오는 패턴

  • 센서 장애 ⇒ N/A 처리

  • 문자열 숫자 변환 ⇒ float 필수

  • 람다 + map + filter = 데이터 전처리 최적 조합

예제3) 누진세 전기요금 계산(재귀 함수)

  • 상황: 전기요금은 단계별로 단가가 다름 ⇒ 재귀로 계산 구조 깔끔하게 구현 가능

func_54

✔ 실무 포인트

  • 냉난방 에너지 비용 예측 모델 기초

  • BEMS 운영 데이터와 요금 계산 로직에 사용 가능

  • 단계별 구간 처리를 재귀 함수가 직관적으로 표현함

5. 함수(하) 한눈에 보기

  • 인자 전달 방식: 파이썬은 객체 참조를 전달하며, mutable 객체는 원본이 수정될 수 있음.

  • 스코프 규칙(LEGB): Local → Enclosing → Global → Built-in 순서로 변수를 탐색함.

  • 전역 상태 관리: global은 모듈 전역 변수 수정, nonlocal은 중첩 함수의 상위 스코프 변수 수정에 사용된다.

  • 재귀 함수 구조: Base Case가 필수이며, 문제를 더 작은 단위로 분해해 자기 자신을 호출함.

  • 재귀 활용 패턴: 거듭제곱, 팩토리얼, 피보나치 수열 같은 구조적 반복 처리에 효과적.

  • 람다 표현식: 한 줄 표현식 기반 익명 함수로, map / filter / sorted 와 조합해 사용됨.

  • 실무 적용 함수: 데이터 필터링, 구간 통계 처리, 요금 계산 등 반복 업무 패턴을 함수로 모듈화함.

6. 아웃트로

하편에서는 함수 실행 모델 전반을 구성하는 스코프, 전역 상태 관리, 재귀 구조, 람다 표현식 등의 핵심 요소를 정리했다.
이 내용을 통해 함수 단위 로직이 실행되는 방식과 상태 변화가 코드에 미치는 영향을 명확하게 파악할 수 있다.

다음 문서에서는 함수를 모듈 단위로 확장하는 과정(모듈 구성, 파일 분리, import 체계 설계)을 다루며,
이를 통해 프로그램 구조화를 이어간다.

profile
에너지 기획 전문가로 성장하고자 합니다.

0개의 댓글