Загружаем каталог…
Загружаем каталог…
Python을 조금만 공부하다 보면 같은 코드를 여러 번 작성하게 된다. 처음에는 복사해서 붙여넣어도 되지만 코드가 커질수록 수정해야 할 장소가 늘어나고, 로직의 의도도 파악하기 어려워진다. 이 문제를 해결하는 핵심 도구가 함수, 모듈, 패키지 다. 이 글에서는 작은 코드 조각을 함수로 묶는 것부터 여러 파일로 프로그램을 분리하는 방법까지 정리한다. 함수가 필요한 이유 예를 들어 여러 주문의 할인 금액을 계산한다고 해보자. price = 50000 discount = price * 0.1 final_price = price - discount 비슷한 계산을 여러 곳에서 반복한다면 함수로 분리하는 편이 좋다. def calculate_discount_price(price, rate): discount = price * rate return price - discount 이제 필요한 곳에서 호출할 수 있다. result = calculate_discount_price(50000, 0.1) print(result) 함수의 핵심은 반복되는 로직에 이름을 붙여 재사용하는 것 이다. 함수 정의와 호출 함수는 def 로 정의한다. def greet(): print("안녕하세요.") 호출: greet() 매개변수와 인자 def greet(name): print(f"안녕하세요, {name}님.") 여기서 name 은 매개변수(parameter) 다. greet("kim") 호출할 때 전달한 "kim" 은 인자(argument) 다. 반환값 return def add(a, b): return a + b result = add(10, 20) print(result) return 을 만나는 순간 함수 실행도 종료된다. def validate_age(age): if age < 0: return False return True 반환값이 없으면 어떻게 될까? 명시적인 return 이 없는 함수는 None 을 반환한다. def print_message(): print("hello") result = print_message() print(result) 여러 값을 반환하기 Python에서는 여러 값을 쉼표로 나열해서 반환할 수 있다. def get_order_summary(): total_price = 82000 order_count = 4 return total_price, order_count 받을 때는 언패킹할 수 있다. total, count = get_order_summary() 실제로 반환되는 값은 튜플이다. 지역 변수와 스코프 함수 안에서 만든 변수는 기본적으로 함수 내부에서만 사용할 수 있다. def process(): message = "processing" print(message) process() 아래 코드는 오류가 난다. print(message) message 는 함수의 지역 변수이기 때문이다. 함수 밖의 값을 읽기 tax_rate = 0.1 def calculate_tax(price): return price * tax_rate 함수 내부에서 외부 값을 읽는 것은 가능하다. 하지만 외부 상태에 지나치게 의존하면 함수의 동작을 이해하기 어려워진다. 가능하면 필요한 값은 인자로 전달하는 편이 명확하다. def calculate_tax(price, tax_rate): return price * tax_rate global 은 신중하게 사용하자 request_count = 0 def increase_count(): global request_count request_count += 1 동작은 하지만 프로그램 규모가 커질수록 상태 변경 위치를 추적하기 어려워질 수 있다. 가능하면 값을 반환하고 외부에서 갱신하는 구조가 더 단순하다. def increase_count(count): return count + 1 request_count = 0 request_count = increase_count(request_count) 기본 인자 def request_api(timeout=3): print(f"timeout: {timeout}초") request_api() request_api(10) 변경 가능한 객체를 기본값으로 사용하지 말자 다음 코드는 예상치 못한 결과를 만들 수 있다. def add_item(item, items=[]): items.append(item) return items 기본값 객체는 함수가 호출될 때마다 새로 만들어지는 것이 아니라 함수 정의 시 한 번 만들어진다. 안전한 패턴은 None 을 사용하는 것이다. def add_item(item, items=None): if items is None: items = [] items.append(item) return items 키워드 인자 def create_user(name, age=20, active=True): return { "name": name, "age": age, "active": active, } user = create_user( name="kim", active=False, ) 매개변수 이름을 직접 지정하면 호출 코드를 읽었을 때 각 값의 의미가 분명해진다. *args 정해지지 않은 개수의 위치 인자를 받을 때 사용한다. def total(*numbers): return sum(numbers) print(total(10, 20, 30)) 함수 내부에서 numbers 는 튜플이다. **kwargs 정해지지 않은 개수의 키워드 인자를 받을 때 사용한다. def print_options(**options): for key, value in options.items(): print(key, value) print_options( timeout=3, retries=5, debug=True, ) options 는 딕셔너리다. 인자 언패킹 def add(a, b): return a + b numbers = [10, 20] print(add(*numbers)) 딕셔너리는 ** 를 사용한다. def create_user(name, age): return { "name": name, "age": age, } data = { "name": "lee", "age": 28, } user = create_user(**data) Docstring def calculate_total(prices): """주어진 가격 목록의 총합을 반환한다.""" return sum(prices) __doc__ 로 확인할 수 있다. print(calculate_total.__doc__) help() 도 docstring을 활용한다. help(calculate_total) 함수를 작게 만드는 이유 좋은 함수는 보통 하나의 분명한 역할을 가진다. 다음 함수는 너무 많은 일을 한다. def process_order(order): # 검증 # 할인 계산 # 결제 # 데이터베이스 저장 # 이메일 전송 ... 역할별로 분리하면 테스트와 수정이 쉬워진다. def validate_order(order): ... def calculate_order_total(order): ... def save_order(order): ... def send_order_email(order): ... 함수는 단순히 코드 줄 수를 줄이는 도구가 아니라 프로그램의 책임을 나누는 단위 다. 모듈이란? Python에서는 .py 파일 하나를 모듈로 사용할 수 있다. price_utils.py def calculate_discount(price, rate): return price * (1 - rate) 다른 파일에서 불러올 수 있다. import price_utils price = price_utils.calculate_discount(50000, 0.1) print(price) 함수 하나보다 더 큰 단위의 재사용이 필요할 때 모듈을 사용한다. import 가 하는 일 import math print(math.sqrt(16)) 모듈 내부의 이름은 마침표로 접근한다. math.sqrt math.pi 이 방식은 이름의 출처가 명확하다는 장점이 있다. from ... import ... from math import sqrt print(sqrt(16)) 간단하지만 같은 이름을 가진 함수가 많아질 경우 출처를 파악하기 어려울 수 있다. 대규모 코드에서는 다음처럼 명시적인 형태가 더 읽기 쉬운 경우가 많다. import math math.sqrt(16) import * 를 피하는 이유 from some_module import * 어떤 이름이 현재 네임스페이스에 들어왔는지 코드만 보고 판단하기 어려워진다. 이름 충돌 가능성도 커진다. __name__ == "__main__" Python 파일은 직접 실행할 수도 있고 다른 파일에서 import할 수도 있다. 두 상황을 구분할 때 다음 패턴을 자주 사용한다. def main(): print("프로그램 실행") if __name__ == "__main__": main() 직접 실행하면 main() 이 호출된다. python app.py 하지만 다른 파일에서 import하면 자동 실행되지 않는다. import app 모듈 검색 경로 sys.path import sys for path in sys.path: print(path) ModuleNotFoundError 가 발생했을 때 중요한 확인 포인트다. dir() 와 help() import math print(dir(math)) help(math.sqrt) 인터넷 검색 없이도 실행 환경 안에서 객체의 기본 정보를 확인할 수 있다. 패키지란? 프로젝트가 커지면 모듈도 많아진다. 이때 여러 모듈을 디렉터리 단위로 묶어 관리하는 구조가 패키지 다. my_app/ main.py services/ __init__.py user_service.py order_service.py utils/ __init__.py date_utils.py price_utils.py main.py 에서는 다음처럼 사용할 수 있다. from services.user_service import create_user from utils.price_utils import calculate_discount __init__.py 는 항상 필수일까? 과거에는 패키지 디렉터리에 __init__.py 가 반드시 필요했다. 현재 Python에는 namespace package 도 있기 때문에 모든 상황에서 필수는 아니다. 하지만 일반 애플리케이션 프로젝트에서는 패키지 경계를 명확하게 보여주고 초기화 코드를 둘 수 있다는 이유로 여전히 흔하게 사용된다. __pycache__ 와 .pyc 모듈을 실행하거나 import하면 디렉터리에 다음과 같은 폴더가 생길 수 있다. __pycache__/ 그 안에는 바이트코드 캐시인 .pyc 파일이 생성될 수 있다. 직접 수정할 파일은 아니다. Git 저장소에서도 일반적으로 제외한다. __pycache__/ *.pyc 표준 라이브러리와 외부 패키지 내장 기능 별도의 import 없이 사용 가능하다. len() print() sum() range() 표준 라이브러리 Python과 함께 제공되지만 import가 필요하다. import json import pathlib import datetime 외부 패키지 별도 설치가 필요하다. python -m pip install requests import requests 프로젝트 구조 예제 order_app/ main.py services/ __init__.py order_service.py utils/ __init__.py price.py utils/price.py def calculate_total(prices): return sum(prices) services/order_service.py from utils.price import calculate_total def create_order(prices): total = calculate_total(prices) return { "items": len(prices), "total": total, } main.py from services.order_service import create_order def main(): order = create_order([12000, 8000, 30000]) print(order) if __name__ == "__main__": main() 함수와 모듈을 나누는 기준 같은 코드가 두 번 이상 반복되는가? 하나의 코드 블록에 명확한 이름을 붙일 수 있는가? 함수가 한 가지 역할보다 너무 많은 일을 하는가? 한 파일에 서로 다른 책임의 함수가 너무 많이 모여 있는가? 다른 프로젝트에서도 다시 사용할 가능성이 있는가? 이 질문 중 여러 개에 해당한다면 함수나 모듈 분리를 고려해볼 수 있다. 핵심 정리 함수는 반복되는 로직을 이름 붙여 재사용하는 가장 기본적인 단위다. 매개변수와 반환값을 명확하게 만들수록 함수의 의존성이 줄어든다. 기본 인자에는 리스트나 딕셔너리 같은 변경 가능한 객체를 직접 두지 않는 것이 안전하다. *args , **kwargs 는 가변 개수의 인자를 다룰 때 사용한다. .py 파일 하나는 하나의 모듈이 될 수 있으며 import 로 재사용할 수 있다. __name__ == "__main__" 패턴을 이용하면 직접 실행과 import 상황을 구분할 수 있다. 여러 모듈이 모이면 패키지 단위로 구조화할 수 있다. dir() , help() , sys.path 를 알면 Python 객체와 import 문제를 스스로 탐색하기 쉬워진다.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
Python 함수, 모듈, 패키지까지 코드 재사용 구조 이해하기. Python을 조금만 공부하다 보면 같은 코드를 여러 번 작성하게 된다. 처음에는 복사해서 붙여넣어도 되지만 코드가 커질수록 수정해야 할 장소가 늘어나고, 로직의 의도도 파악하기 어려워진다. 이 문제를 해결하는 핵심 도구가 함수, 모듈, 패키지 다. 이 글에서는 작은 코드 조각을 함수로 묶는 것부터 여러 파일로 프로그램을 분리하는 방법까지 정리한다. 함수가 필요한 이유 예를 들어 여러 주문의 할인 금액을 계산한다고 해보자. price = 50000 discount = price * 0.1 final_price = price - discount 비슷한 계산을 여러 곳에서 반복한다면 함수로 분리하는 편이 좋다. def…
Открыть источник