[Python] 다양한 오류와 해결 방안 (2)
목차 오류의 종류 파이썬 오류의 종류 런타임 오류 vs 예외 오류 예외 오류 처리 하는 방법 조건문을 사용한 예외 처리(Exception handling) "허가보다 용서를 구하는 것이 더 쉽다(It's easier to ask for forgiveness than permission)" 오류 해결을 위한 구문 try-except 구문 try-except-else 구문 'finally' 구문 try-except-else-finally 구문 closed 함수 return 키워드 try-except 구문 Python의 try-except 구문은 예외(런타임 오류)를 정상적으로 처리하는 데 사용됩니다. 오류가 발생했을 때 프로그램이 충돌하는 대신 try-except 블록을 사용하면 예외가 발생했을 때 일부 코..
2023.05.02
[Python] 다양한 오류와 해결 방안 (1)
목차 오류의 종류 파이썬 오류의 종류 런타임 오류 vs 예외 오류 예외 오류 처리 하는 방법 조건문을 사용한 예외 처리(Exception handling) "허가보다 용서를 구하는 것이 더 쉽다(It's easier to ask for forgiveness than permission)" 오류 해결을 위한 구문 try-except 구문 try-except-else 구문 'finally' 구문 try-except-else-finally 구문 closed 함수 return 키워드 파이썬 오류의 종류 Python에는 코드 작업 중에 발생할 수 있는 몇 가지 유형의 오류가 있습니다. 이러한 오류는 크게 구문 오류와 예외의 두 가지 유형으로 분류할 수 있습니다. 1. 구문 오류 이러한 오류는 Python 파서가 ..
2023.05.02
no image
[Python] 객체를 함수로 전달하는 방법
객체 잠조 복사(pass-by-object-reference) 값 복사 레퍼런스 복사 객체 참조 복사 Python에서 함수에 값을 복사할 때 실제로 개체 자체의 복사본이 아니라 개체에 대한 참조를 복사합니다. 이 개념을 "객체 참조 복사" 또는 "참조 값 복사"이라고 합니다. 함수에서 값 복사 동작은 객체가 변경 가능한지 또는 변경 불가능한지에 따라 다릅니다. 1. 불변 객체(Immutable Objects) 숫자, 문자열 및 튜플과 같은 불변 객체의 경우 함수 내 객체에 대한 모든 변경 사항은 새 객체를 생성합니다. 원래 개체는 변경되지 않은 상태로 유지되므로 개체의 복사본이 함수에 복사된 것처럼 보입니다. def modify_value(x): x = x + 1 print(f"Inside the fun..
2023.04.30
no image
[Python] 스택(stack)과 힙(heap)
목차 스택(stack) 힙(heap) 스택(stack) 스택은 LIFO(Last In First Out) 원칙을 따르는 선형 데이터 구조입니다. 즉, 스택에 추가된 마지막 요소가 제거되는 첫 번째 요소입니다. 스택은 스택의 맨 위에서 항목이 추가(푸시)되거나 제거(팝)되는 항목 모음으로 시각화할 수 있습니다. LIFO 특성으로 인해 스택은 상위 요소에 대한 액세스만 허용하고 하위 요소는 허용하지 않습니다. 스택과 관련된 두 가지 기본 작업이 있습니다. Push: 스택 맨 위에 요소를 추가합니다. Pop: 스택에서 맨 위 요소를 제거합니다. 스택에는 다음과 같은 보조 작업도 있을 수 있습니다. Peek 또는 Top: 스택의 맨 위 요소를 제거하지 않고 반환합니다. IsEmpty: 스택이 비어 있는지 확인합..
2023.04.30
no image
[Python] key 매개 변수, 콜백 함수
목차 Key 매개 변수 콜백 함수 Key 매개 변수 Python에서 key 매개변수는 sorted(), min() 및 max()와 같은 특정 내장 목록 함수와 함께 사용되어 함수의 동작을 사용자 정의할 수 있습니다. 'key' 매개변수는 목록의 각 요소에서 비교 키를 추출하는 데 사용되는 함수를 사용합니다. 다음은 목록과 함께 key 매개변수를 사용하는 방법의 예입니다. # 샘플 튜플 리스트 my_list = [(1, 'apple'), (4, 'banana'), (2, 'cherry'), (3, 'date')] # 리스트를 각 튜플의 두 번째 요소를 기준으로 정렬 sorted_list = sorted(my_list, key=lambda x: x[1]) print("Sorted list:", sorted_..
2023.04.30
no image
[Python] 반복문을 사용하는 여러가지 방법
목차 Iterable Iterator Generator Generator 표현식 Iterable Iterable은 for 루프를 사용하여 반복할 수 있는 객체입니다. Python에서 리스트, 튜플, 문자열, 딕셔너리 및 세트는 반복 가능 항목의 예입니다. for 루프에서 iterable을 사용하여 요소를 하나씩 반복할 수 있습니다. 다음은 Python에서 iterable을 사용하는 방법에 대한 몇 가지 예입니다. 1. 리스트를 통해 반복 fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(fruit) 2. 튜플을 통해 반복 colors = ("red", "green", "blue") for color in colors: print(colo..
2023.04.30
반응형

목차

  1. 오류의 종류
    1. 파이썬 오류의 종류
    2. 런타임 오류 vs 예외 오류
    3. 예외 오류 처리 하는 방법
    4. 조건문을 사용한 예외 처리(Exception handling)
    5. "허가보다 용서를 구하는 것이 더 쉽다(It's easier to ask for forgiveness than permission)"
  2. 오류 해결을 위한 구문
    1. try-except 구문
    2. try-except-else 구문
    3. 'finally' 구문
    4. try-except-else-finally 구문
    5. closed 함수
    6. return 키워드

try-except 구문

Python의 try-except 구문은 예외(런타임 오류)를 정상적으로 처리하는 데 사용됩니다. 오류가 발생했을 때 프로그램이 충돌하는 대신 try-except 블록을 사용하면 예외가 발생했을 때 일부 코드를 실행하고 프로그램 실행을 계속할 수 있습니다.

다음은 try-except 블록의 기본 구문입니다.

try:
    # Code that might raise an exception
except SomeExceptionType as e:
    # Code to handle the exception


이 예에서는 try 블록 내부의 코드가 실행됩니다. 실행 중에 지정된 유형의 예외(SomeExceptionType)가 발생하면 except 블록 내부의 코드가 실행됩니다. 발생한 예외 객체는 'as' 키워드 뒤에 변수 이름(이 경우 'e')을 사용하여 캡처할 수 있습니다. 그런 다음 이 변수를 사용하여 예외에 대한 자세한 정보를 얻거나 사용자 지정 오류 메시지를 표시할 수 있습니다. 

예외 유형을 튜플로 지정하여 단일 except 블록으로 여러 예외 유형을 잡을 수도 있습니다.

try:
    # Code that might raise an exception
except (ExceptionType1, ExceptionType2) as e:
    # Code to handle the exception


유형에 관계없이 예외를 포착하려면 Exception 기본 클래스를 사용할 수 있습니다.

try:
    # Code that might raise an exception
except Exception as e:
    # Code to handle the exception


그러나 일반적으로 모든 예외를 포착하는 것보다 발생할 것으로 예상되는 특정 예외 유형만 포착하는 것이 좋습니다. 이렇게 하면 예상하지 못한 의도하지 않은 마스킹 오류를 방지할 수 있습니다.

예외가 발생했는지 여부에 관계없이 실행될 코드를 포함하는 except 블록 뒤에 선택적 finally 블록을 추가할 수도 있습니다.

try:
    # Code that might raise an exception
except SomeExceptionType as e:
    # Code to handle the exception
finally:
    # Code that will always be executed


이는 try 블록 내 코드의 성공 또는 실패에 관계없이 파일 핸들 또는 네트워크 연결 닫기와 같은 리소스 정리에 유용할 수 있습니다.


try-except-else 구문

try, except 및 else 블록을 함께 사용하는 예를 살펴보겠습니다. 이 예에서는 사용자의 입력을 정수로 변환하고 숫자의 제곱을 계산하려고 합니다. 변환이 성공하면 결과를 출력하고 그렇지 않으면 예외를 처리하고 오류 메시지를 출력합니다.

def calculate_square():
    user_input = input("Enter a number: ")

    try:
        number = int(user_input)
    except ValueError:
        print("Invalid input. Please enter a valid integer.")
    else:
        square = number ** 2
        print(f"The square of {number} is {square}.")

calculate_square()


코드에 대한 내용은 다음과 같습니다.

  1. input() 함수를 사용하여 사용자로부터 입력을 받습니다.

  2. try 블록에서 int() 함수를 사용하여 사용자 입력을 정수로 변환하려고 시도합니다. 입력이 유효한 정수가 아니면 ValueError가 발생합니다.

  3. except 블록에서 ValueError 예외를 포착하고 잘못된 입력에 대해 사용자에게 알리는 오류 메시지를 인쇄합니다.
    변환에 성공하고 예외가 발생하지 않으면 else 블록이 실행됩니다. else 블록에서 정수의 제곱을 계산하고 결과를 인쇄합니다.

try, except 및 else 블록을 함께 사용하면 오류를 정상적으로 처리하고 예외가 발생하지 않을 때 특정 작업을 수행할 수 있습니다. 이는 보다 강력하고 유지 관리 가능한 코드로 이어집니다.


'finally' 문

Python의 'finally' 문은 예외가 발생했는지 여부에 관계없이 코드 블록이 항상 실행되도록 하기 위해 'try' 및 'except' 문과 함께 사용됩니다. finally 블록은 try, except 및 선택적 else 블록 뒤에 배치됩니다.

다음은 try-except-finally 구문의 일반 구문입니다.

try:
    # Code that might raise an exception
except SomeExceptionType as e:
    # Code to handle the exception
else:
    # Optional: Code to be executed if no exception is raised in the try block
finally:
    # Code that will always be executed, regardless of whether an exception was raised or not


'finally' 블록은 이전 코드에서 어떤 일이 발생하든 실행해야 하는 정리 작업을 수행하거나 리소스를 해제(예: 파일 핸들 닫기, 네트워크 연결 또는 데이터베이스 연결)해야 할 때 유용합니다.

다음은 finally 문 사용을 보여주는 예입니다.

file_handle = None

try:
    file_handle = open("file.txt", "r")
    content = file_handle.read()
    print(content)
except FileNotFoundError as e:
    print("File not found")
except IOError as e:
    print("An I/O error occurred")
finally:
    if file_handle:
        file_handle.close()
        print("File handle closed")


이 예제에서 'finally' 블록은 파일을 열거나 읽는 동안 예외가 발생하더라도 파일 핸들이 닫히도록 합니다. file_handle.close() 문은 try 및 except 블록에서 어떤 일이 발생하든 상관없이 실행됩니다.


try-except-else-finally 구문

Python에서 try-except-else 구문을 사용하면 try 블록에서 예외가 발생하지 않는 경우에만 실행될 코드 블록을 지정할 수 있습니다. else 블록은 try 블록 다음에 실행되지만 선택적 finally 블록(있는 경우) 이전에 실행됩니다. 구문은 다음과 같습니다.

try:
    # Code that might raise an exception
except SomeExceptionType as e:
    # Code to handle the exception
else:
    # Code to be executed if no exception is raised in the try block
finally:
    # Optional: Code that will always be executed, regardless of whether an exception was raised or not


try 블록 내부의 코드가 먼저 실행됩니다. 지정된 유형의 예외(SomeExceptionType)가 발생하면 except 블록 내부의 코드가 실행됩니다. try 블록에서 예외가 발생하지 않으면 else 블록 내부의 코드가 실행됩니다.

else 블록은 try 블록에서 예외가 발생하지 않은 경우에만 어떤 작업을 수행하려는 상황에서 유용할 수 있습니다. 예를 들어 이전 코드에 오류가 없는 경우에만 데이터베이스에 대한 변경 사항을 커밋할 수 있습니다.

다음은 try-except-else 구문의 사용을 보여주는 예입니다.

try:
    result = 10 / 2  # This might raise a ZeroDivisionError if the divisor is zero
except ZeroDivisionError as e:
    print("Cannot divide by zero")
else:
    print(f"The result of the division is {result}")
finally:
    print("This message will always be displayed, regardless of whether an exception was raised or not")


이 예에서 try 블록의 result 계산에서 ZeroDivisionError가 발생하지 않으면 else 블록이 실행되고 결과가 인쇄됩니다. 'finally' 블록이 있는 경우 예외가 발생했는지 여부에 관계없이 항상 실행됩니다.


closed 함수

파이썬에서 파일 객체의 closed 속성은 파일이 닫혀 있는지 여부를 확인하는 데 사용됩니다. 함수가 아니라 파일 객체의 속성입니다. 부울 값을 반환합니다. 파일이 닫혀 있으면 'True', 그렇지 않으면 'False'입니다.

다음은 closed 속성을 사용하는 방법의 예입니다.

# Opening a file for reading
file = open("example.txt", "r")

# Checking if the file is closed
if file.closed:
    print("The file is closed.")
else:
    print("The file is open.")

# Closing the file
file.close()

# Checking if the file is closed again
if file.closed:
    print("The file is closed.")
else:
    print("The file is open.")


이 예에서는 먼저 example.txt라는 파일을 읽기 위해 엽니다. 그런 다음 closed 속성을 사용하여 파일이 닫혀 있는지 열려 있는지 확인합니다. file.close()로 파일을 닫은 후 closed 속성을 다시 확인하여 파일이 실제로 닫혔는지 확인합니다.

작업을 마친 후에는 파일을 닫아 시스템 리소스를 확보하는 것이 중요합니다. 파일 닫기를 처리하는 권장 방법은 코드 블록이 종료될 때 파일을 자동으로 닫는 with 문을 사용하는 것입니다.

with open("example.txt", "r") as file:
    # Perform file operations here

# File is automatically closed after the block
if file.closed:
    print("The file is closed.")


이 예제에서는 with 블록이 종료되면 파일이 자동으로 닫히므로 파일 작업을 보다 안전하고 깔끔하게 수행할 수 있습니다.


return 키워드

반환 키워드는 코드의 다른 부분과 마찬가지로 try 문 안에 사용할 수 있습니다. try 블록 내에서 return을 사용하면 함수가 지정된 값을 즉시 반환하고 함수를 종료하여 try 블록의 나머지 코드와 연결된 예외, else 및 마지막으로 블록을 건너뜁니다.

다음은 try 문 내에서 return을 사용하는 예입니다.

def divide(a, b):
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("Division by zero is not allowed.")
        return None

result1 = divide(10, 2)
result2 = divide(10, 0)
print(f"Result 1: {result1}")
print(f"Result 2: {result2}")


이 예에서는 두 개의 인수 a와 b를 사용하는 divide라는 함수를 정의합니다. a를 b로 나누려고 시도하고 나누기가 성공하면 즉시 결과를 반환합니다. ZeroDivisionError가 발생하면 except 블록 내부의 코드가 실행되고 함수는 None을 반환합니다.

예제의 출력은 다음과 같습니다.

Result 1: 5.0
Division by zero is not allowed.
Result 2: None


보시다시피 이 함수는 첫 번째 나눗셈에 대해 올바른 결과를 반환하고 두 번째 나눗셈에 대해 0으로 나누기 오류를 처리하여 'None'을 반환합니다.


반응형
반응형

목차

  1. 오류의 종류
    1. 파이썬 오류의 종류
    2. 런타임 오류 vs 예외 오류
    3. 예외 오류 처리 하는 방법
    4. 조건문을 사용한 예외 처리(Exception handling)
    5. "허가보다 용서를 구하는 것이 더 쉽다(It's easier to ask for forgiveness than permission)"
  2. 오류 해결을 위한 구문
    1. try-except 구문
    2. try-except-else 구문
    3. 'finally' 구문
    4. try-except-else-finally 구문
    5. closed 함수
    6. return 키워드

파이썬 오류의 종류

Python에는 코드 작업 중에 발생할 수 있는 몇 가지 유형의 오류가 있습니다. 이러한 오류는 크게 구문 오류와 예외의 두 가지 유형으로 분류할 수 있습니다.

1. 구문 오류
이러한 오류는 Python 파서가 코드에서 잘못된 구문을 발견할 때 발생합니다. 구문 오류에는 누락되거나 잘못된 구두점, 잘못된 들여쓰기 또는 잘못된 구문 구문 사용이 포함될 수 있습니다. 구문 오류의 예는 다음과 같습니다.

  • 누락되거나 잘못 배치된 콜론, 괄호 또는 쉼표
  • 코드 블록을 정의하기 위해 들여쓰기를 사용하기 때문에 Python에서 중요한 잘못된 들여쓰기
if 5 > 2  # Syntax error: Missing colon at the end of the line
    print("5 is greater than 2")

 


2. 예외
예외는 코드 실행 중에 발생하는 오류입니다. 이러한 오류는 일반적으로 잘못된 논리, 내장 함수의 잘못된 사용 또는 예기치 않은 입력으로 인해 발생합니다. 몇 가지 일반적인 예외는 다음과 같습니다.

  • NameError: 현재 범위에 정의되지 않은 변수나 함수를 사용하려고 할 때 발생
  • TypeError: 특정 작업이나 기능에 잘못된 유형을 사용할 때 발생
  • ValueError: 특정 작업이나 기능에 잘못된 값을 제공했을 때 발생
  • IndexError: 목록 또는 다른 시퀀스 유형의 범위를 벗어난 인덱스에 액세스하려고 할 때 발생합니다.
  • KeyError: 사전에 존재하지 않는 키에 접근하려 할 때 발생
  • ZeroDivisionError: 숫자를 0으로 나누려고 할 때 발생
undefined_variable = 5 + nonexistent  # NameError

result = "Hello" + 5  # TypeError

number = int("text")  # ValueError

my_list = [1, 2, 3]
element = my_list[5]  # IndexError

my_dict = {"key1": "value1"}
value = my_dict["key2"]  # KeyError

division = 5 / 0  # ZeroDivisionError


예기치 않은 오류로 인해 프로그램이 중단되지 않도록 하려면 try-except 블록을 사용하여 코드의 예외를 처리하는 것이 중요합니다.


런타임 오류 vs 예외 오류

런타임 오류 및 예외 오류는 종종 같은 의미로 사용되는 용어입니다. 그러나 그들 사이에는 미묘한 차이가 있습니다.

  1. 런타임 오류
    런타임 오류는 프로그램 실행 중에 발생하는 모든 오류를 가리키는 일반적인 용어입니다. 여기에는 논리적 오류, 입/출력 오류, 프로그램에서 발생한 예외 등 프로그램이 실행되는 동안 발생할 수 있는 모든 유형의 오류가 포함됩니다. 런타임 오류는 언어 구성 또는 코드 구문과 반드시 ​​관련이 있는 것은 아닙니다. 잘못된 알고리즘, 시스템 리소스 부족 또는 하드웨어 문제와 같은 다양한 이유로 인해 발생할 수 있습니다. 런타임 오류가 있는 프로그램은 비정상적으로 종료되거나 잘못된 결과를 생성할 수 있습니다.

  2. 예외 오류
    반면에 예외 오류는 프로그램이 0으로 나누기, 범위를 벗어난 인덱스에 액세스, 또는 존재하지 않는 파일을 열려고 시도합니다. Python을 비롯한 많은 프로그래밍 언어에서 프로그램이 자체적으로 처리할 수 없는 오류 조건을 만나면 예외가 발생합니다. 프로그래머는 프로그램 충돌을 방지하고 오류를 적절하게 처리하기 위해 try-except 블록과 같은 예외 처리 메커니즘을 사용하여 이러한 예외를 처리할 수 있습니다.

요약하면 런타임 오류는 프로그램 실행 중에 발생할 수 있는 광범위한 오류 범주인 반면 예외 오류는 프로그램이 자체적으로 처리할 수 없는 예외 조건을 만났을 때 발생하는 특정 유형의 런타임 오류입니다. 예외 오류는 프로그래밍 언어에서 제공하는 예외 처리 메커니즘을 사용하여 포착하고 처리할 수 있는 반면 런타임 오류는 프로그램 논리 또는 기본 시스템에서 추가 디버깅 및 수정이 필요할 수 있습니다.


예외 오류 처리 하는 방법

예외 처리(Exception handling)는 프로그램 실행 중에 오류를 정상적으로 처리하는 방법입니다. Python에서는 예외 처리를 위해 try, except, finally 및 raise 문을 사용할 수 있습니다.

다음은 Python에서 예외 처리를 사용하는 방법입니다.

  • try 블록
    try 블록 내에서 예외를 발생시킬 수 있는 코드를 포함합니다. 예외가 발생하면 코드 실행이 적절한 except 블록으로 이동합니다.

  • except 블록
    하나 이상의 except 블록을 사용하여 특정 예외를 포착하고 처리합니다. 튜플로 지정하여 동일한 블록에서 여러 예외를 catch하거나 다른 예외에 대해 별도의 except 블록을 사용할 수 있습니다.

  • else 블록(선택 사항)
    모든 except 블록 다음에 else 블록을 사용할 수 있습니다. else 블록의 코드는 try 블록이 예외를 발생시키지 않으면 실행됩니다.

  • finally 블록(선택 사항)
    finally 블록은 예외가 발생했는지 여부에 상관없이 실행되어야 하는 코드를 지정하는 데 사용됩니다. 이 블록은 선택 사항이며 try, except 및 else 블록 뒤에 나타날 수 있습니다.

  • raise 문
    raise 문을 사용하여 코드 내에서 명시적으로 예외를 발생시킬 수 있습니다. 이는 사용자 지정 예외를 발생시키거나 예외를 처리한 후 다시 발생시키려는 경우에 유용합니다.


다음은 Python에서 예외 처리를 사용하는 예입니다.

try:
    # Code that might raise an exception
    x = int(input("Enter a number: "))
    result = 10 / x
except ZeroDivisionError:
    # Handle the ZeroDivisionError exception
    print("Error: Division by zero.")
except ValueError:
    # Handle the ValueError exception (e.g., non-numeric input)
    print("Error: Invalid input. Please enter a number.")
else:
    # This block executes if no exception occurred
    print(f"The result is: {result}")
finally:
    # This block executes no matter what
    print("This message is always displayed.")


이 예에서 try 블록 내의 코드는 ZeroDivisionError 또는 ValueError 예외를 발생시킬 수 있습니다. except 블록은 이러한 예외를 처리하고 final 블록은 예외 발생 여부에 관계없이 특정 메시지가 항상 표시되도록 합니다.


조건문을 사용한 예외 처리(Exception handling)

조건문을 사용한 예외 처리는 "허가보다 용서를 구하는 것이 더 쉽다(it's easier to ask for forgiveness than permission)"는 파이썬의 접근 방식에 어긋나므로 권장되지 않습니다. 대신 예외 처리를 위해 try 및 except 블록을 사용하는 것이 좋습니다.

그러나 여전히 조건문을 사용하여 예외를 처리하려는 경우에는 예외를 발생시킬 수 있는 코드를 실행하기 전에 예외를 발생시킬 수 있는 조건을 확인할 수 있습니다. 이 접근 방식을 "도약하기 전에 살펴보기(LBYL)"라고 합니다.

그러나 여전히 조건문을 사용하여 예외를 처리하려는 경우 예외를 발생시킬 수 있는 코드를 실행하기 전에 예외를 유발할 수 있는 조건을 확인할 수 있습니다. 이 접근법은 "도약하기 전에 보기"(Look Before You Leap, LBYL)로 알려져 있습니다.

다음은 조건문을 사용하여 예외를 처리하는 예입니다.

x = input("Enter a number: ")

# Check if the input is a valid number
if x.isdigit():
    x = int(x)

    # Check for division by zero
    if x != 0:
        result = 10 / x
        print(f"The result is: {result}")
    else:
        print("Error: Division by zero.")
else:
    print("Error: Invalid input. Please enter a number.")


이 예제에서는 'if' 문을 사용하여 나누기를 수행하기 전에 입력이 유효한 숫자인지, 0이 아닌지 확인합니다. 이 접근 방식은 사전에 조건을 확인하여 예외 발생을 방지합니다.

예외 처리에 조건문을 사용하면 정상적인 코드 흐름과 오류 처리 코드가 분리되지 않으므로 코드의 가독성과 유지 관리가 어려워질 수 있습니다. 또한 발생할 수 있는 모든 가능한 예외를 포착하지 못하여 코드의 견고성이 떨어질 수 있습니다. 따라서 일반적으로 Python에서 예외 처리를 위해 try 및 except 블록을 사용하는 것이 좋습니다.


"허가보다 용서를 구하는 것이 더 쉽다(It's easier to ask for forgiveness than permission)"

"허락을 구하는 것보다 용서를 구하는 것이 더 쉽다"는 미국의 컴퓨터 과학자이자 미 해군 후방 제독인 그레이스 호퍼의 명언이 유명합니다. 이 속담은 어떤 상황에서는 행동하기 전에 허가를 기다리는 것보다 먼저 승인을 구하지 않고 행동을 취한 다음 나중에 결과나 이의를 처리하는 것이 더 낫다는 것을 시사합니다.

이 문구는 허가나 승인을 기다리는 것이 진행을 방해하고 창의성을 억제할 수 있는 혁신과 위험 감수라는 맥락에서 자주 사용됩니다. 경우에 따라서는 명시적인 허가가 없더라도 자신의 행동이 긍정적인 결과를 가져올 것이라고 믿는 상황에서 적극적이고 주도적인 태도를 취하도록 장려하기도 합니다.

프로그래밍 세계에서는 이 말을 EAFP(허락보다 용서를 구하는 것이 더 쉽다)라는 철학으로 채택했습니다. EAFP는 코드를 실행하기 전에 가능한 오류를 확인하는 대신 예외를 처리하기 위해 시도 예외 블록을 사용하는 것을 선호하는 코딩 스타일입니다. 이 접근 방식은 오류나 예외 조건을 확인하기 위한 긴 if-else 체인을 피할 수 있으므로 경우에 따라 더 깔끔하고 가독성 높은 코드를 만들 수 있습니다.


반응형
반응형
  1. 객체 잠조 복사(pass-by-object-reference)
  2. 값 복사
  3. 레퍼런스 복사

객체 참조 복사

Python에서 함수에 값을 복사할 때 실제로 개체 자체의 복사본이 아니라 개체에 대한 참조를 복사합니다. 이 개념을 "객체 참조 복사" 또는 "참조 값 복사"이라고 합니다. 함수에서 값 복사 동작은 객체가 변경 가능한지 또는 변경 불가능한지에 따라 다릅니다.

1. 불변 객체(Immutable Objects)

숫자, 문자열 및 튜플과 같은 불변 객체의 경우 함수 내 객체에 대한 모든 변경 사항은 새 객체를 생성합니다. 원래 개체는 변경되지 않은 상태로 유지되므로 개체의 복사본이 함수에 복사된 것처럼 보입니다.

def modify_value(x):
    x = x + 1
    print(f"Inside the function: {x}")

number = 5
modify_value(number)
print(f"Outside the function: {number}")


Output

Inside the function: 6
Outside the function: 5

 


이 예에서 변수 number는 함수 내에서 수정되더라도 함수 외부에서는 변경되지 않은 상태로 유지됩니다.

2. 가변 객체(Mutable Object)

리스트, 딕셔너리 및 집합과 같은 변경 가능한 개체의 경우 참조가 동일한 개체를 가리키기 때문에 함수 내에서 개체에 대한 변경 사항이 함수 외부에도 반영됩니다.

def modify_list(lst):
    lst.append(4)
    print(f"Inside the function: {lst}")

my_list = [1, 2, 3]
modify_list(my_list)
print(f"Outside the function: {my_list}")


Output

Inside the function: [1, 2, 3, 4]
Outside the function: [1, 2, 3, 4]


이 예제에서 함수 내 리스트에 대한 변경 사항은 함수 외부에서도 볼 수 있습니다.

변경 가능한 객체를 함수에 복사하기 전에 복사본을 만들고 싶다면 얕은 복사본에는 copy 모듈을, 깊은 복사본에는 deepcopy 모듈을 사용할 수 있습니다. 이렇게 하면 함수가 복사본을 수정할 때 원본 객체가 변경되지 않은 상태로 유지됩니다.


값 복사

"값 복사"이라고도 하는 값 복사는 원래 개체 값의 복사본을 사용하여 새 개체를 만드는 프로세스입니다. 이 경우 원본 객체와 복사된 객체는 서로 독립적입니다. 한 개체를 수정해도 다른 개체에는 영향을 미치지 않습니다. 이는 두 객체가 별개의 메모리 위치를 가지고 있고 해당 값이 분리되어 있기 때문입니다.

Python에서 정수, 실수, 문자열 및 튜플과 같은 불변 유형은 값 복사를 사용합니다. 불변 객체의 값을 다른 변수에 할당하면 새 객체가 생성되고 원래 객체에서 값이 복사됩니다.

다음은 값 복사를 설명하는 예입니다.

original_string = "hello"
copied_string = original_string

original_string = "world"

print(original_string)  # Output: world
print(copied_string)    # Output: hello

 


예제에서는 original_string 값을 copied_string에 할당했습니다. 나중에 original_string을 수정했을 때 copied_string에는 영향을 미치지 않았습니다. 두 변수가 독립적이고 별도의 메모리 위치에 값을 저장하기 때문입니다.

값 복사는 함수에 인수로 복사하거나 복사본을 만들 때 원래 개체가 변경되지 않은 상태로 유지되도록 합니다. 그러나 값 복사는 큰 개체를 처리할 때 효율성이 떨어질 수 있습니다. 동일한 값으로 새 개체를 만들면 상당한 양의 메모리와 처리 시간이 소비될 수 있기 때문입니다. 이러한 경우 참조 복사가 더 효율적일 수 있습니다.


레퍼런스 복사

"참조에 의한 복사"이라고도 하는 참조 복사는 개체 값의 별도 복사본을 만드는 대신 기존 개체에 대한 새 참조(또는 별칭)를 만드는 프로세스입니다. 이는 원본 참조와 복사된 참조가 모두 메모리의 동일한 개체를 가리키며 한 참조를 통해 개체에 대한 모든 변경 사항이 다른 참조에 반영됨을 의미합니다.

Python에서 목록, 사전 및 집합과 같은 변경 가능한 유형은 참조 복사를 사용합니다. 변경 가능한 개체를 다른 변수에 할당하면 새 개체가 생성되지 않습니다. 대신 두 변수 모두 동일한 개체를 참조합니다.

다음은 참조 복사를 설명하는 예입니다.

original_list = [1, 2, 3]
copied_list = original_list

original_list[0] = 99

print(original_list)  # Output: [99, 2, 3]
print(copied_list)    # Output: [99, 2, 3]

 


예제에서는 original_list의 참조를 copied_list에 할당했습니다. 나중에 original_list를 수정했을 때 copied_list에도 변경 사항이 반영되었습니다. 두 변수 모두 메모리에서 동일한 객체를 참조하기 때문입니다.

참조 복사는 새 개체를 만들고 값을 복사할 필요가 없기 때문에 특히 큰 개체로 작업할 때 값 복사보다 더 효율적일 수 있습니다. 그러나 하나의 참조를 통해 개체에 대한 변경 사항이 동일한 개체에 대한 다른 모든 참조에 영향을 미치므로 의도하지 않은 부작용이 발생할 수도 있습니다. 이러한 부작용을 방지하기 위해 개체의 전체 복사본을 만들 수 있습니다. 그러면 원래 개체 값의 복사본과 모든 중첩된 개체를 사용하여 새 개체가 생성됩니다.

반응형
반응형

목차

  1. 스택(stack)
  2. 힙(heap)

스택(stack)

스택은 LIFO(Last In First Out) 원칙을 따르는 선형 데이터 구조입니다. 즉, 스택에 추가된 마지막 요소가 제거되는 첫 번째 요소입니다. 스택은 스택의 맨 위에서 항목이 추가(푸시)되거나 제거(팝)되는 항목 모음으로 시각화할 수 있습니다. LIFO 특성으로 인해 스택은 상위 요소에 대한 액세스만 허용하고 하위 요소는 허용하지 않습니다.

스택과 관련된 두 가지 기본 작업이 있습니다.

  • Push: 스택 맨 위에 요소를 추가합니다.
  • Pop: 스택에서 맨 위 요소를 제거합니다.


스택에는 다음과 같은 보조 작업도 있을 수 있습니다.

  • Peek 또는 Top: 스택의 맨 위 요소를 제거하지 않고 반환합니다.
  • IsEmpty: 스택이 비어 있는지 확인합니다.
  • Size: 스택의 요소 수를 반환합니다.


다음은 목록을 사용하여 Python에서 간단한 스택 구현의 예입니다.

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.is_empty():
            return self.items.pop()

    def peek(self):
        if not self.is_empty():
            return self.items[-1]

    def is_empty(self):
        return len(self.items) == 0

    def size(self):
        return len(self.items)

# Using the stack
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.pop())  # Output: 3
print(stack.peek())  # Output: 2
print(stack.is_empty())  # Output: False
print(stack.size())  # Output: 2

 


이 예에서는 목록을 사용하여 요소를 저장하는 Stack 클래스를 만들었습니다. 이 클래스에는 푸시, 팝, 엿보기, 스택이 비어 있는지 확인, 스택 크기 찾기 등의 메서드가 있습니다. 그런 다음 스택을 사용하여 LIFO 원칙에 따라 다양한 작업을 수행할 수 있습니다.


힙(heap)

힙은 힙 속성을 충족하는 특수 트리 기반 데이터 구조입니다. 완전한 이진 트리입니다. 즉, 왼쪽에서 오른쪽으로 채워지는 마지막 수준을 제외하고 트리의 각 수준이 완전히 채워집니다. 힙에서 각 노드의 키는 자식 키보다 크거나 같거나(max-heap) 작거나 같습니다(min-heap).

힙에는 두 가지 유형이 있습니다.

  • 최대 힙(Max-heap)
    최대 힙에서 부모 노드는 자식 키보다 크거나 같은 키를 가집니다. 가장 큰 키는 루트 노드에 있습니다.

  • 최소 힙(Min-heap)
    최소 힙에서 부모 노드는 자식 키보다 작거나 같은 키를 가집니다. 가장 작은 키는 루트 노드에 있습니다.


힙은 일반적으로 우선 순위 큐를 구현하는 데 사용되며 우선 순위가 가장 높거나 낮은 요소에 효율적으로 액세스할 수 있습니다. 힙의 가장 일반적인 응용 프로그램은 힙 데이터 구조를 사용하여 요소를 정렬하는 힙 정렬 알고리즘입니다.

힙과 관련된 몇 가지 일반적인 작업은 다음과 같습니다.

  • 삽입(Insert): 힙 속성을 유지하면서 요소를 힙에 추가합니다.
  • 추출(Extract): 힙에서 루트 요소(최대 또는 최소)를 제거하고 반환한 다음 힙 속성을 유지하도록 힙을 재구성합니다.
  • Peek: 루트 요소(최대 또는 최소)를 제거하지 않고 반환합니다.


Python에서 heapq 모듈은 최소 힙이 있는 힙 데이터 구조의 구현을 제공합니다. 다음은 heapq 모듈을 사용하여 최소 힙을 만드는 예입니다.

import heapq

heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)

