파이썬 기초 - 객체, 상속, 예외

BlackLabel·2023년 8월 9일
0

파이썬 이론

목록 보기
5/8

53. 객체와 메모리

추상화

  • 프로그래밍에서 복잡한 기능이나 데이터를 간단한 형태로 만드는 것을 의미
  • 클래스는 추상화의 도구로, 어떤 것의 공통된 특징을 모아서 하나의 틀로 만든다.
  • 이 틀을 이용해 구체적인 객체를 만드는데, 이 구체적인 객체를 인스턴스라고 한다.

변수는 객체의 메모리 주소를 저장하고 이를 이용해서 객체를 참조한다.

Robot 이라는 클래스를 생성 후 객체를 두개 생성함

이 두 객체를 참조하는 rb1과 rb2라는 변수는 메모리에 저장이 되어있는 것이아니라 메모리 바깥의 공간에 존재하고 객체의 '주소값'을 저장한 것

다시말해, 변수 rb1과 rb2는 객체의 메모리 주소를 저장하고 이를 이용해서 객체를 참조하고 있는 것

54. 객체의 얕은복사와 깊은복사

얕은 복사

객체 주소를 복사하는 것(객체 자체가 복사되지는 않음)

위 에서 rb1과 rb2가 하나의 객체를 참조하게 하려면 다음과 같이 입력


얕은 복사의 경우, 위의 예시처럼 rb2 라는 새로운 객체를 생성하지만, 그 안에 들어가는 내용은 rb1와 같은 객체이다.

깊은 복사

객체 자체를 복사하는 것(또 하나의 객체가 만들어짐)


깊은 복사의 경우, 복사를 위해 주소 값이 다른 새로운 객체를 생성하고, 내부의 객체들까지 모두 새롭게 생성된다.

55. 클래스 상속

  • 한 클래스가 다른 클래스의 속성과 메소드를 물려받아 사용하는 것을 의미 (class2가 class1 상속시 class2는 class1의 모든 기능 사용가능)
  • 상속은 클래스 정의 시 괄호안에 부모 클래스를 명시함으로써 구현할 수 있다.

예시

class Animal:
    def __init__(self, species, age, name):
        self.species = species
        self.age = age
        self.name = name
        
    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    def make_sound(self):
        print(f"{self.name}이(가) 소리를 냅니다.")

위 Animal 클래스를 기반으로 상속을 설명

class Dog(Animal):
    def bark(self):
        print(f"{self.name}이(가) 멍멍 짖습니다.")

class Cat(Animal):
    def meow(self):
        print(f"{self.name}이(가) 야옹 소리를 냅니다.")

Dog 클래스와 Cat클래스는 각각 Bark와 meow라는 메소드를 추가로 정의했다. 이렇게 상속을 통해 기존 클래스의 기능을 확장하거나 변경할 수 있다.

56. 생성자

객체가 생성될 때 생성자를 호출하면 init() 메서드가 자동 호출되며, 메모리에 생성된 객체 공간에 데이터를 넣거나 초기화하는 목적으로 사용한다.

class B에서 class A의 속성값은 복사가 안되지만 기능은 복사가 되는 것을 알 수 있다.

super()

상위 클래스의 속성을 초기화 할 수 있음
즉 클래스 상속을 받으면 기능은 상속하여 사용할 수 있지만, 속성은 init메서드가 호출되어야지만 속성이 초기화되면서 사용할 수 있다.

P_class.__init__(self, cNum1, cNum2)super().__init__(cNum1, cNum2) 는 같은 말이다.

즉, super()는 상속받은 부모 클래스를 의미
상위 클래스의 init()에 있는 클래스 변수들을 가지고 올 수 있다.

57. 다중상속

2개 이상의 클래스를 상속받는 경우
꼭 필요한 경우가 아니면 사용을 남발하지 않도록 해야한다. 왜냐하면 동일한 메소드를 각 클래스에 갖고 있는 경우 출력시 원치 않는 결과값을 갖게 되기도 하는 등 프로그램을 개발하는데 읽기 쉬운 코드가 되지 않을 수 있다.

