코드가 길어질수록 같은 작업을 반복해서 작성하기보다 기능을 함수로 분리하고 입력과 출력을 명확하게 만드는 것이 중요하다.
이 글에서는 함수의 기본 구조부터 사용자 입력, 파일 처리, 명령행 인자까지 연결해서 정리한다.
주문 금액의 부가세를 여러 곳에서 계산한다고 해보자.
price = 50000
tax = price * 0.1
같은 계산을 반복한다면 함수로 분리할 수 있다.
def calculate_tax(
price,
rate=0.1,
):
return price * rate
사용:
tax = calculate_tax(
50000
)
함수는 반복 코드를 줄이는 것뿐 아니라 코드의 역할에 이름을 붙이는 도구다.
def greet():
print("안녕하세요.")
호출:
greet()
def greet(name):
print(
f"안녕하세요, "
f"{name}님."
)
여기서 name은 매개변수다.
greet("kim")
호출할 때 전달한 "kim"은 인자다.
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)
def get_summary():
total = 120000
count = 5
return total, count
total, count = (
get_summary()
)
실제로는 튜플이 반환된다.
def request_api(
timeout=3,
):
print(
f"timeout: "
f"{timeout}초"
)
request_api()
request_api(10)
다음 코드는 피하는 것이 좋다.
def add_item(
item,
items=[],
):
items.append(item)
return items
기본 리스트가 호출 사이에 공유될 수 있다.
안전한 형태:
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,
)
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
)
함수 안의 변수는 기본적으로 함수 내부에서만 사용할 수 있다.
def process():
message = "processing"
print(message)
함수 밖에서 message를 직접 사용할 수 없다.
외부 상태를 변경하기보다 필요한 값을 인자로 받고 결과를 반환하는 구조가 이해하기 쉽다.
input()name = input(
"이름: "
)
print(
f"안녕하세요, "
f"{name}님."
)
input()의 결과는 문자열이다.
숫자가 필요하면 변환한다.
age = int(
input("나이: ")
)
print() 활용구분자:
print(
"python",
"sql",
"api",
sep=" | ",
)
줄바꿈 변경:
print(
"loading",
end="...",
)
print("done")
with open(
"result.txt",
"w",
encoding="utf-8",
) as file:
file.write(
"처리 완료"
)
with를 사용하면 블록이 끝날 때 파일이 자동으로 닫힌다.
with open(
"result.txt",
"r",
encoding="utf-8",
) as file:
content = file.read()
큰 파일은 줄 단위로 읽을 수 있다.
with open(
"access.log",
encoding="utf-8",
) as file:
for line in file:
print(
line.rstrip()
)
| 모드 | 의미 |
|---|---|
r | 읽기 |
w | 새로 쓰기, 기존 내용 덮어쓰기 |
a | 기존 내용 뒤에 추가 |
x | 새 파일 생성 |
b | 바이너리 모드 |
pathlib 사용하기파일 경로를 다룰 때 Path를 사용할 수 있다.
from pathlib import Path
path = (
Path("data")
/ "users.txt"
)
읽기:
content = path.read_text(
encoding="utf-8"
)
쓰기:
path.write_text(
"hello",
encoding="utf-8",
)
import json
data = {
"name": "kim",
"skills": [
"python",
"sql",
],
}
쓰기:
with open(
"user.json",
"w",
encoding="utf-8",
) as file:
json.dump(
data,
file,
ensure_ascii=False,
indent=4,
)
읽기:
with open(
"user.json",
"r",
encoding="utf-8",
) as file:
data = json.load(file)
sys.argv스크립트를 실행할 때 값을 전달할 수 있다.
python app.py users.json
import sys
print(sys.argv)
첫 번째 추가 인자:
filename = sys.argv[1]
복잡한 CLI 프로그램이라면 argparse를 사용하는 편이 좋다.
argparseimport argparse
parser = (
argparse.ArgumentParser()
)
parser.add_argument(
"--file",
required=True,
)
args = parser.parse_args()
print(args.file)
실행:
python app.py --file users.json
import argparse
import json
from pathlib import Path
def load_users(
path: Path,
):
text = path.read_text(
encoding="utf-8"
)
return json.loads(text)
def parse_args():
parser = (
argparse.ArgumentParser()
)
parser.add_argument(
"--file",
required=True,
)
return parser.parse_args()
def main():
args = parse_args()
users = load_users(
Path(args.file)
)
active_count = sum(
1
for user in users
if user.get(
"active",
False,
)
)
print(
f"활성 사용자: "
f"{active_count}명"
)
if __name__ == "__main__":
main()
이 예제 안에는 함수, 파일, JSON, CLI 인자, 리스트 순회가 함께 사용된다.
return은 함수의 결과를 반환하며 실행을 종료한다.*args와 **kwargs를 이용해 가변 개수의 인자를 받을 수 있다.input(), 출력은 print()를 사용한다.with open(..., encoding="utf-8") 형태로 처리하면 안전하다.pathlib.Path, 구조화 데이터는 JSON을 활용하면 편리하다.argparse를 사용해 CLI 인터페이스를 만들 수 있다.