hojeomi blog
4-1. 파이썬 OOP(객체 지향 프로그래밍) 본문
1. 객체지향 프로그램¶
- 예전에 만든 코드를 재사용할 수 있게 해줌
- Object-Oriented Programming, OOP
- 객체: 실생활에서 일종의 물건 → 속성(attribute)와 행동(action)을 가짐
- OOP는 이러한 객체 개념을 프로그램으로 표현 → 속성은 변수(variable), 행동은 함수(method)로 표현됨
- 예) variable: 선수, method: 공을 차다
- OOP는 설계도에 해당하는 클래스(class)와 구현체인 인스턴스(instance)로 나뉨
1) 클래스의 매직 메소드: init, str, add, eq 등¶
In [25]:
class SoccerPlayer(object):
# attribute 추가는 __init__, self와 함께
# __init__은 객체 초기화 예약 함수
def __init__(self, name:str, position:str, back_number:int): # :<타입>을 적어주면 변수 선언 시 힌트
self.name = name
self.position = position
self.back_number = back_number
def __str__(self):
return "hello!"
def __add__(self, other):
return self.name + other.name
def change_back_number(self, new_number):
print(f"선수의 등번호를 {self.back_number}에서 {new_number}로 변경합니다.")
self.back_number = new_number
In [26]:
a = SoccerPlayer('son','FW',7)
b = SoccerPlayer('park','WF',11)
a
Out[26]:
In [27]:
# __str__의 값이 print를 하면 나옴
print(a)
In [28]:
# __add__ 실행
a + b
Out[28]:
In [29]:
a.change_back_number(99)
In [41]:
# __init__에서 속성 불러오기
a.back_number = 20
print(a.back_number)
In [ ]:
In [ ]:
2. 상속(Inheritance)¶
- 부모클래스로부터 속성과 method를 물려받은 자식 클래스를 생성하는 것
In [60]:
class Person(object):
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def about_me(self):
print(f"저의 이름은 {self.name}이구요, 제 나이는 {self.age}살 입니다.")
def about_parent(self):
print("부모클래스로 연결된다.")
In [61]:
class Employee(Person):
def __init__(self, name, age, gender, salary, hire_date):
super().__init__(name, age, gender) # super()로 부모클래스의 속성을 받아옴
self.salary = salary
self.hire_date = hire_date
def about_me(self):
super().about_me()
print(f"제 급여는 {self.salary}입니다.")
In [62]:
p1 = Person('jm','25','F')
In [63]:
p1.about_me()
In [71]:
p1_job = Employee('modi','52','F','30000','2021-01-01')
In [74]:
p1_job.about_me() # 부모클래스와 연결됨
* Employee 클래스에 없어도 부모클래스의 함수를 사용할 수 있음 (Empployee("Person")으로 object에 부모클래스를 넣어주기 때문?)¶
In [75]:
p1_job.about_parent()
In [ ]:
In [ ]:
3. 다형성(Polymorphism)¶
- 같은 이름 메소드의 내부 로직을 다르게 작성
- Dynamic Typing 특성으로 인해 파이썬에서는 같은 부모클래스의 상속에서 주로 발생함
- [참고] 동적 타이핑: a = 3 이라고 선언하면 a의 타입은 int형으로 자동으로 정해짐(int a = 3은 정적 타이핑)
- OOP의 개념 중 하나
🎈 Question. 상속과 무슨 차이? → 상속과 같은 기능들로 생긴 클래스의 특성 중 하나¶
In [76]:
class Animal:
def __init__(self, name):
self.name = name
def talk(self):
raise NotImplementedError("Subclass must implement abstract method.")
In [85]:
class Cat(Animal):
def talk(self):
return "야옹"
class Dog(Animal):
def talk(self):
return "월월"
In [86]:
duck = Cat("duck")
daebak = Dog("daebak")
In [87]:
duck.talk()
Out[87]:
In [88]:
daebak.talk()
Out[88]:
In [ ]:
In [ ]:
4. 다형성(Visibility)¶
- 객체의 정보를 볼 수 있는 레벨을 조절하는 것
- 누구나 객체 안에 모든 변수를 볼 필요가 없음
[알아두면 상식] Encapsulation¶
- 캡슐화 또는 정보 은닉(Information Hiding)
- 클래스를 설계할 때, 클래스 간 간섭/정보공유의 최소화
- 심판 클래스가 축구선수 클래스 가족 정보를 알아야 하나?
- 캡슐을 던지듯, 인터페이스만 알아서 써야함
1) 예제¶
- 조건
1) Product 객체를 Inventory 객체에 추가
2) Inventory에는 오직 Product 객체만 들어감
3) Inventory에 Product가 몇 개인지 확인이 필요
4) Inventory에 Product items는 직접 접근이 불가
#1. 언더바 두 개(__) 없을 경우(private 변수가 아닐 경우)¶
In [107]:
class Product(object):
pass
class Inventory(object):
def __init__(self):
self.items = []
self.test = "abc"
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 [108]:
my_inventory = Inventory()
my_inventory.add_new_item(Product())
In [109]:
my_inventory.items # items에는 Product(내가 선언해준 클래스) 타입인 것만 들어갈 수 있음
Out[109]:
In [110]:
my_inventory.items.append("def") # 하지만, items에 외부로부터의 접근도 허용되기에 Product 타입이 아닌 것도 들어가게 됨
In [111]:
my_inventory.items # 이런 경우를 방지하기 위해 private 변수 생성 필요
Out[111]:
#2. 언더바 두 개(__) 있을 경우(private 변수일 경우)¶
In [115]:
class Product(object):
pass
class Inventory(object):
def __init__(self):
self.__items = [] ## 언더바 두 개(__) -> private 변수 생성, 타 객체가 접근 못함
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 [116]:
my_inventory = Inventory()
my_inventory.add_new_item(Product())
In [119]:
my_inventory.__items # private로 숨겨서 접근이 안됨
In [121]:
my_inventory.__items.append("def") # 다른 객체 추가도 안됨
2) 예제¶
- 조건
1) Product 객체를 Inventory 객체에 추가
2) Inventory에는 오직 Product 객체만 들어감
3) Inventory에 Product가 몇 개인지 확인이 필요
4) Inventory에 Product items는 접근은 가능 (위 예제와 차이점)
→ property decorator 이용: 숨겨진 변수를 반환하게 해줌¶
In [122]:
class Product(object):
pass
class Inventory(object):
def __init__(self):
self.__items = [] ## 언더바 두 개(__) -> private 변수 생성, 타 객체가 접근 못함
@property # 반환할 때 복사를 해서 반환하는 형태
def items(self):
return 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 [123]:
my_inventory = Inventory()
my_inventory.add_new_item(Product())
In [126]:
my_inventory.items # 언더바 두 개 빼고 실행하면 property decorator를 통해 접근 가능
Out[126]:
In [ ]:
In [ ]:
5. decorate¶
1) first-class object¶
- 일등함수 또는 일급 객체
- 변수나 데이터 구조에 할당이 가능한 객체
- 파라미터로 전달이 가능 + 리턴 값으로 이용
→ 파이썬의 함수는 일급함수
예) map(f, ex)에서 f는 함수이지만 파라미터로 쓰임
In [3]:
def square(x):
return x*x
f = square # 함수를 변수로 사용
print(f(5))
In [4]:
def cube(x):
return x*x*x
In [5]:
def formula(method, argument_list):
return [method(value) for value in argument_list]
In [9]:
a = formula(square,[1,2,3]) # 함수를 파라미터로 사용
print(a)
2) 내재함수(inner function)¶
In [12]:
def print_msg(msg): # 1
def printer(): #3
print(msg)
printer() #2
In [13]:
print_msg("hello")
- closures: inner function을 return값으로 반환
In [14]:
def print_msg(msg): # 1
def printer(): #3
print(msg)
return printer() #2
In [25]:
print_msg("hello")
2-a) 예제 - closures¶
🎈 Qustion. # ()를 붙이는 것과 안 붙이는 것의 차이?¶
#1. () 붙인 것¶
In [37]:
def tag_func(tag, text):
text = text
tag = tag
def inner_func():
print('<{0}>{1}<{0}>'.format(tag, text))
return ('<{0}>{1}<{0}>'.format(tag, text))
return inner_func() # ()를 붙이는 것과 안 붙이는 것의 차이
h1_func = tag_func('title',"This is class")
p_func = tag_func('p',"Data academy")
In [38]:
h1_func
Out[38]:
#2. () 안 붙인 것¶
In [39]:
def tag_func(tag, text):
text = text
tag = tag
def inner_func():
print('<{0}>{1}<{0}>'.format(tag, text))
return ('<{0}>{1}<{0}>'.format(tag, text))
return inner_func # ()를 붙이는 것과 안 붙이는 것의 차이
h1_func = tag_func('title',"This is class")
p_func = tag_func('p',"Data academy")
In [40]:
h1_func
Out[40]:
2-b) 예제¶
#1.¶
In [60]:
def star(func):
def inner(*args, **kwargs):
print("*"*30)
func(*args, **kwargs) # func -> msg -> "hello"
print("*"*30)
return inner
@star
def printer(msg):
print(msg)
In [61]:
printer("hello")
In [62]:
def percent(func):
def inner(*args, **kwargs):
print("%"*30)
func(*args, **kwargs)
print("%"*30)
return inner
@star
@percent # percent 먼저, 그 다음 star
def printer(msg):
print(msg)
In [63]:
printer("hello")
#2.¶
In [64]:
def star(func):
def inner(*args, **kwargs):
print(args[1]*30) # args[1] -> mark
func(*args, **kwargs)
print(args[1]*30)
return inner
@star
def printer(msg, mark):
print(msg)
In [65]:
printer("hello","T")
#3.¶
In [73]:
def generate_power(exponent):
def wrapper(f): # f -> raise_two
def inner(*args):
result = f(*args) # f() -> n^2 예) 7^2
print(result)
return exponent**result # exponent -> 2 => 2^49가 리턴됨
return inner
return wrapper
In [74]:
@generate_power(2)
def raise_two(n):
return n**2
In [75]:
print(raise_two(7))
In [ ]:
'AI > Course' 카테고리의 다른 글
Day 2-2. 파이썬 함수에서 call by object reference (0) | 2021.01.25 |
---|---|
Day 5-1. File / Exception / Log Handling (0) | 2021.01.22 |
3-2. Pythonic Code (0) | 2021.01.21 |
Day 3-1. Python Data Structure (0) | 2021.01.20 |
Day 2. 파이썬 기초 문법 (2) | 2021.01.19 |
Comments