print(heap)  # Output: [1, 3, 2]

smallest_element = heapq.heappop(heap)
print(smallest_element)  # Output: 1
print(heap)  # Output: [2, 3]

# Peek at the smallest element without removing it
smallest_element = heap[0]
print(smallest_element)  # Output: 2

 


이 예제에서는 heapq 모듈을 사용하여 최소 힙을 만듭니다. heappush 함수를 사용하여 요소를 힙에 삽입하고 heappop 함수를 사용하여 가장 작은 요소를 제거합니다. 제거하지 않고 가장 작은 요소를 살펴보려면 목록의 첫 번째 요소(인덱스 0)에 액세스하면 됩니다. heapq 모듈은 최대 힙 구현을 제공하지 않지만 값을 삽입하기 전과 추출한 후에 값을 부정하여 최대 힙을 생성할 수 있습니다.

반응형
반응형

목차

  1. Key 매개 변수
  2. 콜백 함수

Key 매개 변수

Python에서 key 매개변수는 sorted(), min() 및 max()와 같은 특정 내장 목록 함수와 함께 사용되어 함수의 동작을 사용자 정의할 수 있습니다. 'key' 매개변수는 목록의 각 요소에서 비교 키를 추출하는 데 사용되는 함수를 사용합니다.

다음은 목록과 함께 key 매개변수를 사용하는 방법의 예입니다.

