데이터 엔지니어링

패스트캠퍼스 환급챌린지 39일차: 데이터엔지니어링 초격차 강의 후기

Big Byte 2025. 5. 9. 23:31

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

파이썬 🐍! 함수(Functions)로 코드의 효율성과 재사용성을 높여보자! 🚀 (상)

 

안녕하세요, 여러분! ✨

지난 시간에는 파이썬의 연산자, 조건문, 반복문을 통해 프로그램의 '흐름'을 제어하는 방법을 익혔습니다. 🛠️🤔🔄 마치 요리의 기본 단계를 마스터한 것처럼, 우리는 이 도구들로 데이터를 가공하고, 원하는 순서대로 프로그램을 구성할 수 있게 되었습니다.

 

예를 들어, if user_level > 10: unlock_new_feature()처럼 특정 조건에 따라 다른 기능을 실행하거나, for item in shopping_cart: calculate_total(item)처럼 장바구니의 모든 상품을 처리하는 로직을 구현할 수 있게 되었죠. 👨‍💻👩‍💻

 

자, 이제 우리는 작성한 코드들을 더 깔끔하게 정리하고, 필요할 때마다 쉽게 재사용할 수 있는 방법을 배울 차례입니다. 마치 잘 정리된 '설계도'나 '표준 부품'처럼 말이죠. 바로 오늘 배울 함수(Functions)가 그 핵심입니다!

 

연산자, 조건문, 반복문이 개별적인 작업 지시였다면, 함수는 이러한 코드 조각들을 묶어 하나의 '독립적인 기능 단위' 또는 '효율적인 작업 도구'로 만드는 것과 같습니다. ⚙️

 

오늘 우리가 함께 살펴볼 파이썬 함수의 주요 내용은 다음과 같습니다:

  • 함수란 무엇일까? (What are Functions?) 🤔
  • 함수 만들기: 정의와 호출 (Defining and Calling Functions) ✍️
  • 반환값이 없는 함수 (Functions without Return Values) 📤➡️❌
  • 결과를 돌려주는 함수 (Functions with Return Values) 📤➡️🎁
  • 가변 인자 처리: *args와 **kwargs (Handling Variable Arguments: *args and **kwargs) 📦
  • 변수의 유효 범위: 함수 내 변수 선언 (Variable Scope) 🗺️🔍
  • 간결한 표현: 람다(Lambda) 함수 📏

자, 파이썬으로 더욱 구조적이고 효율적인 프로그램을 만들 준비, 되셨나요? 함께 시작해 봅시다! 🚀

 

함수란 무엇일까? (What are Functions?) 🤔

 

함수(Function)는 특정 작업을 수행하기 위해 미리 작성해 둔 코드 블록(code block)입니다. 마치 커피 머신을 생각해보세요. ☕ 원두와 물(입력값)을 넣고 버튼을 누르면(함수 호출), 맛있는 커피(결과)가 나오는 것처럼, 함수도 특정 입력값을 받아 정해진 작업을 수행하고 그 결과를 돌려줄 수 있습니다.

 

함수를 사용하는 주된 이유는 코드의 재사용성가독성 향상입니다.


동일한 코드를 여러 곳에서 반복적으로 작성하는 대신, 함수로 한 번 정의해두면 필요할 때마다 호출하여 사용할 수 있습니다. 이는 "반복하지 마라(Don't Repeat Yourself, DRY)" 원칙을 지키는 좋은 방법입니다. 또한, 복잡한 프로그램을 기능별로 함수로 나누면 전체 코드의 구조를 파악하기 쉬워지고 유지보수도 용이해집니다.

 

함수 만들기: 정의와 호출 (Defining and Calling Functions) ✍️


파이썬에서 함수를 정의할 때는 def 키워드를 사용합니다. "define"의 약자죠. 기본적인 구조는 다음과 같습니다:

def 함수이름(매개변수1, 매개변수2, ...):  # 콜론(:)으로 끝납니다.
    """
    이 함수는 어떤 기능을 수행하는지에 대한 설명입니다. (선택사항이지만, 권장됩니다 - '독스트링(docstring)')
    """
    # 함수가 수행할 코드들 (들여쓰기로 구분됩니다!)
    # ...
    return 결과값  # 결과값을 반환할 수도, 안 할 수도 있습니다.

간단한 인사 함수를 예로 들어보겠습니다:

def greet(name):
    """주어진 이름에 맞춰 인사말을 출력합니다."""
    print(f"안녕하세요, {name}님. 반갑습니다!")

# 함수 호출하기
greet("개발자")  # 출력: 안녕하세요, 개발자님. 반갑습니다!
greet("데이터 분석가")  # 출력: 안녕하세요, 데이터 분석가님. 반갑습니다!

greet라는 이름의 함수를 정의하고, name이라는 매개변수(parameter)를 받도록 했습니다. 함수를 호출할 때는 greet("개발자")와 같이 실제 값("개발자" - 이를 '인자(argument)'라고 합니다)을 전달합니다. 자바에서 메소드를 정의하고 호출하는 것과 유사한 개념입니다: public void greet(String name) { ... }. 파이썬은 타입 명시가 필수는 아니지만, 필요에 따라 타입 힌트를 사용할 수 있습니다.

 

반환값이 없는 함수 (Functions without Return Values) 📤➡️❌

모든 함수가 반드시 결과값을 반환해야 하는 것은 아닙니다. 위에서 만든 greet 함수처럼, 특정 동작만을 수행하고 종료되는 함수도 있습니다. 이러한 함수는 return 문을 생략하거나, return만 단독으로 사용하여 명시적으로 '아무것도 반환하지 않음'을 나타낼 수 있습니다. (엄밀히 말해, 파이썬에서 return이 없는 함수는 내부적으로 None이라는 특별한 값을 반환합니다.)

def print_operation_result(a, b, operation_name):
    """두 숫자의 연산 결과를 출력하는 함수 (반환값 없음)"""
    if operation_name == "덧셈":
        result = a + b
        print(f"{a} + {b} = {result}")
    elif operation_name == "곱셈":
        result = a * b
        print(f"{a} * {b} = {result}")
    else:
        print("지원하지 않는 연산입니다.")

print_operation_result(10, 20, "덧셈")  # 출력: 10 + 20 = 30
returned_value = print_operation_result(5, 3, "곱셈") # 함수는 실행되지만,
print(f"반환된 값: {returned_value}") # 출력: 반환된 값: None

print_operation_result 함수는 연산 결과를 화면에 출력할 뿐, 어떤 값을 직접 돌려주지는 않습니다.

 

 

결과를 돌려주는 함수 (Functions with Return Values) 📤➡️🎁

함수가 수행한 계산의 결과를 다른 곳에서 활용하고자 할 때는 return 키워드를 사용하여 값을 반환해야 합니다. 마치 자판기에 동전을 넣고 버튼을 누르면 원하는 음료수(결과)를 얻는 것과 같습니다.

def calculate_sum(a, b):
    """두 숫자를 더한 결과를 반환하는 함수"""
    total = a + b
    return total

sum_val = calculate_sum(100, 50)
print(f"100 + 50의 합계: {sum_val}") # 출력: 100 + 50의 합계: 150
print(f"calculate_sum(3, 7)의 결과: {calculate_sum(3, 7)}") # 출력: calculate_sum(3, 7)의 결과: 10

calculate_sum 함수는 ab를 더한 total 값을 return을 통해 함수를 호출한 지점으로 돌려줍니다. 이렇게 반환된 값은 변수에 저장하거나 다른 연산에 즉시 사용할 수 있습니다.

함수는 여러 값을 반환할 수도 있습니다. 이 경우, 값들은 튜플(tuple) 형태로 묶여서 반환됩니다.

