Ai Tech Pre-course Lec.4

Lilmeow·2023년 9월 7일
0

Boostcamp Step.1

목록 보기
4/10
post-thumbnail

Lec4: Python Object Oriented Programming

01_Python 개발 방법 : 만들어 놓은 코드를 재사용하고 싶다

1) Class & Object : 객체 지향 언어의 이해

수강신청 프로그램 작성

  • 방법1. 수강신청이 시작부터 끝까지 순서대로 작성
  • 방법2. 수강신청 관련 주체들(교수, 학생, 관리자)의 행동(수강신청, 과목 입력)과 Data(수강과목, 강의 과목)들을 중심으로 프로그램 작성 후 연결

두 가지 모두 가능, 최근에는 방법2가 주류, 이러한 기법을 객체 지향 프로그램이라 한다.

  • 객체지향 프로그래밍 개요
    • Object-Oriented Programming(OOP)
    • Object : 실생활에서 일종의 물건, 속성(Attribute)와 행동(Action)을 가짐
    • OOP는 이러한 객체 개념을 프로그램으로 표현
      속성은 변수(Variable), 행동은 함수(Method)로 표현됨
    • Python역시 OOP Language

ex) 인공지능 축구 프로그램을 작성한다고 가정

  • 객체 종류 : 팀, 선수, 심판, 공
  • Action : 선수(공을 차다, 패스하다), 심판(휘슬을 불다, 경고를 주다)
  • Attribute : 선수(선수 이름, 포지션, 소속팀), 팀(팀 이름, 팀 연고지, 팀소속 선수)
  • OOP는 설계도에 해당하는 Class와 실제 구현체인 Instance로 나눈다.
    ex) Class(붕어빵틀), Instance(붕어빵)

2) Object in Python

축구 선수 정보를 Class로 구현해보자.

class SoccerPlayer(object):
    def __init__(self, name, position, back_number):
        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
  • Class 선언하기(Object는 Python3에서 자동 상속)
  • Python Naming Rule
    • Variable, Class, Function 이름은 짓는 방식이 존재
    • Snake_case : 띄어쓰기 부분에 언더바 추가
      뱀처럼 늘여쓰기, Python Function/Variable명으로 사용
    • CamelCase : 띄어쓰기 부분에 대문자
      낙타의 등 모양, Python Class명으로 사용
  • Attribute 추가하기
#__init__(객체 초기화 예약 함수), self 사용

class SoccerPlayer(object):
    def __init__(self, name, position, back_number):
        self.name = name
        self.position = position
        self.back_number = back_number
  • What does '__' mean in Python
    : 특수한 예약 함수나 변수 그리고 함수명 변경(Mangling)으로 사용
ex) __main__, __add__, __str__, __eq__

class SoccerPlayer(object):
    def __init__(self, name, position, number):
        self.name = name
        self.position = position
        self.number = number

    def __str__(self):
        return "Hello, My name is %s. I play in %s in center " % (self.name, self.position)

jinhyun = SoccerPlayer("Jinhyun", "MF", 10)
print(jinhyun)
  • Method 구현하기
    : Method(Action) 추가는 기존 함수와 같으나, 반드시 self를 추가해야만 Class Function으로 인정됨
class ScoccerPlayer(object):
    def change_back_number(self, new_number):
        print("선수의 등번호를 변경합니다 : From %d to %d" %(self.back_number, new_number))
        self.back_number = new_number
  • Object(Instance) 사용하기
    : Object명 선언과 함께 초기값 입력하기

  • Class 구현하기

class SoccerPlayer(object):
    def __init__(self, name, position, back_number):
        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

jinhyun = SoccerPlayer("Jinhyun", "MF", 10)
print("현재 선수의 등번호는 :", jinhyun.back_number)
jinhyun.change_back_number(5)
print("현재 선수의 등번호는 :", jinhyun.back_number)
현재 선수의 등번호는 : 10
선수의 등번호를 변경합니다 : From 10 to 5
현재 선수의 등번호는 : 5

3) OOP Implementation Example

구현 가능한 OOP 만들기 - Notebook

  • Note를 정라히는 프로그램
  • 사용자는 Note에 뭔가를 적을 수 있다.
  • Note에는 Content가 있고, 내용을 제거할 수 있다.
  • 두 개의 노트북을 합쳐 하나로 만들 수 있다.
  • Note는 Notebook에 삽입된다.
  • Notebook은 Note가 삽입 될 때 페이지를 생성하며, 최고 300페이지까지 저장 가능하다.
  • 300 페이지가 넘으면 더 이상 Note를 삽입하지 못한다.
  • Class Scheme

  • Note Class

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())