# 샘플 튜플 리스트
my_list = [(1, 'apple'), (4, 'banana'), (2, 'cherry'), (3, 'date')]

# 리스트를 각 튜플의 두 번째 요소를 기준으로 정렬
sorted_list = sorted(my_list, key=lambda x: x[1])
print("Sorted list:", sorted_list)
# Output: [(1, 'apple'), (4, 'banana'), (2, 'cherry'), (3, 'date')]

# 첫 번째 요소 중 최솟값을 가지는 튜플 찾기
min_element = min(my_list, key=lambda x: x[0])
print("Minimum element:", min_element)  # Output: (1, 'apple')

# 첫 번째 요소 중 최댓값을 가지는 튜플 찾기
max_element = max(my_list, key=lambda x: x[0])
print("Maximum element:", max_element)  # Output: (4, 'banana')

 


이 예에는 my_list 튜플 목록이 있습니다. key 매개변수와 함께 sorted(), min() 및 max() 함수를 사용하여 목록을 정렬하고 다양한 기준에 따라 최소 및 최대 요소를 찾습니다. 람다 함수를 키 매개변수로 사용하여 비교 기준을 지정합니다. 이 경우 비교를 위해 각 튜플의 첫 번째 또는 두 번째 요소를 추출합니다.

이 접근 방식은 비교 값을 추출하는 적절한 키 기능을 제공하는 한 사전, 개체 또는 기타 데이터 구조 목록에도 적용할 수 있습니다.


