배우기 앞서, 그냥 돌아가기만 하면 되는거 아닌가!?
객체 지향 프로그래밍 왜 배워야하는데!! 라고 생각한다면 아래의 예시를 생각해보자.
나는야 잘나가는 멋쟁이 개발자1.
근데 실상은 Po구글러wer & 복붙러...! 다른 똑똑이들이 작성해놓은 코드 그냥 갖다 재사용하고 시포...
요구사항에 맞춰 조금만 바꿔서 쓰고 싶당 말이양...!
나는야 멋쟁이 개발자2!
어디 내놔도 부끄럽지 않은 잘키운 내 소스코드면 다른 사람도 편하게 쓸 수 있을 것 같은데!?
모두 코드의 재사용성이 좋아야한다는 것이 포인트다!
☞ 어떻게 잘 구조화 시켜야 할까? 라고 할 때 떠오르는 것이 객체 지향 프로그래밍!
☞ 왜냐면 객체지향 프로그래밍은 수정시 클래스 내부 변수 혹은 메서드로 존재하기 때문에 해당 부분만 수정하면 된다(↔절차 지향 프로그래밍). 다 클래스 단위로 모듈화 시켜 개발했기 때문(이래서 프로젝트로 나눠 개발 하기도 좋지)
☞ 그리고 개발자1 같은 경우엔 다들 객체 지향으로 쓰는데 나도 객체 지향을 알아야 수정하기 쉽다는 코드 쓱 바꿔서 쓰지 & 나도 그렇게 써야하고요 (는 나야나)
그럼 왜 배워야하는지 알았으니 계속 가보자고!
Q. 수강신청 프로그램을 작성한다! 어떻게 해야할까?
수강신청이 시작부터 끝까지 순서대로 작성 (옛날 방식)
수강신청 관련 주체들(교수, 학생, 관리자)의 행동(수강신청, 과목입력)과 데이터들을 중심으로 프로그램 작성 후 연결
→ 최근 방식. '객체 지향 프로그램 기법'
인공지능 축구 프로그램을 작성한다고 가정시,
__init__
, self
와 함께 →__init__
은 객체 초기화 예약함수__init__
, 행동 메서드self.객체
(self에 소속된 객체)으로 객체의 초기정보 입력 def __init__(self, name : str, position : str, back_number: int):
★★ 상식) 파이썬에서 __
의 의미
__
은 특수한 예약 함수나 변수, 함수명 변경(맨글링)으로 사용함__main__
, __add__
(더해줌), __str__
(문자 print), __eq__
class SoccerPlayer(object):
def __str__(self):
return "hi, my name is %s. I play in %s in center" % (self.name, self.position)
# 객체 클래스
chabbo = SoccerPlayer("chabbo", "MF", 10)
print(chabbo)
>>> hi, my name is chabbo. I play in MF in center
chabbo = SoccerPlayer("chabbo", "MF", 10)
Son = SoccerPlayer("Son", "FW", 7)
chabbo is Son
>>> False
print(chabbo)
시<__main__.SoccerPlayer object at 0x000002D541267C40>
이런 식으로 메모리 주소값이 출력됨class SoccerPlayer(object):
def change_back_number(self, new_number):
print('선수의 등 번호를 변경합니다 : from %d to %d' %(self.back_number, new_number))
self.back_number = new_number
chabbo = SoccerPlayer("chabbo", "MF", 10)
print('현재 선수의 등번호는 :', chabbo.back_number)
★★중요) self
가 모야?
chabbo
라는 instance를 생성되면(chabbo = SoccerPlayer("chabbo", "MF", 10)
), 밖에서는 chabbo.back_number
로 변수명(chabbo)으로 쓰지만, code안에서는 self가 chabbo가 됨. 말그래도 자기 자신을 가리킬때 self를 사용.class SoccerPlayer(object):
def __init__(self, name : str, position : str, back_number: int):
self.name = name
self.position = position
self.back_number = back_number
def change_back_number(self, new_number):
print('선수의 등 번호를 변경합니다 : from %d to %d' %(self.back_number, new_number))
self.back_number = new_number
def __str__(self):
return "hi, my name is %s. I play in %s in center. back number is %d" % (self.name, self.position, self.back_number)
chabbo = SoccerPlayer("chabbo", "MF", 10)
print(chabbo)
chabbo.change_back_number(7)
print(chabbo)
>>> hi, my name is chabbo. I play in MF in center. back number is 10
>>> 선수의 등 번호를 변경합니다 : from 10 to 7
>>> hi, my name is chabbo. I play in MF in center. back number is 7
구현 가능한 OOP 만들기 - 노트북
- Note를 정리하는 프로그램
- 사용자는 Note에 뭔가를 적을 수 있다.
- Note에는 Content가 있고, 내용을 제거할 수 있다.
- 두 개의 노트북을 합쳐 하나로 만들 수 있다.
- Note는 Notebook에 삽입된다.
- Notebook은 Note가 삽입 될 때 page를 생성하며, 최고 300page 까지 저장 가능하다.
- 300page가 넘으면 더 이상 노트를 삽입하지 못한다.
class NoteBook():
def __init__(self, title):
self.title = title
self.page_number = 1
self.notes = {}
def add_note(self, note, page = 0):
if self.page_number < 300:
if page == 0:
self.notes[self.page_number] = note
self.page_number += 1
else:
self.notes = {page:note}
self.page_number += 1
else:
print('page가 모두 채워졌습니다.')
def remove_note(self, page_number):
if page_number in self.notes.keys():
return self.notes.pop(page_number) # 와 여기에 pop을..
else:
print('해당 페이지는 존재하지 않습니다.')
def get_number_of_pages(self):
return len(self.notes.keys())
class Note():
def __init__(self, content):
self.content = content
def creat_content(self, content):
self.content = content
return content
def remove_content(self):
self.content = ''
def __add__(self, other):
return self.content + other.content
def __str__(self):
return self.content
from file명 import 함수명
from creat_note import Note
from creat_note import NoteBooK
my_notebook = NoteBook('타이틀')
new_note = Note('오 신기하다')
print(new_note)
>>> 오 신기하다
new_note2 = Note('파이썬')
print(new_note2)
>>> 파이썬
my_notebook = NoteBook('타이틀')
new_note = Note('오 신기하다')
print(new_note)
new_note2 = Note('파이썬')
print(new_note2)
my_notebook.add_note(new_note)
my_notebook.add_note(new_note2, 100)
print(my_notebook.notes[100])
print(my_notebook.get_number_of_pages())
my_notebook.notes[0] = Note('이게 왜안돼')
print(my_notebook.notes[0])
(몰라도 코딩은 할 수 있다)ㅋㅋㅋㅋ
class Employee(Person):
def __init__(self, name, age, gender, salary, hire_date):
super().__init__(name, age, gender) # 부모객체 사용
self.salary = salary
self.hire_date = hire_date
super()
은 부모클래스(person)의 객체를 불러오는 것. self로 자기자신을 불러오듯이, super은 부모클래스를 불러온다.class Person():
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def about_me(self):
print(f'제 이름은 {self.name}이구요, 제 나이는 {str(self.age)}살 입니다.')
def __str__(self):
return (f'제 이름은 {self.name}이구요, 제 나이는 {str(self.age)}살 입니다.')
class Employee(Person):
def __init__(self, name, age, gender, salary, hire_date):
super().__init__(name, age, gender) # 부모객체 사용
self.salary = salary
self.hire_date = hire_date
def do_work(self):
print('열일!')
def about_me(self): # 부모클래스 함수 재정의
super().about_me() # 부모클래스 함수 사용
print(f'제 급여는 {self.salary}원 이구요, 제 입사일은 {self.hire_date}입니다.')
chabbo = Person('chabbo', 31, 'Female')
chiwoo = Employee('chiwoo', 31, "Male", 10000000000, '1992.01.01')
chabbo.about_me()
chiwoo.about_me()
출력 결과
>>> 제 이름은 chabbo이구요, 제 나이는 31살 입니다.
############ 자식 클래스의 출력 결과 #############
# 먼저 super().about_me() 출력
>>> 제 이름은 chiwoo이구요, 제 나이는 31살 입니다.
# 새로 추가한 부분 출력
>>> 제 급여는 10000000000원 이구요, 제 입사일은 1992.01.01입니다.
class Animal():
def __init__(self, name):
self.name = name
def talk(self):
raise NotImplementedError('서브클래스 메소드가 구현되야합니다')
class Cat(Animal):
def talk(self):
return '야옹!'
class Dog(Animal):
def talk(self):
return '멈무!멈무!'
animals = [Cat('냥이'), Cat('옹이'), Dog('멈무미')]
for animal in animals:
print(f'{animal.name} : {animal.talk()}')
냥이 : 야옹!
옹이 : 야옹!
멈무미 : 멈무!멈무!
이렇게 비슷한 일을 할 때! 같은 이름을 쓰되, 내부 코드를 다르게 해서 쉽게 가동할 수 있음
※참고) Encapsulation 이라고도함
Product 객체를 Inventory 객체에 추가
Inventory에는 오직 Product 객체만 들어감
Inventory에 Product가 몇 개인지 확인이 필요
Inventory에 Product items는 직접 접근이 불가
__items
처리
Bad case Code
class Product():
# 빈 더미클래스 생성
pass
class Inventory():
def __init__(self):
self.items = []
self.test = 'abc'
def add_new_item(self, product):
if type(product) == Product:
self.items.append(product)
print('새로운 아이템을 추가했습니다')
else:
raise ValueError('Invalid Item')
def get_number_of_items(self):
return len(self.items)
코드 생성 후 입출력 진행
my_inven = Inventory()
my_inven.add_new_item(Product())
my_inven.add_new_item(Product())
print(my_inven)
print(my_inven.items)
my_inven.items.append('virus')
print(my_inven.items)
개발자가 원한 것은 my_inven.add_new_item(Product())
Product를 이용해서 inventory에 들어가길 원했으나,
my_inven.items.append('virus')
이런식으로 다른 사용자가 직접적으로 inventory에 접근해 추가할 수 있다.
결과 : Product 객체외의 다른 item이 추가됨
새로운 아이템을 추가했습니다
새로운 아이템을 추가했습니다
<__main__.Inventory object at 0x000001734527BCA0>
[<__main__.Product object at 0x000001734527BAF0>, <__main__.Product object at 0x000001734527BAC0>]
[<__main__.Product object at 0x000001734527BAF0>, <__main__.Product object at 0x000001734527BAC0>, 'virus']
class Product():
# 빈 더미클래스 생성
pass
class Inventory():
def __init__(self):
self.__items = [] #private 변수로 선언 타객체가 접근 못함
self.test = 'abc'
def add_new_item(self, product):
if type(product) == Product:
self.__items.append(product)
print('새로운 아이템을 추가했습니다')
else:
raise ValueError('Invalid Item')
def get_number_of_items(self):
return len(self.__items)
이렇게 하면,
AttributeError: 'Inventory' object has no attribute 'items'
이런식으로 접근할 수 없게 됨.
@property
라는 decorator사용!!class Inventory():
def __init__(self):
self.__items = [] #private 변수로 선언 타객체가 접근 못함
@property #property decorator 숨겨진 변수를 반환하게 해줌
def items(self):
return self.__items
def square(x):
return x * x
f = square # 메모리주소 할당
f(5) >> 25
#################################
def cube(x):
return x * x * x
def formula(method, argument_list):
return [method(value) for value in argument_list]
def print_massage(msg):
def printer():
print(msg)
printer()
print_massage('Hello, Python')
def print_massage(msg):
def printer():
print(msg)
return printer()
another = print_massage('Hello, Python')
another()
another()
은 항상 Hello, Python 메세지가 return됨?def tag_func(tag, text):
text = text
tag = tag
def inner_func():
return '<{0}>{1}<{0}>'.format(tag, text)
return inner_func
h1_func = tag_func('title', 'this is python class')
p_func = tag_func('p', 'data academy')
def star(func):
def inner(*args, **kwargs):
print("*" * 30)
func(*args, **kwargs)
print("*" * 30)
return inner
@star
def printer(msg):
print(msg)
printer('Hello')
printer()
함수가 앞에 star()
함수 안으로 들어가게됨******************************
Hello
******************************
def star(func):
def inner(*args, **kwargs):
print (args[1] * 30)
func(*args, **kwargs)
print (args[1] * 30)
return inner
@star
def printer(msg, mark):
print(msg)
printer('Hello', '=')
출력값
==============================
Hello
==============================