def get_user_details():
    """사용자의 ID, 이름, 이메일 정보를 반환하는 함수"""
    user_id = "python_master"
    user_name = "홍길동"
    user_email = "hong@example.com"
    return user_id, user_name, user_email # (user_id, user_name, user_email) 튜플 반환

user_data = get_user_details()
print(user_data) # 출력: ('python_master', '홍길동', 'hong@example.com')

# 각 값을 개별 변수에 바로 할당 가능 (튜플 언패킹)
uid, name, email = get_user_details()
print(f"ID: {uid}, 이름: {name}, 이메일: {email}")
# 출력: ID: python_master, 이름: 홍길동, 이메일: hong@example.com

가변 인자 처리: *args와 **kwargs (Handling Variable Arguments: *args and **kwargs) 📦

함수를 호출할 때 전달되는 인자의 개수가 유동적일 경우가 있습니다. 이럴 때 *args**kwargs를 사용하면 유연하게 인자를 처리할 수 있습니다.

  1. *args (Arbitrary Positional Arguments): 여러 개의 위치 인자(positional arguments)를 튜플로 묶어서 받습니다.
    *는 "여기에 전달되는 모든 위치 인자들을 하나의 튜플로 모아줘!"라는 의미입니다. args는 관례적으로 사용되는 이름이며, 다른 이름(예: *numbers)을 사용해도 무방합니다.
    def sum_all_numbers(*numbers): # numbers는 튜플이 됩니다.
        total = 0
        for num in numbers:
            total += num
        return total
    
    print(f"1, 2, 3의 합: {sum_all_numbers(1, 2, 3)}")       # 출력: 1, 2, 3의 합: 6
    print(f"10, 20, 30, 40의 합: {sum_all_numbers(10, 20, 30, 40)}") # 출력: 10, 20, 30, 40의 합: 100
  2. **kwargs (Arbitrary Keyword Arguments): 여러 개의 키워드 인자(keyword arguments)를 딕셔너리로 묶어서 받습니다.
    **는 "여기에 전달되는 모든 '키워드=값' 형태의 인자들을 딕셔너리로 모아줘!"라는 의미입니다. kwargs 역시 관례적인 이름입니다 (예: **options).*args**kwargs는 일반 매개변수와 함께 사용할 수 있으며, 순서는 일반 매개변수, *args, **kwargs 순으로 정의해야 합니다.
     

변수의 유효 범위: 함수 내 변수 선언 (Variable Scope) 🗺️🔍

변수는 선언된 위치에 따라 접근할 수 있는 유효 범위(Scope)가 결정됩니다.

  • 지역 변수 (Local Variables): 함수 내부에서 선언된 변수는 해당 함수 내에서만 유효합니다. 함수 실행이 종료되면 해당 변수는 사라집니다. 특정 함수라는 '작업 공간' 안에서만 사용되는 도구와 같습니다.
  • 전역 변수 (Global Variables): 함수 외부, 즉 프로그램의 최상위 레벨에서 선언된 변수는 프로그램 전체에서 접근 가능합니다. 모든 작업 공간에서 참조할 수 있는 공유 자원과 같습니다.
app_version = "1.0" # 전역 변수

def display_settings():
    theme = "Dark Mode" # 지역 변수
    print(f"현재 테마: {theme}")
    print(f"앱 버전: {app_version}") # 함수 내에서 전역 변수 읽기 가능

display_settings()
# 출력:
# 현재 테마: Dark Mode
# 앱 버전: 1.0

print(f"전역 앱 버전: {app_version}") # 출력: 전역 앱 버전: 1.0
# print(theme) # 오류 발생! NameError: name 'theme' is not defined (지역 변수는 함수 외부에서 접근 불가)