콜백 함수

콜백 함수는 다른 함수에 인수로 전달되어 다른 함수 내의 특정 지점에서 실행되는 함수입니다. 콜백 함수를 람다로 변환하려면 명시적 함수 정의를 동일한 기능을 가진 람다 식으로 바꿔야 합니다.

이를 보여주는 예는 다음과 같습니다.

먼저 다른 함수를 콜백으로 사용하는 간단한 함수와 콜백을 적용할 값을 생성해 보겠습니다.

def apply_callback(callback, value):
    return callback(value)


이제 숫자를 제곱하는 간단한 콜백 함수를 만들어 보겠습니다.

def square(x):
    return x * x


이 콜백 함수를 apply_callback() 함수와 함께 사용할 수 있습니다.

result = apply_callback(square, 4)
print(result)  # Output: 16


이제 square() 함수를 람다식으로 변환해 보겠습니다.

square_lambda = lambda x: x * x


이 람다 식을 apply_callback() 함수와 함께 콜백 함수로 사용할 수 있습니다.

result = apply_callback(square_lambda, 4)
print(result)  # Output: 16

 


보시다시피 square() 콜백 함수를 람다 식으로 성공적으로 변환하고 apply_callback() 함수와 함께 사용했습니다. 기능은 동일하게 유지되지만 람다 식을 사용하면 콜백 함수를 보다 간결하게 표현할 수 있습니다.