58. 오버로딩과 오버라이딩

  • 오버로딩: 같은 이름의 메소드나 연산자를 여러개 정의하고, 이들이 다른 매개변수의 개수, 타입 또는 순서를 가지도록 하는 것
  • 오버라이딩: 상속을 통해 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의하는 것

하위 클래스에서 상위 클래스의 메서드를 재정의(override)함
덮어쓰기라고도 함

class Dog(Animal):
    # 오버라이딩 예시
    def make_sound(self):
        print(f"{self.name}이(가) 멍멍 소리를 냅니다.")

    # 오버로딩 예시
    def play(self, toy):
        if isinstance(toy, str):
            print(f"{self.name}이(가) {toy}로 놀고 있습니다.")
        else:
            print(f"{self.name}이(가) 놀고 있습니다.")

class Cat(Animal):
    # 오버라이딩 예시
    def make_sound(self):
        print(f"{self.name}이(가) 야옹 소리를 냅니다.")

dog = Dog("멍멍이", 3)
cat = Cat("야옹이", 2)

dog.eat()
dog.move()
dog.make_sound()  # 오버라이딩 된 메소드 호출
dog.play("뽀로로 인형")  # 오버로딩 된 메소드 호출 (문자열 인자 사용)
dog.play(123)  # 오버로딩 된 메소드 호출 (정수 인자 사용)

cat.eat()
cat.move()
cat.make_sound()  # 오버라이딩 된 메소드 호출

실습 : 삼각형 넓이를 계산하는 클래스를 만들고 이를 상속하는 클래스에서 getArea()를 오버라이딩 해서 출력 결과에 제곱센치미터가 추가 될 수 있도록 만들어보자

하위 클래스의 getArea()메서드에서 상위 클래스를 강제 상속받아 문자열(str)로 고쳐준 다음 제곱센치미터를 붙여준 것을 확인 할 수 있다.(숫자+문자는 오류가 나므로 숫자를 문자형태로 바꿔준다.)

59. 추상클래스

  • 추상 클래스: 추상 메서드를 가지고 있는 클래스(추상 메서드는 메서드의 선언만 있고 구현이 없는 메서드)
  • 추상 클래스를 상속받은 클래스는 반드시 추상 메서드를 구현해야 한다.
  • 상위 클래스에서 하위 클래스에 메서드 구현을 강요한다.
  • 현재 클래스에서 행동(메서드)를 지정하기 애매하거나 너무 다양할 때 사용한다.
  • abc 모듈을 이용

기본구조

from abc import abstractmethod
class 함수명(metaclass=ABCMeta):
    @abstractmethod
    def 함수명

아래 코드에서 Animal 클래스는 추상 클래스로 정의되어 있으며 make_sound 메서드는 추상 메서드로 선언

  • 추상 메서드로 선언된 make_sound 메서드는 자식 클래스인 dog와 cat에서 오버라이딩되어 각 동물이 낼 수 있는 소리에 맞게 구현되었음.
from abc import ABC, abstractmethod

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

    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    @abstractmethod
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        print(f"{self.name}이(가) 멍멍 소리를 냅니다.")

class Cat(Animal):
    def make_sound(self):
        print(f"{self.name}이(가) 야옹 소리를 냅니다.")

dog = Dog("멍멍이", 3)
cat = Cat("야옹이", 2)

dog.eat()
dog.move()
dog.make_sound()

cat.eat()
cat.move()
cat.make_sound()

예를들어, Person이라면 eat, sleep 등이 있을 것이다. 그런데 Person이 직접 밥을 어떻게 먹고, 어떻게 잠을 자고하는 것을 정의할 수는 없다. 이건 구체적인 각 인간들마다 다르기 때문이다. 그렇기 때문에 Person의 eat, sleep 등을 추상메서드로 두고 자식 클래스에서 구현하도록 하는 것이다.

from abc import *

class Person(metaclass=ABCMeta):
    @abstractmethod
    def eat(self):
        pass

    @abstractmethod
    def sleep(self):
        pass

class James(Person):
    def eat(self):
        print("chop chop")

    def sleep(self):
        print("coa coa")

class Dean(Person):
    def eat(self):
        print("yam yam")

    def sleep(self):
        print("zzzz")
    

james = James()
dean = Dean()

james.eat() # chop chop
james.sleep() # coa coa
dean.eat() # yam yam
dean.sleep() # zzzz