4) OOP Characteristics

  • 실제 세상을 Modeling
  • 필요한 것 3가지 :
    1) Inheritance(상속)
    2) Polymorphism(다형성)
    3) Visibility(가시성)
  • Inheritance
    : 부모 Class로부터 속성과 Method를 물려받은 자식 Class를 생성하는 것.
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)
ex)
class Person(object): # 부모 Class Person 선언
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def about_me(self): # Method 선언
        print("저의 이름은 ", self.name, "이구요, 제 나이는 ", str(self.age), "살 입니다.")
ex2)
class Employee(Person): # 부모 Class 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): # 새로운 Method 추가
        print("열심히 일을 합니다.")

    def about_me(self): # 부모 Class 함수 재정의
        super().about_me() # 부모 Class 함수 사용
        print("제 급여는 ", self.salary, "원 이구요, 제 입사일은 ", self.hire_date," 입니다.")

ob1 = Employee("lilmeow", 24, "male", 100, "1월 11일")
print(ob1)
ob.about_me()
<__main__.Employee object at 0x10391bb50>
저의 이름은  lilmeow 이구요, 제 나이는  24 살 입니다.
제 급여는  100 원 이구요, 제 입사일은  111일  입니다.
  • Polymorphism
    • 같은 이름 Method의 내부 Logic을 다르게 작성
    • Dynamic Typing 특성으로 인해 Python에서는 같은 부모 Class의 상속에서 주로 발생함
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())
Missy: Meow!
Mr. Mistoffelees: Meow!
Lassie: Woof! Woof!
  • Visibility

    • Object의 정보를 볼 수 있는 Level을 조절하는 것
    • 누구나 Object 안에 모든 변수를 볼 필요가 없음 :
      1. Object를 사용하는 사용자가 임의로 정보 수정
      2. 필요 없는 정보에는 접근 할 필요가 없음
      3. 만약 제품으로 판매한다면? 소스의 보호
  • Encapsulation

    • 캡슐화 또는 정보 은닉 : Information Hiding
    • Class를 설계할 때, Class 간 간섭/정보 공유의 최소화
    • 심판 Class가 축구선수 Class 가족 정보를 알아야 하나?
    • 캡슐을 던지듯, Interface만 알아서 써야함
  • Visibility Example1.

    • Product Object를 Inventory Object에 추가
    • Inventory에는 오직 Product Object만 들어감
    • Inventory에 Product가 몇 개인지 확인이 필요
    • Inventory에 Product items는 직접 접근이 불가
class Product(object):
    pass

class Inventory(object): 
    def __init__(self):
        self.__items = [] # Private Variable로 선언 타객체가 접근 못함

    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)
class Inventory:
    def __init__(self):
        self.__items = []

    def add_new_item(self, item):
        self.__items.append(item)

    def get_number_of_items(self):
        return len(self.__items)

class Product:
    pass

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._Inventory__items)
my_inventory.add_new_item(object)
2
[<__main__.Product object at 0x1033891b0>, <__main__.Product object at 0x10338a290>]
  • Visibility Example2.
    • Product Object를 Inventory Object에 추가
    • Inventory에는 오직 Product Object만 들어감
    • Inventory에 Product가 몇 개인지 확인이 필요
    • Inventory에 Product items 접근 허용
class Inventory(object):
    def __init__(self):
        self.__items = []

    @property # Property Decorator : 숨겨진 Variable를 Return하게 해준다
    def items(self):
        return self.__items
    
    def add_new_item(self, item):
        self.__items.append(item)
    
    def get_number_of_items(self):
        return len(self.__items)

class Product(object):
    pass

my_inventory = Inventory()
my_inventory.add_new_item(Product())
my_inventory.add_new_item(Product())
print(my_inventory.get_number_of_items())

items = my_inventory.items # Property Decorator로 Function을 Variable처럼 호출
items.append(Product())
print(my_inventory.get_number_of_items())

5) Decorate

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks
        # self.gotmarks = self.name + ' obtained ' + self.marks + ' marks'

    @property
    def gotmarks(self):
        return self.name + ' obtained ' + str(self.marks) + ' marks'

6) First-Class Objects Inner Function Decorator

  • First-Class Objects
    • 일등함수 또는 일급 Object
    • Variable이나 Data Structure에 할당이 가능한 Object
    • Parameter로 전달이 가능 +Return 값으로 사용
    • Python Function = 일급함수
def square(x):
    return x * x

f = square # Function을 Variable로 사용
f(5) # 25
def square(x):
    return x * x

def cube(x):
    return x * x * x

def formula(method, argument_list): # Function을 Parameter로 사용
    return [method(value) for value in argument_list]
  • Inner Function : 함수 내에 또 다른 함수가 존재
def print_msg(msg):
    def printer():
        print(msg)
    printer()

print_msg("Hello, Python") # Hello, Python
  • Closures : Inner Function을 Return값으로 반환
def print_msg(msg):
    def printer():
        print(msg)
    return printer

another = print_msg("Hello, Python")
another()
  • Closures Example
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")
  • Decorator Function : 복잡한 Closures Function를 간단하게
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
******************************
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
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
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)) # 562949953421312

0개의 댓글