Python_기초문법9

Jingi·2024년 1월 25일

Python

목록 보기
9/32
post-thumbnail

1. 상속


  • 기존 클래스의 속성과 메서드를 물려받아 새로운 하위 클래스를 생성하는 것

1. 상속이 필요한 이유

  • 코드의 재사용
    • 중복된 코드 감소
    • 기존 클래스의 속성과 메서드 재사용
  • 계층 구조
    • 상속을 통해 클래스들 간의 계층 구조 형성
    • 더 구체적인 클래스 생성
  • 유지 보수의 용이성
    • 수정이 필요한 경우 클래스만 변경하면 되기 떄문
    • 코드 일관성 유지 및 수정 범위 최소화


[참조]https://dojang.io/mod/page/view.php?id=2384

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self): # 메서드 재사용
        print(f'반갑습니다. {self.name}입니다.')


class Professor(Person):
    def __init__(self, name, age, department):
        self.name = name
        self.age = age
        self.department = department


class Student(Person):
    def __init__(self, name, age, gpa):
        self.name = name
        self.age = age
        self.gpa = gpa


  p1 = Professor('박교수', 49, '컴퓨터공학과')
  s1 = Student('김학생', 20, 3.5)

  # 부모 Person 클래스의 talk 메서드를 활용
  p1.talk() # 반갑습니다. 박교수입니다.

  # 부모 Person 클래스의 talk 메서드를 활용
  s1.talk() # 반갑습니다. 김학생입니다.

2. Super()

  • 부모 클래스 객체를 반환하는 내장 함수

1. super() 사용 예시

  • 사용 전

    class Person:
        def __init__(self, name, age, number, email):
            self.name = name
            self.age = age
            self.number = number
            self.email = email
class Student(Person):
    def __init__(self, name, age, number, email, student_id):
        self.name = name
        self.age = age
        self.number = number
        self.email = email
        self.student_id = student_id
```
  • 사용 후

    class Person:
        def __init__(self, name, age, number, email):
            self.name = name
            self.age = age
            self.number = number
            self.email = email
class Student(Person):
    def __init__(self, name, age, number, email, student_id):
        # 부모클래스의 init 메서드 호출
        super().__init__(name, age, number, email)
        self.student_id = student_id
```

3. 다중 상속

  • 둘 이상의 상위 클래스부터 여러 행동이나 특징을 상속받을 수 있는 것
  • 상속받은 모든 클래스의 요소를 활용 가능
  • 중복된 속성이나 메서드가 있는 경우 상속 순서에 의해 결정

1. MRO

  • 메서드 결정 순서
  • 왼쪽부터 찾고 없으면 오른쪽을 찾는 식

2. super()

  • 부모 클래스 객체를 반환하는 내장 함수
    • 다중 상속 시 MRO 기반으로 현재 클래스가 상속하는 모든 부 클래스 중 다음에 호출될 메서드를 결정하여 자동으로 호출

3. mro() 메서드

  • 해당 인스턴스의 클래스가 어떤 부모 클래스를 가지는지 확인하는 메서드
  • 기존의 인스턴스 -> 클래스 순으로 이름 공간을 탐색하는 과정에서 상속 관계에 있으면 인스턴스 -> 자식 클래스 -> 부모 클래스 확장
# super 사용 예시 - 1

class ParentA:
    def __init__(self):
        self.value_a = 'ParentA'
    def show_value(self):
        print(f'Value from ParentA: {self.value_a}')


class ParentB:
    def __init__(self):
        self.value_b = 'ParentB'
    def show_value(self):
        print(f'Value from ParentB: {self.value_b}')


class Child(ParentA, ParentB):
    def __init__(self):
        super().__init__() # ParentA 클래스의 __init__ 메서드 호출
        self.value_c = 'Child'
    def show_value(self):
        super().show_value() # ParentA 클래스의 show_value 메서드 호출
        print(f'Value from Child: {self.value_c}')

child = Child()
child.show_value()
# Value from ParentA: ParentA
# Value from Child: Child
# super 사용 예시 - 2

class A:
    def __init__(self):
        print('A Constructor')

class B(A):
    def __init__(self):
        super().__init__()
        print('B Constructor')

class C(A):
    def __init__(self):
        super().__init__()
        print('C Constructor')
        
class D(B, C):
    def __init__(self):
        super().__init__()
        print('D Constructor')

obj = D()
print(D.mro())
# A Constructor
# C Constructor
# B Constructor
# D Constructor
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

4. super 2 가지 사례

  • 단일 상속 구조
    • 명시적으로 이름을 지정하지 않고 부모 클래스 참조가 가능해 코드 유지 관리가 쉽다
    • super을 사용하면 이름이 바뀌더라도 더 쉽게 수정 가능
  • 다중 상속 구조
    • MRO를 따른 메서드 호출
    • 복잡한 다중 상속 구조에서 발생할 수 있는 문제를 방지