다음과 같이 Person의 eat, sleep을 James와 Dean이 상속받아 오버라이딩하면 된다. 만약 오버라이딩을 하지 않으면 에러가 발생하게 된다.

60. 예외와 예외 처리

예외는 문법적인 문제는 없으나 실행 중 발생하는 예상하지 못한 문제이다. (하지만, 에러예외는 다름. 에러는 문법적인 오류 또는 소프트웨어적인 오류를 얘기함)

예외 관련 클래스는 Exception 클래스를 상속한다.
(모든 예외를 처리하고 싶다면, except문에서 Exception을 사용한다.)

ZeroDivisionError : 0으로 나누었을 때 예외를 발생시키는 클래스
IOError : 입출력과 관련된 에러가 발생했을 때 예외를 발생시키는 클래스
IndexError : List에서 예를들어 길이가 5인 List(인덱스는 4번까지 존재)에서 5번 인덱스를 찾는 경우 예외를 발생시키는 클래스
IndentationError : 들여쓰기에 관련하여 에러가 발생했을 때 예외를 발생시키는 클래스
ValueError : 부적절한 값을 받았을 때 에러가 발생했을 때 예외를 발생시키는 클래스

예외 처리방법: 예외 발생 예상 구문을 try~except 로 감싼다.

n1 = 10
n2 = 0

try:
    print(n1 / n2)    #여기서 에러가 발생하기 때문에 아래의 프로그램들은 실행이 안됨. 
    				  #예외가 발생하지 않으면 정상적으로 (n1 * n2) 넘어간다.
except:               #예외를 처리를 함.
    print('예상치 못한 문제가 발생했습니다.')
    print('다음 프로그램이 정상 실행됩니다.')

print(n1 * n2)
print(n1 - n2)
print(n1 + n2)

61. try~except~else

else

예외가 발생하지 않은 경우 실행하는 구문이다.
try, except 구문을 다 써야 else 쓸수 있음

eveList = [] #짝수 리스트
oddList = [] #홀수 리스트
floatList = [] #실수 리스트
n = 1
while n < 6:
    try:
        num = float(input('숫자를 입력 하세요:'))
    except:
        print("예외 발생")
        continue
    else:
        if num % 2 == 0:
            eveList.append(int(num))
        elif num % 2 == 1:
            oddList.append(int(num))
        elif num % 2 != 1:
            floatList.append(num)
    n += 1
print('짝수리스트:{}'.format(eveList))
print('홀수리스트:{}'.format(oddList))
print('실수리스트:{}'.format(floatList))
#실행결과 
짝수리스트:[2]
홀수리스트:[1, 5]
실수리스트:[2.1, 3.2]

62. finally

어떠한 작업을 하는 과정에서 예외 발생과 상관없이 항상 실행한다.
(try~except 에서 예외가 발생하든 else에서 예외가 발생하지 않든 상관없이 무조건 실행한다라는 의미)

try:
    inputData = input('input number : ')
    numInt = int(inputData)

except:
    print('exception raise!!')
    print('not number!!')
    numInt = 0

else:
    if numInt % 2 == 0:
        print('inputData is even number!!')
    else:
        print('inputData is odd number!!')

finally:
    print(f'inputData : {inputData}')

위에서 numInt에 정수형태로 변환할 수 없는 데이터(문자열 등)가 들어가게 되어도 아래 코드에 따라 무슨 데이터가 들어갔는지 출력해준다.
(예외가 발생했지만 입력한 모든 데이터가 출력)

63. Exception 클래스

Excpetion은 예외를 담당하는 클래스이다.
'except Exception as 변수명' 의 형식으로 사용 (변수를 출력해보면 어떤 이유로 에러가 발생했는지 출력)

except Exception as e:
        print('예외 발생 원인:{}'.format(e))
        continue
 #실행결과 
숫자를 입력 하세요:파이썬 
예외 발생 원인:could not convert string to float: '파이썬 '

사용자 예외 클래스 : Exception 클래스를 상속 받아서 사용자 예외 클래스를 만들 수 있다.

64. 텍스트 파일 쓰기

