Python 미드레벨 기술면접
새 면접Q. Python의 데코레이터가 내부적으로 어떻게 동작하는지 설명하고, functools.wraps를 사용해야 하는 이유를 설명해주세요. 또한 클래스 기반 데코레이터와 함수 기반 데코레이터의 차이점과 각각의 사용 사례를 실무 관점에서 설명해주세요.
데코레이터는 함수를 인자로 받아 새로운 함수를 반환하는 고차 함수로, @decorator 문법은 func = decorator(func)의 syntactic sugar입니다. functools.wraps는 원본 함수의 메타데이터(__name__, __doc__ 등)를 보존하기 위해 사용되며, 이를 사용하지 않으면 디버깅과 문서화가 어려워집니다. 클래스 기반 데코레이터는 __call__ 메서드를 구현하여 상태를 유지할 수 있어 캐싱이나 호출 횟수 추적 같은 stateful한 작업에 적합하고, 함수 기반 데코레이터는 간단한 로깅이나 권한 검사 같은 stateless한 작업에 적합합니다. 실무에서는 매개변수를 받는 데코레이터를 구현할 때 3단계 중첩 함수 구조를 사용해야 하며, 비동기 함수를 데코레이팅할 때는 async/await를 올바르게 처리해야 합니다.
- • 데코레이터는 고차 함수로 함수를 감싸 기능을 추가하는 패턴
- • functools.wraps로 원본 함수의 메타데이터 보존 필요
- • 클래스 기반은 상태 유지, 함수 기반은 간단한 작업에 적합
- • 매개변수 있는 데코레이터는 3단계 중첩 구조 필요
여러 데코레이터를 중첩해서 사용할 때 실행 순서는 어떻게 되며, 데코레이터 간 의존성이 있을 때 어떻게 설계해야 하나요?
Q. Python의 컨텍스트 매니저(Context Manager)를 구현하는 두 가지 방법(__enter__/__exit__ 메서드와 contextlib.contextmanager 데코레이터)을 비교 설명하고, 데이터베이스 연결이나 파일 처리에서 컨텍스트 매니저를 사용해야 하는 이유를 설명해주세요. 또한 예외 발생 시 __exit__ 메서드의 반환값이 갖는 의미를 설명해주세요.
컨텍스트 매니저는 __enter__와 __exit__ 매직 메서드를 구현하는 클래스 방식과 contextlib.contextmanager 데코레이터로 제너레이터를 감싸는 방식이 있습니다. 클래스 방식은 복잡한 상태 관리가 필요할 때, 데코레이터 방식은 간단한 리소스 관리에 적합합니다. 데이터베이스 연결이나 파일 처리에서는 예외 발생 여부와 관계없이 리소스를 안전하게 해제하기 위해 사용하며, finally 블록보다 명시적이고 재사용 가능한 패턴을 제공합니다. __exit__ 메서드가 True를 반환하면 발생한 예외를 억제(suppress)하고, False나 None을 반환하면 예외를 다시 발생시킵니다. 실무에서는 트랜잭션 관리, 락 획득/해제, 임시 파일 생성/삭제 등에 활용됩니다.
- • 클래스 방식(__enter__/__exit__)과 데코레이터 방식(@contextmanager) 두 가지 구현 방법
- • 리소스의 안전한 획득과 해제를 보장
- • __exit__의 반환값으로 예외 억제 여부 제어
- • 트랜잭션, 락, 파일 등 리소스 관리에 필수적
비동기 환경에서 컨텍스트 매니저를 사용하려면 어떻게 구현해야 하며, __aenter__와 __aexit__는 언제 사용하나요?
Q. Python의 디스크립터 프로토콜(__get__, __set__, __delete__)이 무엇인지 설명하고, property 데코레이터가 내부적으로 디스크립터를 어떻게 활용하는지 설명해주세요. 또한 data descriptor와 non-data descriptor의 차이점과 속성 접근 우선순위를 설명하고, 실무에서 커스텀 디스크립터를 작성하는 사용 사례를 제시해주세요.
디스크립터는 __get__, __set__, __delete__ 중 하나 이상을 구현한 객체로, 클래스 속성으로 정의되어 인스턴스 속성 접근을 가로채는 메커니즘입니다. property는 디스크립터를 활용하여 getter, setter, deleter를 구현하며, 내부적으로 __get__과 __set__을 통해 메서드 호출을 속성 접근처럼 보이게 합니다. data descriptor는 __get__과 __set__을 모두 구현하고, non-data descriptor는 __get__만 구현하며, 속성 접근 시 data descriptor > 인스턴스 __dict__ > non-data descriptor 순으로 우선순위가 적용됩니다. 실무에서는 타입 검증, 값의 범위 제한, lazy loading, ORM 필드 구현 등에 활용되며, Django의 models.Field나 SQLAlchemy의 Column이 대표적인 예시입니다.
- • 디스크립터는 __get__, __set__, __delete__로 속성 접근 제어
- • property는 디스크립터 프로토콜을 활용한 내장 구현
- • data descriptor가 인스턴스 속성보다 우선순위 높음
- • ORM 필드, 타입 검증, lazy loading 등에 활용
디스크립터를 인스턴스 속성으로 정의하면 동작하지 않는 이유는 무엇이며, 이를 해결하기 위한 방법은 무엇인가요?
Q. Python의 메타클래스(Metaclass)가 무엇인지 설명하고, type을 상속받아 커스텀 메타클래스를 만드는 방법과 __new__와 __init__ 메서드의 차이를 설명해주세요. 또한 실무에서 메타클래스를 사용하는 사례와 메타클래스 대신 다른 패턴을 사용하는 것이 더 나은 경우를 설명해주세요.
메타클래스는 클래스를 만드는 클래스로, 모든 클래스의 기본 메타클래스는 type입니다. 커스텀 메타클래스는 type을 상속받아 __new__에서 클래스 객체를 생성하고 __init__에서 초기화하며, __new__는 클래스가 생성되기 전에 속성을 수정할 수 있고 __init__는 이미 생성된 클래스를 초기화합니다. 실무에서는 ORM의 모델 클래스 자동 등록, API 엔드포인트 자동 라우팅, 추상 기본 클래스 강제, 클래스 속성 검증 등에 사용됩니다. 하지만 메타클래스는 복잡도가 높아 유지보수가 어려우므로, 대부분의 경우 클래스 데코레이터, __init_subclass__, ABC 모듈 등 더 간단한 대안을 먼저 고려해야 합니다.
- • 메타클래스는 클래스를 생성하는 클래스, type이 기본 메타클래스
- • __new__는 클래스 생성 전 수정, __init__는 생성 후 초기화
- • ORM 모델 등록, 속성 검증, 자동 라우팅 등에 활용
- • 복잡도가 높아 클래스 데코레이터나 __init_subclass__ 우선 고려
메타클래스와 ABC(Abstract Base Class)를 함께 사용할 때 발생할 수 있는 메타클래스 충돌 문제를 어떻게 해결하나요?
Q. Python에서 threading.Lock, threading.RLock, threading.Semaphore의 차이점을 설명하고, 각각 어떤 상황에서 사용해야 하는지 설명해주세요. 또한 데드락(Deadlock)이 발생하는 조건과 이를 예방하기 위한 전략을 실무 예시와 함께 설명해주세요.
Lock은 한 번에 하나의 스레드만 획득 가능한 기본 뮤텍스로, 같은 스레드가 두 번 획득하면 데드락이 발생합니다. RLock(Reentrant Lock)은 같은 스레드가 여러 번 획득 가능하여 재귀 함수나 중첩 호출에 사용되며, 획득한 횟수만큼 해제해야 합니다. Semaphore는 정해진 개수의 스레드만 동시 접근을 허용하여 커넥션 풀이나 제한된 리소스 관리에 사용됩니다. 데드락은 상호 배제, 점유와 대기, 비선점, 순환 대기 4가지 조건이 모두 만족될 때 발생하며, 락 획득 순서 통일, 타임아웃 설정, 락 계층 구조 정의 등으로 예방할 수 있습니다. 실무에서는 with 문으로 락을 자동 해제하고, 락 범위를 최소화하며, 가능하면 queue.Queue 같은 thread-safe 자료구조를 사용하는 것이 좋습니다.
- • Lock은 기본 뮤텍스, RLock은 재진입 가능, Semaphore는 개수 제한
- • 데드락은 4가지 조건이 모두 만족될 때 발생
- • 락 순서 통일, 타임아웃, 계층 구조로 예방
- • with 문 사용과 thread-safe 자료구조 활용 권장
Python에서 GIL이 있는데도 Lock이나 Semaphore가 필요한 이유는 무엇이며, GIL과 Lock의 차이점은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!