작성자: Rupesh Sharma AKA @hackyrupesh
간단함과 아름다움을 지닌 Python은 세계에서 가장 인기 있는 프로그래밍 언어 중 하나입니다. 그러나 2024년에도 특정 결함이 계속해서 개발자를 괴롭히고 있습니다. 이러한 문제는 항상 Python의 약점으로 인한 것이 아니라 예상치 못한 결과를 초래하는 Python의 설계, 동작 또는 일반적인 오해로 인해 발생합니다. 이 블로그 기사에서는 2024년에도 모든 개발자가 여전히 직면하게 되는 5가지 Python 문제와 해결 방법을 살펴보겠습니다.
가장 악명 높은 Python 버그 중 하나는 변경 가능한 기본 인수입니다. 목록이나 사전과 같은 변경 가능한 객체가 함수의 기본 인수로 사용되면 Python은 함수가 호출될 때마다가 아니라 함수가 정의될 때 이 기본 인수를 한 번만 평가합니다. 이로 인해 함수가 객체를 수정할 때 예기치 않은 동작이 발생합니다.
def append_to_list(value, my_list=[]): my_list.append(value) return my_list print(append_to_list(1)) # Outputs: [1] print(append_to_list(2)) # Outputs: [1, 2] - Unexpected! print(append_to_list(3)) # Outputs: [1, 2, 3] - Even more unexpected!
이를 방지하려면 None을 기본 인수로 사용하고 필요한 경우 함수 내부에 새 목록을 만듭니다.
def append_to_list(value, my_list=None): if my_list is None: my_list = [] my_list.append(value) return my_list print(append_to_list(1)) # Outputs: [1] print(append_to_list(2)) # Outputs: [2] print(append_to_list(3)) # Outputs: [3]
존재하지 않는 사전 키에 액세스하려고 하면 KeyError가 발생합니다. 이는 중첩된 사전을 사용하거나 구조가 보장되지 않는 데이터를 처리할 때 특히 까다로울 수 있습니다.
data = {'name': 'Alice'} print(data['age']) # Raises KeyError: 'age'
KeyError를 방지하려면 키를 찾을 수 없는 경우 None(또는 지정된 기본값)을 반환하는 get() 메서드를 사용하세요.
print(data.get('age')) # Outputs: None print(data.get('age', 'Unknown')) # Outputs: Unknown
중첩 사전의 경우 컬렉션 모듈이나 dotmap 또는 pydash와 같은 라이브러리의 defaultdict 사용을 고려하세요.
from collections import defaultdict nested_data = defaultdict(lambda: 'Unknown') nested_data['name'] = 'Alice' print(nested_data['age']) # Outputs: Unknown
try-Exception 블록을 과도하게 사용하거나 오용하면 예외가 포착되지만 제대로 처리되지 않는 자동 오류가 발생할 수 있습니다. 이로 인해 버그 감지 및 디버깅이 어려워질 수 있습니다.
try: result = 1 / 0 except: pass # Silently ignores the error print("Continuing execution...")
위의 예에서는 ZeroDivisionError가 포착되어 무시되지만 이로 인해 근본적인 문제가 가려질 수 있습니다.
항상 포착하려는 예외 유형을 지정하고 적절하게 처리하세요. 오류를 기록하면 문제를 추적하는 데 도움이 될 수도 있습니다.
try: result = 1 / 0 except ZeroDivisionError as e: print(f"Error: {e}") print("Continuing execution...")
보다 광범위한 예외 처리를 위해 패스 대신 로깅을 사용할 수 있습니다.
import logging try: result = 1 / 0 except Exception as e: logging.error(f"Unexpected error: {e}")
Python 3 이전에는 두 정수의 나눗셈이 기본적으로 바닥 나눗셈을 수행하여 결과를 정수로 자릅니다. Python 3에서는 진정한 나눗셈(/)으로 이 문제를 해결했지만 일부 개발자는 실수로 바닥 나눗셈(//)을 사용할 때 여전히 문제에 직면합니다.
print(5 / 2) # Outputs: 2.5 in Python 3, but would be 2 in Python 2 print(5 // 2) # Outputs: 2
특별히 바닥 구분이 필요하지 않은 한 구분에는 항상 /를 사용하세요. Python 2에서 Python 3으로 코드를 이식할 때는 주의하세요.
print(5 / 2) # Outputs: 2.5 print(5 // 2) # Outputs: 2
명확하고 예측 가능한 코드를 위해 십진수 사용을 고려하세요. 특히 재무 계산에서 더 정확한 산술 연산을 위해 십진수를 사용하세요.
from decimal import Decimal print(Decimal('5') / Decimal('2')) # Outputs: 2.5
Python의 가비지 수집기는 대부분의 메모리 관리를 처리하지만 순환 참조는 올바르게 처리되지 않으면 메모리 누수를 일으킬 수 있습니다. 두 개 이상의 개체가 서로 참조하는 경우 가비지 수집되지 않아 메모리 사용량이 증가할 수 있습니다.
class Node: def __init__(self, value): self.value = value self.next = None node1 = Node(1) node2 = Node(2) node1.next = node2 node2.next = node1 # Circular reference del node1 del node2 # Memory not freed due to circular reference
순환 참조를 피하려면 약한 참조 모듈을 통해 약한 참조를 사용하는 것이 좋습니다. 그러면 강한 참조가 없을 때 참조가 가비지 수집될 수 있습니다.
import weakref class Node: def __init__(self, value): self.value = value self.next = None node1 = Node(1) node2 = Node(2) node1.next = weakref.ref(node2) node2.next = weakref.ref(node1) # No circular reference now
또는 개체를 삭제하기 전에 참조를 없음으로 설정하여 수동으로 주기를 중단할 수 있습니다.
node1.next = None node2.next = None del node1 del node2 # Memory is freed
2024년에도 Python 개발자는 이러한 일반적인 버그에 계속 직면합니다. 언어는 수년에 걸쳐 발전하고 개선되었지만 이러한 문제는 Python 작동 방식의 근본적인 측면과 관련이 있는 경우가 많습니다. 이러한 함정을 이해하고 적절한 솔루션을 적용하면 더욱 강력하고 오류 없는 코드를 작성할 수 있습니다. 즐거운 코딩하세요!
작성자: Rupesh Sharma AKA @hackyrupesh
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3