텍스트 파일 쓰기 함수

  • open('경로명/파일명', 'w') : 파일 열기 (쓰기 모드), 경로에 해당 파일이 있으면 불러오고 없으면 입력한 파일명으로 파일을 새로 만듦 (기존의 내용을 덮어씌움)
  • open('경로명/파일명', 'a') : 파일 열기 (쓰기 모드), 경로에 해당 파일이 있으면 불러오고 없으면 입력한 파일명으로 파일을 새로 만듦 (기존의 내용에 덧붙임)
  • open('경로명/파일명', 'x') : 파일 열기 (쓰기 모드), 경로에 해당 파일이 있으면 에러가 발생하고 없으면 입력한 파일명으로 파일을 새로 만듦
  • write() : 쓰기
  • close() : 파일 닫기
file = open('/Users/seayoon/Desktop/제로베이스취업스쿨/text.txt','w')
strCnt = file.write('hello world!')
print(strCnt) #문자열의 길이를 출력하였다. 
file.close()
#실행결과 
12 

65. 텍스트 파일 읽기

텍스트 파일 읽기 함수
open('경로명/파일명', 'r') : 파일 열기 (읽기 모드), 경로에 해당 파일이 있으면 불러오고 없으면 에러가 발생한다.
read() : 읽기, 쓰기
close() : 파일 닫기

file = open('C:/pythonTxt/test.txt','r')

str = file.read()      # 파일에 있는 데이터는 숫자건 문자건 모두 문자열로 취급한다.
print(f'str : {str}')

file.close()      # 작업을 마치고 꼭 닫아줘야한다. 외부자원(텍스트)과의 연결을 해제 하는것.

66. 텍스트파일닫기(with ~ as 문)

with ~ as문 : 파일 닫기(close)를 생략할 수 있다.
with open('주소명'/'파일명.txt', '모드') as 변수명:
(들여쓰기)변수명.write('입력하려는 문구')
with open('주소명'/'파일명.txt', 'r') as 변수명:
(들여쓰기)변수명.read('입력하려는 문구')

uri = 'C:/pythonTxt/'

file = open(uri + '5_037.txt', 'w')
file.write('python study!!')
file.close()

file = open(uri + '5_037.txt', 'r')
print(file.read())
file.close()

이걸 with~as로 바꾸면

with open(uri + '5_037.txt', 'w') as f:
    f.write('python study!!')

with open(uri + '5_037.txt', 'r') as f:
    print(f.read())
    

67. writelines()

writelines()는 리스트 또는 튜플 데이터를 파일에 쓰기 위한 함수 이다.

languages = ['c/c++', 'java', 'c#', 'python', 'javascript']

uri = 'C:/pythonTxt/'
for item in languages:
     with open(uri + 'languages.txt', 'a') as f:
         f.write(item)
         f.write('\n')

위의 리스트 파일들을 for문을 통해 하나하나 넣는 방법에서 writelines() 함수로 리스트를 한번에 파일에 넣은 것임

languages = ['c/c++', 'java', 'c#', 'python', 'javascript']

uri = 'C:/pythonTxt/'
with open(uri + 'languages.txt', 'w') as f:
    f.writelines(languages)

68. readlines(), readline()

readlines()
파일의 모든 데이터를 (통째로) 읽어서 리스트 형태로 반환한다.

path = '/Users/seayoon/Desktop/제로베이스취업스쿨/'
with open(path + 'test.txt','r') as file:
    result = file.readlines()
print(result)
#실행결과 
['c/c++\n', 'java\n', 'c#\n', 'python\n', 'javascript\n']

readline()
한 행을 하나씩 읽어서 문자열로 반환 한다.
while 문을 넣어서 파일의 한행이 비어있지 않다면 다시 코드가 돌아가게 만들어서 한줄씩읽어서 문자열로 반환하게 만든다.

path = '/Users/seayoon/Desktop/제로베이스취업스쿨/'
with open(path + 'test.txt','r') as file:
    result = file.readline()
    while result != '':
        print(result, end='')
        result = file.readline()
#실행결과 
c/c++
java
c#
python
javascript
profile
+database

1개의 댓글

comment-user-thumbnail
2023년 8월 9일

즐겁게 읽었습니다. 유용한 정보 감사합니다.

답글 달기