-
[python]1. Objects_in_Python인공지능/부스트캠프 Ai Tech 2022. 1. 21. 18:16728x90
[python]1. Objects_in_Python In [1]:from IPython.core.display import display, HTML display(HTML("<style>.container { width:90% !important; }</style>")) #창 맞추기위함
1-1. Python Object Oriented Programming¶
객체 지향 프로그래밍(OOP)¶
객체 : 실생활에서 일종의 물건, 속성(Attribute)와 행동(Action)을 가짐
속성은 변수(variable), 행동은 함수(method)로 표현됨
ex) 수강신청 프로그램 : 수강신청 관련 주체(교수,학생,관리자)의 행동(수강신청, 과목 입력) 과 데이터(수강과목, 강의 과목)들을 중심으로 프로그램 작성 후 연결
OOP는 설계도에 해당하는 클래스(class)와 실제 구현체인 인스턴스(instance, 또는 객체)로 나뉜다.
변수, Class, 함수명은 짓는 방식이 존재
snakecase : 띄어쓰기 부분에 ""를 추가, 뱀 처럼 늘여쓰기 파이썬 함수/변수명에 사용
ex) professor_name
- CamelCase : 띄어쓰기 부분에 대문자 낙타의 등 모양, 파이썬 Class명에 사용
ex) SoccerPlayer
파이썬에서 __의 의미(magic methods)¶
- __은 특수한 예약 함수나 변수 그리고 함수명 변경(맨글링)으로 사용한다.
ex) main, add , str , eq
Attribute 추가는 init, self와 함께 사용한다. init은 객체 초기화 예약 함수
method(Action) 추가는 기존 함수와 같으나, 반드시 self를 추가해야만 class 함수로 인정됨
self란? 생성된 instance를 의미한다.
In [1]:# 축구 선수 정보로 class SoccerPlayer(object): # CamelCase def __init__(self, name : str, position : str, back_number : int): # 객체 초기화 함수, self는 필수 self.name = name # self. 으로 객체의 초기 정보를 선언 할 수 있다 self.position = position self.back_number = back_number def __str__(self): # __str__ : 앞으로 print로 객체에 적용하면 출력해주는 코드 return "Hello, My name is %s. I play in %s in center. " % \ (self.name, self.position) def __add__(self, other): # __add__ : 두 객체를 서로 더해준다. return self.name + other.name def change_back_number(self, new_number : int): print("선수의 등번호를 변경합니다 : From %d to %d" % \ (self.back_number, new_number)) self.back_number = new_number
In [2]:dongseok = SoccerPlayer("dongseok", "MF", 10) # 이때 self는 dongseok 자기 자신이 된다. park = SoccerPlayer("park", "WF", 13) print(dongseok) # __str__ 로 응답
Hello, My name is dongseok. I play in MF in center.
In [3]:dongseok is park # 같은 class에서 나왔지만 서로 다른 객체이다.
Out[3]:False
In [4]:dongseok + park # 사칙연산 가능, __add__ 함수 덕분!
Out[4]:'dongseokpark'
In [23]:dongseok.back_number
Out[23]:10
In [26]:dongseok.change_back_number(20)
선수의 등번호를 변경합니다 : From 10 to 20
In [29]:dongseok.back_number = 30 # 바로 변수를 변경하는 것은 추천하지 않음 print(dongseok)
Hello, My name is dongseok. I play in MF in center.
In [30]:dongseok.back_number
Out[30]:30
Note를 정리하는 프로그램¶
class는 Notebook, Note
Notebook의 attribute & methods: Note(300페이지까지 제한), page(Note가 삽입될 때 생성됨), add(두개의 노트북을 합치는 메소드), insert(Note를 삽입하는 메소드)
Note의 attribute & methods: Content(str), write(노트 작성), remove(노트 제거)
In [179]:class Note(object): def __init__(self, Content : str): # Content = None으로 할 경우 생성없이 가능 self.Content = Content def remove(self): self.Content = "" def write(self, Content : str): self.Content = Content def __str__(self): return "노트에 적힌 내용입니다. : {0}".format(self.Content) def __add__(self, other): return self.Content + other.Content
In [180]:class Notebook(object): def __init__(self): self.page_num = 0 def __add__(self, other_Notebook): return self def insert(self, Note): if self.page_num < 300: return print("이 Notebook은 300페이지 이상 추가할 수 없습니다. 현재 \ 페이지 수는 %d 입니다."(self.page_num)) self.page_num = self.page_num + 1
교수님 코드 + 내 방식
In [181]:class Notebook(object): def __init__(self, title): self.title = title self.page_num = 1 self.notes = {} def insert(self, note, page = 0): # page를 입력해주지 않으면 자동으로 다음 넘버 if self.page_num < 301: if page == 0: self.notes[self.page_num] = note self.page_num += 1 print("이 Notebook은 300페이지 이상 추가할 수 없습니다.") print("현재 페이지 수 : {0}".format(len(self.notes.keys()))) else: self.notes[page] = note self.page_num = self.page_num + 1 print("이 Notebook은 300페이지 이상 추가할 수 없습니다.") print("현재 페이지 수 : {0}".format(len(self.notes.keys()))) else: print("Page가 모두 채워졌습니다.") def remove_note(self, page_num): if page_num in self.notes.keys(): # note에 내용물이 있으면 return self.notes.pop(page_num) # 선택한 page_num의 note 제거 else: print("해당 Page는 존재하지 않습니다.") def get_number_of_pages(self): return len(self.notes.keys()) # or len(page_num)
In [182]:my_notebook = Notebook("팀 랩 강의노트")
In [183]:my_notebook.title
Out[183]:'팀 랩 강의노트'
In [184]:new_note = Note("아자아자") print(new_note)
노트에 적힌 내용입니다. : 아자아자
In [185]:new_note2 = Note("호롤롤로") print(new_note2)
노트에 적힌 내용입니다. : 호롤롤로
In [186]:my_notebook.insert(new_note) my_notebook.insert(new_note2, 100)
이 Notebook은 300페이지 이상 추가할 수 없습니다. 현재 페이지 수 : 1 이 Notebook은 300페이지 이상 추가할 수 없습니다. 현재 페이지 수 : 2
In [187]:my_notebook.notes
Out[187]:{1: <__main__.Note at 0x2b42dc3e348>, 100: <__main__.Note at 0x2b42dc00148>}
In [188]:my_notebook.get_number_of_pages()
Out[188]:2
In [189]:print(my_notebook.notes[1])
노트에 적힌 내용입니다. : 아자아자
In [190]:print(my_notebook.notes[100])
노트에 적힌 내용입니다. : 호롤롤로
In [191]:my_notebook.notes[2] = Note("으악") print(my_notebook.notes[2])
노트에 적힌 내용입니다. : 으악
1-2. OOP characteristics¶
객체 지향 언어의 특징 : 세상을 모델링
Inheritance(상속)
Polymorphism(다형성)
Visibility(가시성) - hidden class
상속(Inheritance)¶
부모클래스로 부터 속성과 Method를 물려받은 자식 클래스를 생성하는 것
In [3]:class Person(object): # 부모클래스 def __init__(self, name, age, gender = 'N'): self.name = name self.age = age self.gender = gender def __str__(self): return "저의 이름은 {0} 입니다. 나이는 {1} 입니다.".format(self.name, self.age) def about_me(self): print("나는 {0}이다.".format(self.name)) class Korean(Person): # 부모클래스 Person을 상속받은 자식클래스 pass first_korean = Korean("Dongseok", 29) print(first_korean.name)
Dongseok
In [4]:print(first_korean)
저의 이름은 Dongseok 입니다. 나이는 29 입니다.
In [10]:first_korean.about_me()
나는 Dongseok이다.
In [2]: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("내 임금은 ", self.salary, "원 이다. 내 입사일은", self.hire_date, "이다.")
In [5]:myPerson = Person("john", 34, "Male") myEmployee = Employee("seok", 29, "Male", 3000000, "2019/06/27") myEmployee.about_me() # 부모의 about_me, 자식의 about_me 다 실행
나는 seok이다. 내 임금은 3000000 원 이다. 내 입사일은 2019/06/27 이다.
다형성(Polymorphism)¶
- 같은 이름 메소드의 내부 로직을 다르게 작성, 같은 일을 하는데 세부적으로 구현이 다른 경우
ex) draw(Rentangle) , draw(Circle)..
In [6]:class Animal: def __init__(self, name): self.name = name def talk(self): # 추상 메소드, 상속받는 클래스에서 내용을 완성시켜라. raise NotImplementedError("Subclass must implement abstract method") class Cat(Animal): def talk(self): return "Meow!" class Dog(Animal): def talk(self): return "Woof! Woof!"
In [7]:animals = [Cat('Missy'), Cat('Mr. mistro'), Dog('Lassie')]
In [18]:for animal in animals: print(animal.name + ': ' + animal.talk())
Missy: Meow! Mr. mistro: Meow! Lassie: Woof! Woof!
가시성(Visibility)¶
객체의 정보를 볼 수 있는 레벨을 조절하는 것, 누구나 객체 안에 모든 변수를 볼 필요가 없다.
객체를 사용하는 사용자가 임의로 정보 수정
필요없는 정보에는 접근 할 필요가 없음
만약 제품으로 판매한다면? 소스의 보호
캡슐화(Encapsulation)¶
캡슐화 또는 정보 은닉(Information Hiding)
- Class를 설계할 때, 클래스 간 간섭/정보공유의 최소화
- 심판 클래스가 축구선수 클래스 가족 정보를 알아야 하나?
- 캡슐을 던지듯 인터페이스만 알아서 써야함
예제1
- Product 객체를 Inventory 객체에 추가
- Inventory에는 오직 Product 객체만 들어감
- Inventory에 Product가 몇 개인지 확인이 필요
- Inventory에 Product items는 직접 접근이 불가
In [9]:class Product(object): # 더미 클래스 pass class Inventory(object): def __init__(self): self.__items = [] # __ : private 변수로 선언, 타객체가 접근하지 못함 def add_new_item(self, product): if type(product) == 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 # property decorator : 숨겨진 변수를 반환하게 해줌 함수지만 변수명처럼 사용 가능 def items(self): return self.__items # 내부에서 접근하여 반환
In [10]:my_inventory = Inventory() my_inventory.add_new_item("abc") # Product 클래스가 아님
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-10-25678ee92950> in <module> 1 my_inventory = Inventory() ----> 2 my_inventory.add_new_item("abc") # Product 클래스가 아님 <ipython-input-9-f62a343c4cdc> in add_new_item(self, product) 11 print("new item added") 12 else: ---> 13 raise ValueError("Invalid Item") 14 15 def get_number_of_items(self): ValueError: Invalid Item
In [11]:my_inventory.__items # 외부에서 접근 못함
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-11-f48349b818a3> in <module> ----> 1 my_inventory.__items # 외부에서 접근 못함 AttributeError: 'Inventory' object has no attribute '__items'
In [13]:my_inventory.add_new_item(Product())
new item added
In [33]:my_inventory.items # 내부에 있는 객체 접근 가능, 변수명처럼 사용
Out[33]:[<__main__.Product at 0x1459dc68e08>]
In [14]:my_inventory.items.append("a")
In [2]: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] f = square # 변수에 할당한 함수 f(5)
Out[2]:25
In [3]:def formula(method, argument_list): # 함수를 파라메터로 사용 return [method(value) for value in argument_list] arg_list = [1,2,3,4,5] formula(cube, arg_list)
Out[3]:[1, 8, 27, 64, 125]
inner function¶
함수 내에 또 다른 함수가 존재
In [38]:def print_msg(msg): def printer(): print(msg) printer() print_msg("Hello, Python")
Hello, Python
closures¶
inner function을 return값으로 반환, 같은 용도인데 조금씩 다르게 사용할 경우
In [40]:def print_msg(msg): def printer(): print(msg) return printer another = print_msg("Hello, Python") another()
Hello, Python
In [41]: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")
In [44]:h1_func
Out[44]:<function __main__.tag_func.<locals>.inner_func()>
In [43]:h1_func()
Out[43]:'<0>This is Python Class<title>'
In [45]:p_func()
Out[45]:'<0>Data Academy<p>'
decorator function¶
복잡한 클로저 함수를 간단하게!
In [4]:def star(func): def inner(*args, **kwargs): print("*" * 30) func(*args, **kwargs) print("*" * 30) return inner @star def printer(msg): print(msg) printer("Hello")
****************************** Hello ******************************
In [51]: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)
In [52]:printer("Hello", "&")
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Hello &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
In [54]: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")
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
In [58]:def generate_power(exponent): def wrapper(f): def inner(*args): result = f(*args) # raise_two 실행 print(">>>>", result) return exponent**result return inner return wrapper @generate_power(2) # argument를 쓰기 위해서 wrapper 함수를 사용 def raise_two(n): return n**2 print(raise_two(7)) # exponent의 49제곱 : 2^49
>>>> 49 562949953421312
'인공지능 > 부스트캠프 Ai Tech' 카테고리의 다른 글
[python]5. Numpy (0) 2022.01.21 [python]4. Python Data Handling (0) 2022.01.21 [python]3. Exception_File_LogHandling (0) 2022.01.21 [python]0. Pythonic code (0) 2022.01.21 [python]2. Module and Project (0) 2022.01.21