다른 명령
@with_async_connection(db_name_func())
- 데코레이터에서 런타임에 DB 이름을 동적으로 선택하는 건 불가능합니다.
- 이유는 Python의 데코레이터는 함수 정의 시점에 실행되기 때문입니다
- — 즉, @가 붙는 순간에 이미 db_name_func()는 실행되고, 나중에 바꿀 수 없습니다.
해결 방법 1
- 동적 DB 이름을 인자로 넘기기
async def run_query_dynamic(db_name):
await run_dynamic_query(db_name, "SELECT * FROM users")
이때 데코레이터 대신 일반 함수로 구성:
async def run_dynamic_query(db_name, sql):
pool = await init_connection_pool(db_name)
async with pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute(sql)
return await cursor.fetchall()
해결 방법 2
- 함수를 감싸는 헬퍼 데코레이터
- 좀 더 데코레이터처럼 쓰고 싶다면 아래처럼 만들 수 있습니다:
async def run_query_dynamic(db_name, func, *args, **kwargs):
pool = await init_connection_pool(db_name)
async with pool.acquire() as conn:
async with conn.cursor() as cursor:
return await func(cursor, *args, **kwargs)
- 사용 예시:
async def get_user_by_id(cursor, user_id):
await cursor.execute("SELECT * FROM users WHERE id = :1", [user_id])
return await cursor.fetchone()
# 호출 시 동적으로 DB 선택
user = await run_query_dynamic("MyDB2", get_user_by_id, user_id=42)
ĉ=== 해결 방법 3 ===
- 데코레이터 내부에서 동적으로 DB 결정 (함수 인자 기반)
- - 이 방식은 데코레이터가 함수의 첫 번째 인자 또는 키워드 인자에서 DB 이름을 가져오는 방식입니다:
def dynamic_db_decorator():
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
db_name = kwargs.get("db_name") or args[0] # 첫 인자 또는 키워드에서
pool = await init_connection_pool(db_name)
async with pool.acquire() as conn:
async with conn.cursor() as cursor:
return await func(cursor, *args[1:], **kwargs)
return wrapper
return decorator
- 사용:
@dynamic_db_decorator()
async def get_all_users(cursor, db_name=None):
await cursor.execute("SELECT * FROM users")
return await cursor.fetchall()
await get_all_users("MyDB1")
추천 방식
| 코드가 단순해야 함 | run_query_dynamic() 방식 |
| 데코레이터 스타일을 유지하고 싶음 | dynamic_db_decorator() |
| 복잡한 쿼리 로직 분리 원함 | run_query_dynamic(func, ...) |