함수 내에서 전역 변수와 동일한 이름의 변수를 선언하면, 해당 함수 내에서는 지역 변수로 취급됩니다(shadowing). 만약 함수 내에서 전역 변수의 값을 직접 수정하려면 global 키워드를 사용해야 하지만, 이는 코드의 흐름을 추적하기 어렵게 만들 수 있으므로 사용에 주의해야 합니다. 일반적으로 함수 외부의 상태를 변경하는 것보다는, 인자로 값을 받고 return으로 결과를 전달하는 방식이 권장됩니다.

 

간결한 표현: 람다(Lambda) 함수 📏

람다(Lambda) 함수는 이름 없이 한 줄로 간단하게 정의할 수 있는 익명 함수(anonymous function)입니다. lambda 키워드를 사용하며, 주로 다른 함수의 인자로 전달되거나, 일시적으로 간단한 기능을 수행할 때 유용합니다.

기본 구조: lambda 매개변수들: 표현식 (표현식의 결과가 반환됩니다)

# 일반 함수 정의
def add_ten(x):
    return x + 10

# 람다 함수 정의
lambda_add_ten = lambda x: x + 10

print(f"일반 함수 결과: {add_ten(5)}")           # 출력: 일반 함수 결과: 15
print(f"람다 함수 결과: {lambda_add_ten(5)}")    # 출력: 람다 함수 결과: 15

# 리스트 정렬 시 key 인자로 활용
data_points = [('A', 10), ('C', 5), ('B', 12)]
# 각 튜플의 두 번째 요소를 기준으로 정렬
sorted_data = sorted(data_points, key=lambda item: item[1])
print(f"두 번째 요소 기준 정렬: {sorted_data}") # 출력: 두 번째 요소 기준 정렬: [('C', 5), ('A', 10), ('B', 12)]

람다 함수는 복잡한 로직을 구현하기에는 한계가 있지만, 코드 라인을 줄이고 가독성을 높일 수 있는 간편한 기능입니다.

 

정리하며 📝

오늘은 파이썬에서 코드의 구조화와 재사용성을 크게 향상시키는 함수(Functions)에 대해 자세히 알아보았습니다. 🚀

  • 함수 (Functions) 🤔: 특정 작업을 수행하는 독립적인 코드 단위로, 코드 재사용성과 가독성을 높여줍니다. (잘 설계된 부품이나 도구와 같습니다.)
  • 함수 정의와 호출 (Defining and Calling Functions) ✍️: def 함수이름(매개변수): ... 형태로 정의하고, 함수이름(인자) 형태로 호출합니다.
  • 반환값 (Return Values) 📤➡️🎁/❌: return을 사용하여 결과를 반환하거나, 반환 없이 특정 동작만 수행할 수 있습니다. (return이 없으면 None 반환)
  • 가변 인자 처리 (*args / **kwargs) 📦: *args는 여러 위치 인자를 튜플로, **kwargs는 여러 키워드 인자를 딕셔너리로 받아 유연한 함수를 만듭니다.
  • 변수 유효 범위 (Scope) 🗺️🔍: 변수는 선언 위치(지역/전역)에 따라 접근 가능한 범위가 달라집니다.
  • 람다 함수 (Lambda Functions) 📏: lambda 키워드로 만드는 한 줄짜리 익명 함수로, 간결한 코드 작성에 유용합니다.

지난 시간에 배운 '기본 제어 구조(연산자, 조건문, 반복문)'들을 이제 '함수'라는 잘 정의된 '기능 블록'으로 묶어 사용할 수 있게 되었습니다. 이를 통해 여러분은 더욱 체계적이고, 효율적이며, 유지보수가 용이한 파이썬 프로그램을 작성할 수 있는 기반을 다진 것입니다! 🌟 잘 정의된 함수들을 활용하면 복잡한 문제도 단계별로 나누어 명확하게 해결할 수 있게 됩니다.

 

오늘도 정말 수고 많으셨습니다! 다음 시간에는 파이썬의 또 다른 강력한 기능들을 함께 탐험해 볼 예정이니 기대해주세요. 그때까지 모두 파이팅입니다! 👋

https://abit.ly/lisbva