반응형
반응형

목차

  1. Iterable
  2. Iterator
  3. Generator
  4. Generator 표현식

Iterable

Iterable은 for 루프를 사용하여 반복할 수 있는 객체입니다. Python에서 리스트, 튜플, 문자열, 딕셔너리 및 세트는 반복 가능 항목의 예입니다. for 루프에서 iterable을 사용하여 요소를 하나씩 반복할 수 있습니다.

다음은 Python에서 iterable을 사용하는 방법에 대한 몇 가지 예입니다.

1. 리스트를 통해 반복

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

 


2. 튜플을 통해 반복

colors = ("red", "green", "blue")
for color in colors:
    print(color)

 


3. 문자열을 통해 루핑(문자별로)

text = "Hello, World!"
for character in text:
    print(character)

 


4. 딕셔너리를 통한 반복(키 사용)

person = {"name": "John", "age": 30, "city": "New York"}
for key in person:
    print(key, person[key])

 


5. 딕셔너리를 통한 반복(키-값 쌍을 얻기 위해 items 메서드 사용)

person = {"name": "John", "age": 30, "city": "New York"}
for key, value in person.items():
    print(key, value)

 


6. 세트를 통한 루핑

unique_numbers = {1, 2, 3, 4, 5}
for number in unique_numbers:
    print(number)

 


