- 프로그래밍에서 복잡한 기능이나 데이터를 간단한 형태로 만드는 것을 의미
- 클래스는 추상화의 도구로, 어떤 것의 공통된 특징을 모아서 하나의 틀로 만든다.
- 이 틀을 이용해 구체적인 객체를 만드는데, 이 구체적인 객체를 인스턴스라고 한다.
변수는 객체의 메모리 주소를 저장하고 이를 이용해서 객체를 참조한다.
Robot 이라는 클래스를 생성 후 객체를 두개 생성함
이 두 객체를 참조하는 rb1과 rb2라는 변수는 메모리에 저장이 되어있는 것이아니라 메모리 바깥의 공간에 존재하고 객체의 '주소값'을 저장한 것
다시말해, 변수 rb1과 rb2는 객체의 메모리 주소를 저장하고 이를 이용해서 객체를 참조하고 있는 것
객체 주소를 복사하는 것(객체 자체가 복사되지는 않음)
위 에서 rb1과 rb2가 하나의 객체를 참조하게 하려면 다음과 같이 입력
얕은 복사의 경우, 위의 예시처럼 rb2 라는 새로운 객체를 생성하지만, 그 안에 들어가는 내용은 rb1와 같은 객체이다.
객체 자체를 복사하는 것(또 하나의 객체가 만들어짐)
깊은 복사의 경우, 복사를 위해 주소 값이 다른 새로운 객체를 생성하고, 내부의 객체들까지 모두 새롭게 생성된다.
- 한 클래스가 다른 클래스의 속성과 메소드를 물려받아 사용하는 것을 의미 (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라는 메소드를 추가로 정의했다. 이렇게 상속을 통해 기존 클래스의 기능을 확장하거나 변경할 수 있다.
객체가 생성될 때 생성자를 호출하면 init() 메서드가 자동 호출되며, 메모리에 생성된 객체 공간에 데이터를 넣거나 초기화하는 목적으로 사용한다.
class B에서 class A의 속성값은 복사가 안되지만 기능은 복사가 되는 것을 알 수 있다.
상위 클래스의 속성을 초기화 할 수 있음
즉 클래스 상속을 받으면 기능은 상속하여 사용할 수 있지만, 속성은 init메서드가 호출되어야지만 속성이 초기화되면서 사용할 수 있다.
P_class.__init__(self, cNum1, cNum2) 과
super().__init__(cNum1, cNum2) 는 같은 말이다.
즉, super()는 상속받은 부모 클래스를 의미
상위 클래스의 init()에 있는 클래스 변수들을 가지고 올 수 있다.
2개 이상의 클래스를 상속받는 경우
꼭 필요한 경우가 아니면 사용을 남발하지 않도록 해야한다. 왜냐하면 동일한 메소드를 각 클래스에 갖고 있는 경우 출력시 원치 않는 결과값을 갖게 되기도 하는 등 프로그램을 개발하는데 읽기 쉬운 코드가 되지 않을 수 있다.
- 오버로딩: 같은 이름의 메소드나 연산자를 여러개 정의하고, 이들이 다른 매개변수의 개수, 타입 또는 순서를 가지도록 하는 것
- 오버라이딩: 상속을 통해 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의하는 것
하위 클래스에서 상위 클래스의 메서드를 재정의(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)로 고쳐준 다음 제곱센치미터를 붙여준 것을 확인 할 수 있다.(숫자+문자는 오류가 나므로 숫자를 문자형태로 바꿔준다.)
- 추상 클래스: 추상 메서드를 가지고 있는 클래스(추상 메서드는 메서드의 선언만 있고 구현이 없는 메서드)
- 추상 클래스를 상속받은 클래스는 반드시 추상 메서드를 구현해야 한다.
- 상위 클래스에서 하위 클래스에 메서드 구현을 강요한다.
- 현재 클래스에서 행동(메서드)를 지정하기 애매하거나 너무 다양할 때 사용한다.
- abc 모듈을 이용
from abc import abstractmethod
class 함수명(metaclass=ABCMeta):
@abstractmethod
def 함수명
아래 코드에서 Animal 클래스는 추상 클래스로 정의되어 있으며 make_sound 메서드는 추상 메서드로 선언
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이 상속받아 오버라이딩하면 된다. 만약 오버라이딩을 하지 않으면 에러가 발생하게 된다.
예외는 문법적인 문제는 없으나 실행 중 발생하는 예상하지 못한 문제이다. (하지만, 에러와 예외는 다름. 에러는 문법적인 오류 또는 소프트웨어적인 오류를 얘기함)
예외 관련 클래스는 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)
예외가 발생하지 않은 경우 실행하는 구문이다.
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]
어떠한 작업을 하는 과정에서 예외 발생과 상관없이 항상 실행한다.
(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에 정수형태로 변환할 수 없는 데이터(문자열 등)가 들어가게 되어도 아래 코드에 따라 무슨 데이터가 들어갔는지 출력해준다.
(예외가 발생했지만 입력한 모든 데이터가 출력)
Excpetion은 예외를 담당하는 클래스이다.
'except Exception as 변수명' 의 형식으로 사용 (변수를 출력해보면 어떤 이유로 에러가 발생했는지 출력)
except Exception as e:
print('예외 발생 원인:{}'.format(e))
continue
#실행결과
숫자를 입력 하세요:파이썬
예외 발생 원인:could not convert string to float: '파이썬 '
사용자 예외 클래스 : Exception 클래스를 상속 받아서 사용자 예외 클래스를 만들 수 있다.
텍스트 파일 쓰기 함수
- 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
텍스트 파일 읽기 함수
open('경로명/파일명', 'r') : 파일 열기 (읽기 모드), 경로에 해당 파일이 있으면 불러오고 없으면 에러가 발생한다.
read() : 읽기, 쓰기
close() : 파일 닫기
file = open('C:/pythonTxt/test.txt','r')
str = file.read() # 파일에 있는 데이터는 숫자건 문자건 모두 문자열로 취급한다.
print(f'str : {str}')
file.close() # 작업을 마치고 꼭 닫아줘야한다. 외부자원(텍스트)과의 연결을 해제 하는것.
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())
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)
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
즐겁게 읽었습니다. 유용한 정보 감사합니다.