Python Object Oriented Programming¶
- Object-Oriented Programming, OOP
- 객체: 실생활에서 일종의 물건 속성(Attribute)와 행동(Action)을 가짐
- OOP는 이러한 객체 개념을 프로그램으로 표현. 속성은 변수(variable), 행동은 함수(method)로 표현됨
- 파이썬역시 객체 지향 프로그램 언어
class 구현하기 in Python¶
In [1]:
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 t o%d" %\
(self.back_number, new_number))
self.back_number= new_number
def __str__(self):
return"Hello, My name is %s. I play in %s in center" % \
(self.name, self.position)
class 선언하기¶
- 변수와 Class명 함수명은 짓는 방식이 존재
- snakecase: 띄워쓰기 부분에 '' 를추가
:뱀처럼늘여쓰기, 파이썬함수/변수명에사용 - CamelCase: 띄워쓰기 부분에 대문자
:낙타의등모양, 파이썬Class명에사용
Attribute 추가하기¶
- Attribute 추가는
__init___
,self
와 함께! __init__
은 객체 초기화 예약 함수
파이썬에서 _의미¶
__
는 특수한 예약 함수나 변수 그리고 함수명 변경(맨글링)으로 사용
예)__main__
,__add__
,__str__
,__eq__
In [2]:
jinhyun= SoccerPlayer("Jinhyun", "MF", 10)
print(jinhyun)
print()
함수로 class를 출력하게 되면__str__
함수의 반환값이 출력된다.
method 구현하기¶
self
는 생성된 instance자신을 의미하게 된다.- method(Action) 추가는 기존 함수와 같으나,
반드시self
를 추가해야만 class 함수로 인정됨
objects(instance) 사용하기¶
- Object 이름 선언과 함께 초기값 입력 하기
In [3]:
jinhyun= SoccerPlayer("Jinhyun", "MF", 10)
print("현재선수의등번호는:", jinhyun.back_number)
jinhyun.change_back_number(5)
print("현재선수의등번호는:", jinhyun.back_number)
구현 가능한 OOP만들기 - 노트북¶
구현 해야 할 것¶
- Note를 정리하는 프로그램
- 사용자는 Note에 뭔가를 적을 수 있다.
- Note에는 Content가 있고, 내용을 제거 할 수 있다.
- 두 개의 노트북을 합쳐 하나로 만들 수 있다.
- Note는 Notebook에 삽입된다.
- Notebook은 Note가 삽일 될 때 페이지를 생성하며,
최고 300페이지까지 저장 가능하다. - 300 페이지가 넘으면 더 이상 노트를 삽입하지 못한다.
class scheme¶
Note class¶
In [4]:
class Note(object):
def __init__(self, content= None):
self.content= content
def write_content(self, content):
self.content= content
def remove_all(self):
self.content= ""
def __add__(self, other):
return self.content+ other.content
def __str__(self):
return self.content
NoteBook class¶
In [5]:
class NoteBook(object):
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)
else:
print("해당페이지는존재하지않습니다")
def get_number_of_pages(self):
return len(self.notes.keys())
In [6]:
quote_book = NoteBook("The Quote Book")
new_note = Note()
new_note.write_content("Don't cry because it's over, smile because it happened. ― Dr. Seuss")
quote_book.add_note(new_note)
print(quote_book.get_number_of_pages())
print(quote_book.notes[1])
quote_book.add_note(Note("Hello, World"))
print(quote_book.get_number_of_pages())
my_note = quote_book.remove_note(2)
print(my_note)
OOP characteristics¶
상속(Inheritance)¶
In [7]:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
class Korean(Person):
pass
first_korean = Korean("Sungchul", 35)
print(first_korean.name,first_korean.age)
- 부모클래스로 부터 속성과 Method를 물려받은 자식 클래스를 생성 하는 것
In [8]:
class Person: # 부모 클래스 Person 선언
def __init__(self, name, age, gender):
self.name = name # 속성값 지정, 해당 변수가 클래스의 attribute임을 명확히하기 위해 self를 붙임
self.age = age
self.gender = gender
def about_me(self): # Method 선언
print("저의 이름은 ", self.name, "이구요, 제 나이는 ", str(self.age), "살 입니다.")
class Employee(Person): # 부모 클래스 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("제 급여는 ", self.salary, "원 이구요, 제 입사일은 ", self.hire_date, " 입니다.")
myPerson = Person("John", 34, "Male")
myEmployee = Employee("Daeho", 34, "Male", 300000, "2012/03/01")
myPerson.about_me()
myEmployee.about_me()
- 여기서
super()
라는 명령어는 부모 클래스를 불러오는 명령어이다.
다형성(Polymorphism)¶
- 같은 이름 메소드의 내부 로직을 다르게작성
- Dynamic Typing 특성으로 인해 파이썬에서는 같은 부모클래스의 상속에서 주로 발생함
- 중요한 OOP의 개념 그러나 너무 깊이 알 필요X
In [9]:
class Animal:
def __init__(self, name): # Constructor of the class
self.name = name
def talk(self): # Abstract method, defined by convention only
raise NotImplementedError("Subclass must implement abstract method")
class Cat(Animal):
def talk(self):
return 'Meow!'
class Dog(Animal):
def talk(self):
return 'Woof! Woof!'
animals = [Cat('Missy'),
Cat('Mr. Mistoffelees'),
Dog('Lassie')]
for animal in animals:
print(animal.name + ': ' + animal.talk())
가시성(Visibility)¶
- 객체의 정보를 볼 수 있는 레벨을 조절하는 것
- 누구나 객체 안에 모든 변수를 볼 필요가 없음
1) 객체를 사용하는 사용자가 임의로 정보 수정
2) 필요 없는 정보에는 접근 할 필요가 없음
3) 캡슐화 또는 정보은닉(Information Hiding)
4) Class를 설계할 때, 클래스 간 간섭/정보공유의 최소화
Example1¶
- Product객체를 Inventory객체에 추가
- Inventory에는 오직 Product객체만 들어감
- Inventory에 Product가 몇 개인지 확인이 필요
- Inventory에 Product items는 직접 접근이 불가
만약 __
가 없다면¶
In [10]:
class Product(object):
pass
class Inventory(object):
def __init__(self):
self.items = []
def add_new_item(self, product):
if type(product) == Product:
self.items.append(product)
print("new item added")
else:
raise ValueError("Invalid Item")
def get_number_of_items(self):
return len(self.items)
In [11]:
my_inventory = Inventory()
my_inventory.add_new_item(Product())
my_inventory.add_new_item(Product())
my_inventory
Out[11]:
- 여기서 메서드를 통해서 접근한걸 볼 수 있다.
- Product객체만 넣기 위해서 함수를 만들었다.
In [12]:
my_inventory.items.append('abc')
my_inventory.items
Out[12]:
- 이렇게 마음대로 외부에서 접근할 수 있기때문에 Product객체가 아니라 다른 자료형이 들어온걸 확인 할 수 있다.
- 이러면 문제가 생긴다.
In [13]:
class Product(object):
pass
class Inventory(object):
def __init__(self):
self.__items = []
def add_new_item(self, product):
if type(product) == Product:
self.__items.append(product)
print("new item added")
else:
raise ValueError("Invalid Item")
def get_number_of_items(self):
return len(self.__items)
my_inventory = Inventory()
my_inventory.add_new_item(Product())
my_inventory.add_new_item(Product())
print(my_inventory.get_number_of_items())
#print(my_inventory.__items) # 직접 접근 불가
#my_inventory.add_new_item(object) # 유효 타입이 아님
__
을 통해서 변수를 설정하면 외부에서 접근이 불가하다.
Example2¶
- 위 Example1에서 4번째 조건만 변경
- Inventory에 Product items접근 허용
In [14]:
class Product(object):
pass
class Inventory(object):
def __init__(self):
self.__items = []
def add_new_item(self, product):
if type(product) == Product:
self.__items.append(product)
print("new item added")
else:
raise ValueError("Invalid Item")
def get_number_of_items(self):
return len(self.__items)
@property
def items(self):
return self.__items
In [15]:
my_inventory = Inventory()
my_inventory.add_new_item(Product())
my_inventory.add_new_item(Product())
In [16]:
my_inventory.items
Out[16]:
@property
를 사용하면 접근 가능
In [17]:
my_inventory.items.append('abc')
my_inventory.items
Out[17]:
- 하지만 이렇게 하면 또 내부의 값을 바꿀 수 있게 된다.
- 이걸 막기 위해서는 값을 바로 리턴하는게 아니라
copy()
함수를 통한 값을 반환하는게 일반적이다.
In [18]:
def square(x):
return x * x
f = square
f(5)
Out[18]:
- 함수를 변수로 사용
In [19]:
def square(x):
return x * x
def cube(x):
return x*x*x
def formula(method, argument_list):
return[method(value) for value in argument_list]
print(formula(square,[1,2,3]))
print(formula(cube,[1,2,3]))
- 함수를 파라메터로 사용
inner function¶
In [20]:
def print_msg(msg):
def printer():
print(msg)
printer()
print_msg("Hello, Python")
- 함수내 또 다른 함수가 존재
In [21]:
def print_msg(msg):
def printer():
print(msg)
return printer
another = print_msg("Hello, Python")
another()
- closures: inner function을 return값으로 반환
In [22]:
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")
print(h1_func())
print(p_func())
- 여기서 return값이 function이므로 결과를 보려면 함수 호출로 봐야한다.
decorator¶
In [23]:
def star(func):
def inner(*args, **kwargs):
print("*"* 30)
func(*args, **kwargs)
print("*"* 30)
return inner
@star
def printer(msg):
print(msg)
printer("Hello")
- 복잡한 클로져 함수를 간단하게 만들어 준다.
In [24]:
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",'&')
In [25]:
def star(func):
def inner(*args, **kwargs):
print("*"* 30)
func(*args, **kwargs)
print("*"* 30)
return inner
def percent(func):
def inner(*args, **kwargs):
print("%"* 30)
func(*args, **kwargs)
print("%"* 30)
return inner
@star
@percent
def printer(msg):
print(msg)
printer("Hello")
In [26]:
def generate_power(exponent):
def wrapper(f):
def inner(*args):
result = f(*args)
return exponent**result
return inner
return wrapper
@generate_power(2)
def raise_two(n):
return n**2
print(raise_two(7))
'AI > 이론' 카테고리의 다른 글
Numpy part II (0) | 2021.01.25 |
---|---|
Numpy part I (0) | 2021.01.25 |
Python data handling (0) | 2021.01.22 |
File & Exception & Log Handling (0) | 2021.01.22 |
Module and Project (0) | 2021.01.21 |
pythonic code (0) | 2021.01.20 |
python data structure (0) | 2021.01.20 |
Variable & List (0) | 2021.01.19 |