이러한 각 예제에서 우리는 iterable의 요소(리스트, 튜플, 문자열, 딕셔너리 또는 집합)를 반복하고 각 요소에서 작업(이 경우 요소 인쇄)을 수행하기 위해 for 루프를 사용합니다.


Iterator

Iterator는 Python에서 iterator 프로토콜을 구현하는 객체이며 __iter__() 및 __next__() 메서드로 구성됩니다. iterator는 항목 모음을 하나씩 반복하는 데 사용되어 각 항목에 대한 작업을 수행할 수 있습니다.

Python에서 iterator를 사용하는 방법은 다음과 같습니다.

1. 리스트, 튜플 또는 문자열과 같은 반복 가능한 객체를 만듭니다.

fruits = ["apple", "banana", "cherry"]


2. iter() 함수를 사용하여 iterable에서 iterator 객체를 만듭니다.

fruit_iterator = iter(fruits)


3. iterator에서 다음 항목을 가져오려면 next() 함수를 사용하십시오.

print(next(fruit_iterator))  # Output: apple
print(next(fruit_iterator))  # Output: banana
print(next(fruit_iterator))  # Output: cherry


4. iterator에 더 이상 항목이 없을 때 next()를 다시 호출하려고 하면 StopIteration 예외가 발생합니다.

