Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

개발자가 자주 저지르는 Python 프로그래밍 실수 6가지

Python은 배우기 쉽고 직관적인 언어로 알려져 있지만, 그만큼 개발자들이 무심코 넘어가기 쉬운 함정들도 존재합니다. 숙련된 개발자조차 실수하기 쉬운 대표적인 Python 프로그래밍 실수들을 하나씩 살펴보겠습니다.

1. 스코프(Scope) 이름 조회 문제

Python은 LEGB(Local → Enclosing → Global → Built-in) 순서로 변수를 탐색합니다. 그런데 Python은 엄격한 타입 바인딩이 없기 때문에, 외부 스코프의 변수를 다른 값으로 재할당해 버릴 수 있습니다. 이렇게 되면 나중에 외부 스코프에서 해당 변수를 사용할 때 원래 의도했던 값이 아닌 다른 값이 참조되어 예상치 못한 동작을 일으킬 수 있습니다.

2. is와 == 연산자 혼동

is 연산자는 두 객체가 동일한 메모리 주소를 가리키는지, 즉 같은 객체인지를 확인합니다. 반면 == 연산자는 내부적으로 __eq__ 메서드를 호출하며, 클래스마다 동등성(equality)을 판단하는 방식이 다를 수 있습니다. 따라서 값 비교에는 ==를, 객체 동일성 비교에는 is를 사용하는 것이 올바른 습관입니다.

3. 리스트 순회 중 요소 수정

리스트를 순회(iterate)하는 도중에 요소를 삭제하면 IndexError가 발생할 수 있습니다. 리스트의 크기는 줄어드는데 인덱스는 그대로 유지되기 때문입니다. 이런 경우에는 원본 대신 복사본을 순회하거나, 리스트 컴프리헨션으로 새 리스트를 만드는 것이 안전합니다.

4. 클로저(Closure) 바인딩 문제

다음 코드를 살펴보겠습니다.

listLambdas = [lambda x: i + x for i in range(5)]
for lam in listLambdas:
    print(lam(10))

실행 결과

14
14
14
14
14

0부터 4까지 각각 더해진 결과가 나올 것이라 기대했다면 놀라실 겁니다. 이는 클로저 바인딩 방식 때문입니다. 리스트 안의 모든 람다는 변수 i를 '참조'할 뿐, 생성 시점의 값을 복사하지 않습니다. 따라서 i가 마지막에 4가 된 이후 람다를 호출하면 모두 같은 값인 14를 반환하게 됩니다. 이를 피하려면 lambda x, i=i: i + x처럼 기본 인자로 값을 고정하는 방법을 활용할 수 있습니다.

5. 내장 함수·내장 이름과의 충돌

누구나 한 번쯤 sum이라는 이름의 변수를 만든 적이 있을 것입니다. 이 경우 내장 함수 sum에 대한 참조를 덮어쓰게 됩니다. 단순한 상황에서는 사소해 보이지만, 패키지나 모듈 이름을 이런 식으로 지으면 심각한 문제가 발생할 수 있습니다. 예를 들어 다른 패키지가 표준 모듈 대신 여러분이 만든 클래스나 모듈을 import해 버리는 상황이 생길 수 있습니다.

6. 직관적이지 않은 연산자 오버로딩

Python은 클래스에서 연산자(+, -, == 등)를 오버로딩할 수 있는 기능을 제공합니다. 하지만 많은 개발자가 이를 일반적이지 않은 방식으로 구현하다 보니, 복잡하고 직관적이지 않은 API가 만들어지곤 합니다. 연산자 오버로딩은 해당 연산자가 일반적으로 기대되는 의미와 일치하도록 신중하게 구현해야 합니다.

마무리

이러한 실수들은 Python의 유연함이 주는 부작용이기도 합니다. LEGB 스코프 규칙, is와 ==의 차이, 클로저의 늦은 바인딩(late binding) 등 Python의 핵심 동작 원리를 제대로 이해하고 있다면 대부분의 함정을 미리 피할 수 있습니다. 작은 습관의 차이가 디버깅 시간을 크게 줄여줄 것입니다.