λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🐍 Python

[Python] type hint & generic

by dev.py 2025. 4. 23.

1. νƒ€μž… 힌트(type hint) 

1. ν•„μš”μ„±

νŒŒμ΄μ¬μ€ 동적 νƒ€μž… μ–Έμ–΄λ‘œ λ³€μˆ˜μ˜ νƒ€μž…μ„ λͺ…μ‹œν•˜μ§€ μ•Šμ•„λ„ μ‹€ν–‰ κ°€λŠ₯ν•˜λ‹€.
ν•˜μ§€λ§Œ ν”„λ‘œμ νŠΈ 규λͺ¨κ°€ 컀지고 ν˜‘μ—… 인원이 λ§Žμ•„μ§ˆμˆ˜λ‘ νƒ€μž… λΆˆν™•μ‹€μ„±μœΌλ‘œ μΈν•œ 였λ₯˜κ°€ λ°œμƒν•  κ°€λŠ₯성이 컀진닀.

def total(price, count):
    return price * count

total("1000", 3)  # → '100010001000'

 

예λ₯Ό λ“€μ–΄, μœ„μ˜ μ½”λ“œλŠ” int * int λ₯Ό μ˜ˆμƒν–ˆμ§€λ§Œ, λ¬Έμžμ—΄μ΄ λ“€μ–΄μ˜€λ©΄ 개발자의 μ˜λ„μ™€ λ‹€λ₯΄κ²Œ ν•¨μˆ˜κ°€ λ™μž‘ν•  수 μžˆλ‹€.

νƒ€μž… 힌트λ₯Ό μ‚¬μš©ν•˜λ©΄, νƒ€μž…μ— λŒ€ν•œ 였λ₯˜λ₯Ό 쀄일 수 μžˆλ‹€.

 

 

2. 문법

1. κΈ°λ³Έ νƒ€μž…

λ³€μˆ˜_이름: λ³€μˆ˜_νƒ€μž… 으둜 μ„ μ–Έν•œλ‹€.

ν•¨μˆ˜ μΈμžμ—λ„ λ™μΌν•˜κ²Œ μ„€μ •ν•˜λ©°, λ°˜ν™˜ 값은 -> 뒀에 ν‘œμ‹œν•œλ‹€.

name: str = "pasa"
age: int = 27
height: float = 175.5
is_active: bool = True

def greet(name: str) -> str:
    return f"Hello, {name}"

 

 

2. 리슀트, νŠœν”Œ, μ„ΈνŠΈ

λ³€μˆ˜_이름: μžλ£Œν˜•[λ‚΄λΆ€_νƒ€μž…] 으둜 μ„ μ–Έν•œλ‹€.

numbers: list[int] = [1, 2, 3]
tags: set[str] = {"python", "fastapi"}
user_info: tuple[str, int] = ("pasa", 27)
scores: dict[str, int] = {"math": 90, "eng": 85}

 

 

3. Optional, Union

λ³€μˆ˜κ°€ None을 κ°€μ§ˆ 수 μžˆλŠ” 경우 -> Optional

μ—¬λŸ¬ νƒ€μž…μ„ κ°€μ§ˆ 수 μžˆλŠ” 경우 -> Union

 

Union

# Python 3.9 이전 버전
from typing import Optional
def greet(name: Optional[str]) -> str:
    return f"Hello, {name or 'Guest'}"
    
    
# Python 3.10 이상 버전
def greet(name: str | None) -> str:
    return f"Hello, {name or 'Guest'}"

 

Optional

# Python 3.9 이전 버전
from typing import Union
def parse_id(id: Union[int, str]) -> str:
    return str(id)

# Python 3.10 이상 버전
def parse_id(id: int | str) -> str:
    return str(id)

 

 

2. μ œλ„ˆλ¦­ νƒ€μž…