print(next(fruit_iterator))  # Raises StopIteration exception

 

 

  • 'for' 루프를 사용하여 iterator의 요소를 반복할 수도 있습니다.
fruits = ["apple", "banana", "cherry"]
fruit_iterator = iter(fruits)

for fruit in fruit_iterator:
    print(fruit)

 


for 루프는 StopIteration 예외를 자동으로 처리하므로 for 루프를 사용할 때 이에 대해 걱정할 필요가 없습니다.

다음은 사용자 정의 iterator 클래스를 사용하는 또 다른 예입니다.

class CountUpTo:
    def __init__(self, limit):
        self.limit = limit

    def __iter__(self):
        self.value = 0
        return self

    def __next__(self):
        if self.value > self.limit:
            raise StopIteration
        self.value += 1
        return self.value

counter = CountUpTo(5)
counter_iterator = iter(counter)

for number in counter_iterator:
    print(number)

 


이 예제에서는 1부터 주어진 한계까지 세는 사용자 정의 iterator 클래스 CountUpTo를 정의합니다. 이 클래스는 iterator 프로토콜을 준수하기 위해 __iter__() 및 __next__() 메서드를 구현합니다. 그런 다음 클래스의 인스턴스를 만들고 iterator를 만들고 for 루프를 사용하여 숫자를 반복합니다.