5. MRO가 필요한 이유?

  • 순서를 보존하며 단조적인 구조 형성이 가능하다.
  • 언어의 신뢰성 있고 확장성 있는 클래스를 설계할 수 있다.
  • 코드의 재 사용성과 유지보수성이 향상한다.

2. 에러와 예외


1. 버그

  • 소프트웨어에서 발생하는 오류 또는 결함
  • 프로그램의 예상된 동작과 실제 동작 사이의 불일치

2. 디버깅

  • 소프트웨어에서 발생하는 버그를 찾아내고 수정하는 과정
  • 프로그램의 오작동 원인을 식별하여 수정하는 작업

1. 디버깅 방법

  • print 함수 활용
  • 개발환경 등에서 제공한느 기능활용
  • Python tutor 활용
  • 뇌 컴파일, 눈 디버깅 등

3. 에러

  • 프로그램 실행 중에 발생하는 예외 상황

1. 에러 유형

  • 문법 에러(Syntax Error)
    • 프로그램의 구문이 올바르지 않은 경우 발생
  • 예외(Exception)
    • 프로그램 실행 중에 감지되는 에러

2. 예시

  • invalid synatx(문법 오류)
while # SyntaxError : invalid syntax
  • assign to literal(잘못된 할당)
5 = 3 # SyntaxError : cannot assign to literal
  • EOL(End of Line)
print('hello # SyntaxError : EOL while scanning string literal
  • EOF(End of File)
print( # SyntaxError : unexpceted EOF while parsing

4. 예외

  • 프로그램 실행 중에 감지되는 에러

1. 내장 예외

  • 예외 상황을 나타내는 예외 클래스들
    • 파이썬에서 이미 정의되어 있으며, 특정 예외 상황에 대한 처리를 위해 사용
  • ZeroDivisionError : 나누기 또는 모듈로 연산의 두 번째 인자가 0일 때 발상
  • NameError: 지역 또는 전역 이름을 찾을 수 없을 때 발생
  • TypeError
    • 타입 불일치
    • 인자 누락
    • 인자 초과
    • 인자 타입 불일치
  • ValueError
    • 연산이나 함수에 문제가 없지만 부적절한 값을 가진 인자를 받았고, 상황이 IndexError 처럼 더 구체적인 예외로 설명되지 않는 경우 발생
  • IndexError
    • 시퀀스 인덱스가 범위를 벗어날 때 발생
  • KeyError
    • 딕셔너리에 해당키가 존재하지 않는 경우
  • ModuleNotFoundError
    • 모듈을 찾을 수 없을 때 발생
  • importError
    • 임포트 하려는 이름을 찾을 수 없을 때 발생
  • KeyboardInterrupt
    • 사용자가 Control-C 또는 Delete를 누를 떄 발생
  • IndentationError
    • 잘못된 들여쓰기와 관련된 문법 오류

5. try와 except

1. 구조

  • try 블록 안에는 예외가 발생할 수 있는 코드 작성
  • except 블록 안에는 예외가 발생했을 때 코드 작성
try :
  # 예외가 발생할 수 있는 코드
except : 예외
  # 예외 처리 코드
try:
    num = int(input('100으로 나눌 값을 입력하시오 : '))
    print(100 / num)
except (ValueError, ZeroDivisionError):
    print('제대로 입력해주세요.')

2. 내장 예외의 상속 계층구조 주의

  • 내장 예외 클래스는 상속 계층구조를 가지기 때문에 except 절로 분기시 반드시 하위 클래스를 먼저 확인 할 수 있도록 작성해야함

3. 참고

  • as 키워드
    • as 키워드를 활용하여 에러 메시지를 except 블록에서 사용 가능
my_list = []

try:
    number = my_list[1]
except IndexError as error:
    print(f'{error}가 발생했습니다.')

# list index out of range가 발생했습니다.

6. EAFP & LBYL

1. EAFP

  • 예외처리르 중심으로 코드를 작성하는 접근 방식(try-except)

2. LBYL

  • 값 검사를 중심으로 코드를 작성하는 접근 방식(if - else)
EAFPLBYL
"일단 실행하고 예외를 처리""실행하기 전에 조건을 검사
코드를 실행하고 예외가 발생하면 예외처리를 수행코드 실행전에 조건문 등을 사용하여 예외 상황을 미리 검사하고, 예외 상황을 피하는 방식
코드에서 예외가 발생할 수 있는 부분을 미리 예측하여 대비하는 것이 아니라, 예외가 발생한 후에 예외를 처리코드가 좀 더 예측 가능한 동작을 하지만, 코드가 더 길고 복잡해질 수 있음
예외 상황을 예측하기 어려운 경우에 유용예외 상황을 미리 방지하고 싶을 때 유용
profile
데이터 분석에서 백엔드까지...

0개의 댓글