νƒ€μž… νžŒνŠΈλ§ŒμœΌλ‘œλŠ” κ³ μ •λœ νƒ€μž…λ§Œ ν‘œν˜„ κ°€λŠ₯ν•˜λ‹€.

ν•˜μ§€λ§Œ λ‹€μ–‘ν•œ νƒ€μž…μ„ μœ μ—°ν•˜κ²Œ 닀루고 μ‹Άλ‹€λ©΄ μ œλ„ˆλ¦­(Generic)을 μ‚¬μš©ν•  수 μžˆλ‹€.

 

 

 

1. μ œλ„ˆλ¦­μ„ ν™œμš©ν•œ λ²”μš© ν•¨μˆ˜

def echo_str(x: str) -> str:
    return x

echo_str(1)

μœ„μ˜ ν•¨μˆ˜λŠ” λ¬Έμžμ—΄ 이외에 값을 λ„£μœΌλ©΄ 정적 νƒ€μž… κ²€μ‚¬μ—μ„œ μ—λŸ¬λ₯Ό 좜λ ₯ν•œλ‹€.

 

ν•˜μ§€λ§Œ μ œλ„ˆλ¦­μ„ μ‚¬μš©ν•˜λ©΄, νƒ€μž… 힌트λ₯Ό 쒀더 자유둭게 μ‚¬μš©ν•  수 μžˆλ‹€.

from typing import TypeVar

T = TypeVar('T')  # TλŠ” 아무 νƒ€μž…μ΄λ‚˜ κ°€λŠ₯ν•˜λ‹€λŠ”

def echo(x: T) -> T:
    return x

echo(1)

 

2. μ œλ„ˆλ¦­μ„ ν™œμš©ν•œ 클래슀

from typing import Generic, TypeVar

content = TypeVar('content', int, str)  # TλŠ” int λ˜λŠ” str만 κ°€λŠ₯

class Box(Generic[content]):
    def __init__(self, value: content):
        self.value: content = value

    def get(self) -> content:
        return self.value

 

μœ„μ—λŠ” int, str을 μ €μž₯ν•  수 μžˆλŠ” Box ν΄λž˜μŠ€μ΄λ‹€.

int_box = Box(42)             # TλŠ” int
str_box = Box("hello")        # TλŠ” str

print(int_box.get())          # 42
print(str_box.get())          # hello

정적 νƒ€μž… 검사 λ¬Έμ œκ°€ μ—†λ‹€

 

float_box = Box(3.14)        

print(float_box.get()) # λ¬Όλ‘  3.14둜 좜λ ₯은 λœλ‹€.

content νƒ€μž…μ—λŠ” floatκ°€ λ“€μ–΄κ°ˆ 수 μ—†μ–΄, 정적 κ²€μ‚¬μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

 

 

 

3. Pydantic μ‚¬μš©

API 응닡 λͺ¨λΈμ— 자주 ν™œμš©ν•  수 μžˆλ‹€.

from pydantic import BaseModel
from typing import TypeVar, Generic

T = TypeVar('T')

class ResponseModel(BaseModel, Generic[T]):
    status: str
    data: T

 

이제 λ‹€μ–‘ν•œ νƒ€μž…μ˜ 응닡 λͺ¨λΈμ„ μ•„λž˜μ™€ 같이 λ§Œλ“€ 수 μžˆλ‹€.

class User(BaseModel):
    name: str
    age: int

response = ResponseModel[User](status="ok", data=User(name="pasa", age=27))

이런 λ°©μ‹μœΌλ‘œ μ œλ„ˆλ¦­μ„ ν™œμš©ν•˜λ©΄,

  • ResponseModel[str], ResponseModel[User], ResponseModel[list[int]] λ“± μœ μ—°ν•˜κ²Œ μž‘μ„± κ°€λŠ₯
  • API λ¬Έμ„œ μžλ™ν™” λ„κ΅¬μ—μ„œλ„ μ •ν™•ν•œ νƒ€μž…μ΄ 반영됨