Generator

Python의 Generator는 클래스가 아닌 함수를 사용하는 특별한 유형의 iterator입니다. Generator를 사용하면 보다 간결하고 메모리 효율적인 방식으로 iterator를 만들 수 있습니다. Generator 함수에는 Generator를 반복할 때 생성할 값을 지정하는 하나 이상의 yield 문이 포함되어 있습니다.

Python에서 Generator를 사용하는 방법은 다음과 같습니다.

1. yield 문을 사용하여 Generator 함수를 정의합니다.

def count_up_to(limit):
    value = 1
    while value <= limit:
        yield value
        value += 1


이 예에서는 1에서 주어진 한계까지 세는 Generator 함수 count_up_to를 정의합니다. 이 함수는 while 루프와 yield 문을 사용하여 숫자를 생성합니다.

2. Generator 함수를 호출하여 Generator 객체를 생성합니다.

counter_generator = count_up_to(5)


3. for 루프를 사용하여 Generator 개체를 반복합니다.

for number in counter_generator:
    print(number)

 


Generator 개체를 반복할 때 Python은 자동으로 Generator 함수를 호출하고 yield 문을 처리하므로 iterator 프로토콜을 수동으로 구현하지 않고도 값을 하나씩 생성할 수 있습니다.


Generator는 대용량 데이터 세트로 작업하거나 계산 비용이 많이 드는 일련의 값을 생성할 때 특히 유용합니다. Generator는 즉시 값을 생성하기 때문에 모든 값을 한 번에 저장하기 위해 리스트나 기타 데이터 구조를 만드는 것과 비교하여 메모리를 절약하고 성능을 향상시킬 수 있습니다.

다음은 Generator를 사용하여 피보나치 수열을 생성하는 또 다른 예입니다.

def fibonacci(limit):
    a, b = 0, 1
    while a <= limit:
        yield a
        a, b = b, a + b

fibonacci_generator = fibonacci(10)

for number in fibonacci_generator:
    print(number)

 


이 예제에서는 주어진 한계까지 피보나치 수열을 생성하는 Generator 함수 'fibonacci'를 정의합니다. 이 함수는 'while' 루프와 'yield' 문을 사용하여 시퀀스의 숫자를 생성합니다. 그런 다음 함수에서 Generator 개체를 만들고 for 루프를 사용하여 반복합니다.


Generator 표현식

Generator 표현식과 Generator 함수는 Python에서 제너레이터를 만드는 두 가지 방법으로, 보다 메모리 효율적인 방식으로 iterator를 만드는 데 사용됩니다. 둘 다 반복하면서 즉시 값을 한 번에 하나씩 생성할 수 있습니다.


1. Generator 함수:

Generator 함수는 하나 이상의 yield 문을 포함하는 일반 Python 함수입니다. 함수가 호출되면 for 루프 또는 next() 함수를 사용하여 반복할 수 있는 제너레이터 객체를 반환합니다.

Generator 함수의 예시는 다음과 같습니다.

def count_up_to(limit):
    value = 1
    while value <= limit:
        yield value
        value += 1

counter_generator = count_up_to(5)

for number in counter_generator:
    print(number)

 


2. Generator 표현식

제너레이터 표현식은 한 줄의 코드를 사용하여 제너레이터를 만드는 보다 간결한 방법입니다. 컴프리헨션을 나열하는 구문과 비슷하지만 대괄호 대신 괄호를 사용합니다.

Generator 표현식의 예시는 다음과 같습니다.

squared_numbers = (x * x for x in range(1, 6))

for number in squared_numbers:
    print(number)


이 예에서는 1에서 5까지 각 숫자의 제곱을 계산하는 Generator 표현식을 만듭니다. 그런 다음 'for' 루프를 사용하여 Generator 표현식을 반복할 수 있습니다.

3. 차이점
제너레이터 함수는 여러 줄의 코드를 포함하고 여러 값을 'yield'하고 루프 및 조건문과 같은 제어 구조를 사용할 수 있으므로 제너레이터 표현식보다 더 유연합니다.
제너레이터 표현식은 간단한 사용 사례에 대해 더 간결하고 읽기 쉽지만 제너레이터 함수에 비해 기능이 제한적입니다.

Generator 함수와 Generator 표현식은 모두 대규모 데이터 세트로 작업하거나 계산 비용이 많이 드는 일련의 값을 생성할 때 유용합니다. 모든 값을 한 번에 저장하기 위해 리스트 또는 기타 데이터 구조를 만드는 것과 비교하여 메모리를 절약하고 성능을 향상시킬 수 있습니다.

반응형

'Python > Python 기본' 카테고리의 다른 글

[Python] 스택(stack)과 힙(heap)  (0) 2023.04.30
[Python] key 매개 변수, 콜백 함수  (0) 2023.04.30
[Python] 텍스트 파일 처리  (0) 2023.04.30
[Python] 람다(Lambda)란?  (0) 2023.04.30
[Python] 파이썬 튜플(tuple)이란?  (2) 2023.04.30