2019.03.21 TIL

(TIL은 스스로 이해한 것을 바탕으로 정리한 것으로 오류가 있을 수 있습니다)

# 질문에 답하기.

  1. 아래의 코드를 따라가면서 #에 따라 답해보기

코드를 통해 보는 class

>>>
>>>    def sum(a,b):            #1
>>>        return(a+b)
>>>
>>>    class Account:
>>>        
>>>        interest_rate = 0.08        #2         
>>>        num_of_account = 0                    
>>>        
>>>
>>>        @staticmethod                #3
>>>        def func(a,b):
>>>            return(a+b)
>>>
>>>        @classmethod                    #4
>>>        def string_constructor(cls, string):
>>>            data = string.split('_')
>>>            clnt_name = data[0]
>>>            balance = int(data[1])
>>>            return cls(clnt_name, balance)
>>>
>>>        @classmethod                        #5
>>>        def get_num_of_account(cls):
>>>            """
>>>            Account.get_num_of_account() ---> interger
>>>            return : 개설된 계좌 수
>>>            """
>>>            return cls.num_of_account
>>>
>>>        def __init__(self, clnt_name, balance):      #6
>>>            self.clnt_name = clnt_name              #7
>>>            self.balance = balance
>>>            Account.num_of_account += 1             
>>>
>>>        def deposit(self, money):                 #8
>>>            """
>>>            a.deposit(money) --> boolean
>>>            만약에 money > 0 입금성공
>>>            아니면 에러 메시지 출력 후 실패!
>>>            """
>>>            if money < 0:
>>>                print("입금은 0원 초과부터 가능합니다.")
>>>                return False
>>>            self.balance += money
>>>            return True
>>>
>>>        def withdraw(self, money):
>>>            """
>>>            a.withdraw(money) --> integer
>>>            return : 인출된 돈
>>>            만약 잔고가 모자라면 None
>>>            """
>>>            if money > self.balance:
>>>                print("인출할 돈이 잔액보다 많습니다.")
>>>                return None
>>>            self.balance -= money
>>>            return money
>>>
>>>        def transfer(self, other, money):           #9
>>>            self.balance -= money
>>>            other.deposit(money)
>>>
>>>        def __str__(self):                             #10
>>>            return f"{self.clnt_name} : {self.balance}"
>>>
>>>    if __name__ == "__main__"":
>>>        my_acnt = Account("greg", 5000)            #11
>>>        your_acnt = Account("john", 2000)
>>>    
>>>        print(Account.interest_rate)               #12
>>>        print(Account.get_num_of_account())        #13
>>>        print(my_acnt.interest_rate)               #14
>>>        print(my_acnt.get_num_of_account())        #15
>>>        print(Account.func(4,5))                   #16
>>>        print(type(Account.interest_rate))         #17
>>>        print(type(Account.get_num_of_account()))  #18
>>>        print(type(Account.get_num_of_account))    #19
>>>        print(type(my_acnt.deposit))               #20
>>>        print(type(Account.deposit))               #21
>>>        print(type(Account.func))                  #22
>>>
>>>        s = 'james_6000'                           #23
>>>        his_acnt = Account.string_constructor(s)
>>>        print(his_acnt)
>>>
>>>        my_acnt.deposit(7000)                      #24
>>>        print(my_acnt)
>>>
>>>        result1 = my_acnt.withdraw(3000)           #25
>>>        result2 = your_acnt.withdraw(3000)       
>>>        print(result1)
>>>        print(result2)
>>>
>>>        print(my_acnt)
>>>        print(your_acnt)
>>>
>>>
0.08
2
0.08
2
9
<class 'float'>
<class 'int'>
<class 'method'>
<class 'method'>
<class 'function'>
james : 6000
greg : 12000
인출할 돈이 잔액보다 많습니다.
3000
None
greg : 9000
john : 2000
>>>
>>>
>>>

#에 따라 정리하기

  1. #1 전역 함수

    • 어느 클래스에서도 속하지 않는다.
    • oop에서 제일 싫어하는 행동이다.
    • 최대한 관련있는 class에게 넣어주자.
  2. #2 클래스 멤버(class member)

    • 모든 객체가 공유한다.
    • 전역 변수(global variable)를 대체한다.
    • 클래스 바로 밑에 아무것도 적지 않고 적어주면 된다.
    • 모든 객체가 가지고 있을 필요는 없으나 모든 객체가 함께 공유해야 하는 것
      • ex: 이자율
    • 객체를 통해서도 클래스 멤버에 접근 가능하다.
    • 접근 방법 :
      • my_acnt.interest_rate : 객체를 통한 접근 방법
      • Account.interest_rate : 클래스를 통한 접근 방법
  3. #3 static method

    • 매서드처럼 보이지만 대놓고 함수이다. 전역함수
    • 전역 함수를 대체할 때 클래스메서드와 하나의 해결책이 될 수 있다.
    • 인자로 클래스나 객체를 받지 않는다. 함수의 정의만 클래스 A의 네임 스페이스에 있을 뿐 일반 함수와 같다.
  4. #4 클래스메서드(class method == @데코레이터)

    • 객체가 하나도 없는 상태에서도 호출이 가능하다.
    • cls가 self 대신 메모리 주소를 받는다.
    • 전역함수를 대체한다.
      • 전역함수를 대체할 때는 static method를 쓸 수 있다.
        • 아무것도 받지 않는다. 순수하게 함수다.
        • 사용방법(Account.func(5,4))
    • 관용적으로 cls를 받는다.
    • cls는 class를 받으므로 _init_ 와 같다.
  1. #5 클래스메서드(class method) + 대체 생성자

    • 객체가 하나도 없는 상태에서도 호출이 가능하다.
    • 전역 함수를 대체할 수 있다.
    • 원래 파이썬은 하나의 생성자만을 허용하지만 클래스메서드를 통해 해결 가능하다.
      • 대체 생성자(alternative constructor)가 될 수 있다.
      • 파이썬에서는 생성자를 하나만 가능하기때문에 여러가지 형태의 입력에 대응 할수 없다.
      • ex) 단체가입 "이름"_"초기값" ---> s = 'james_6000'
    • 접근방법
      • Account.get_num_of_account()
      • 객체를 통해서도 클래스 메서드에 접근이 가능하다.
  2. #6 생성자(constructor)

    • 파이썬에서는 오직 하나 존재한다.
    • _init_ : 객체(object)가 생성될 때 반듯이!! 한번 호출된다.
    • __ __ 은 파이썬에서 미리 쓰기로 해놓은 것이다.
  3. #7 인스턴스 멤버(instance member)

    • 인스턴스 멤버 == 상태정보 관리이다.
    • 각자의 객체가 가지는 값(값 = 상태정보)
    • init에 보면 변수가 나와 있다.
    • 생성된 object들은 같은 속성을 가지고 있으나 속성 값이 다르다.
    • Account.num_of_account ---> class멤버에 접근하는 방법
  4. #8 인스턴스 매서드(instance method)

    • object의 메서드로 봐도 된다.
    • class 입장에서는 function/ object입장에서는 메서드이다.
    • 객체가 할 수 있는 행동, 기능을 이야기 한다.
    • 인스턴스 메서드는 self를 꼭 써줘야 한다.
    • self는 해당 객체가 저장된 첫번째 주소를 가르킨다.
      • 즉 self는 생성된 객체 자기 자신을 가르킨다.
      • my_account.deposit(5000)이 실행될 떄 my_account를 self로 던져준다. self는 객체의 메모리 주소를 참조한다. 즉 자체참조이다.
  5. #9 message passing(메시지 패싱)

    • 나의 상태 정보와 함께 다른 객체의 상태 정보를 함께 변경해야 할 때
    • 다른 객체의 상태 정보(인스턴스 멤버)를 변경할 때는 반드시 상대 객체가 가진 메서드를 이용해야 한다.
    • 절대 하면 안되는 예)
      • self.balance -= money
      • other.balance += money
      • 다른 객체가 가진 메서드를 이용하지 않았다.
  6. #10 _str_(self)

    • my_acnt의 반환 포맷을 적어준다.
    • 이게 없으면 _main_.Account object at 0x10f512438처럼 반환
  7. #11 객체 생성

    • my_acnt(변수) = Account("greg", 5000) ==> class(매개변수)
    • 변수 = class(매개변수) 형태로 생성
    • 해당 객체는 해당 class의 인스턴스이다.
  8. #12 클래스 멤버 접근 방법

  9. #13 클래스 메서드 접근 방법

    • 클래스 메서드는 클래스 입장에서는 메서드지만(클래스의 행동 특정)
    • class입장에서 deposit과 같은 것은 함수이다.(클래스에 영상 x)
    • 하지만 객체 입장에서 deposit은 메서드이다.
    • print(type(my_acnt.deposit)) --- class 'method'
    • print(type(Account.deposit)) --- class 'function'
  10. #14 객체를 활용한 클래스 멤버 접근 방법

  11. #15 객체를 활용한 클래스 메서드 접근 방법

  12. #16 static method 접근 방법

  13. #17 클래스 멤버의 type

  14. #18 클래스 메서드 실행 했을 때의 type ---> int

  15. #19 클래스 메서드의 type

  16. #20 객체에서 메서드의 type

  17. #21 클래스에서 인스턴스 메서드의 type

  18. #22 static method의 타입

  19. #23 class method를 통해 대체 생성자를 만든 이유

    • 상황에 따라 전혀 예상하지 못한 형태의 값이 주어질 수도 있음
  20. #24 instance method 호출 방법(객체.method())

    • 객체에 self 인자는 넣어 줄 필요 없다.
    • class를 만들 때는 꼭 self를 써줘야 하지만 method를 호출하거나 객체를 생성할 때는 쓸 필요가 없다.
  21. #25 함수와 method의 차이점을 보여주는 예

    • 원래 withdraw라는 함수라면 입력이 3000원으로 같으므로 똑같이 나와야 한다.
    • 하지만 메소드는 내부에 가지고 있는 상태 정보가 다르기 때문에는 다르게 나온다.
    • 클로저에는 매개변수는 free variable이라고 부르는데
    • OOP에서는 인스턴스 멤버라고 부르는 것을 통해 상태정보를 관리한다.
    • 메서드 : 입력 + 인스턴스 멤버(상태정보, 데이터)에 의해 결과 값이 결정
      • 인스턴스 멤버(상태정보)를 바꾸는 역할을 하기도 한다.
    • 함수 : 입력에 의해 출력이 결정
      • 메서드처럼 사용하기 위해서는 call by reference 혹은 다른 변수에 할당
    • 메시지 패싱
      • 객체 간의 상호 작용 --> 객체가 가지고 있는 멤버 값(데이터, 상태 정보)의 변화
      • 내가 가진 건 1000이 적어지면 너에게 1000이 늘어난다.
      • interaction이 반드시 메서드에 의해 이루어져야 한다.
      • .은 속성을 가지고 온다는 뜻이다. 속성에는 인스턴스 멤버와 인스턴스 메서드가 있다.

절차지향 vs 객체지향

###procedural vs object-oriented

2개다 추상화를 하는 기법이다.

procedural : 함수를 이용해 추상화를 했다. 추상화의 도구로 함수를 이용 (절차지향)

  1. 이 프로그램은 어떤 일을 하는가?
  2. 기계와 비슷한 사고 방식
  3. 함수를 이용

object-oriented : 객체를 통해 추상화를 했다.

  1. 현실 세계(에 존재하는 객체(object)를 어떻게 모델링(modeling)할 것인가?
    1. 객체(object) : 사람, 동물, 자동차 등을 어떻게 프로그램으로 모델링 할 것인가?
  2. 사람과 비슷한 사고 방식
  3. 객체를 이용

객체 vs 인스턴스

메모리 상으로는 완벽히 같다.
하나를 볼 때는 객체로 보고
이 객체는 특정 클래스의 인스턴스라고 부른다.
why? 어떤 클래스에서 나왔는지 알고 싶을 때 - 클래스에 집중해서 말할 때

object란?

  1. 관련 있는 변수와 함수를 한곳에 모아(bundling) 놓은 곳(메모리의 영역)
    1. 변수 - 상태정보
    2. "관련 있는" 변수, 함수" "한곳에 모아" 가 중요하다.
  2. class를 통해 생성되므로 class의 속성을 가지고 있어야 한다.
  3. 속성
    1. instance member(변수)
      1. 각자의 객체가 가지는 값(값 = 상태정보)
      2. init에 보면 변수가 나와 있음
      3. 같은 속성을 가지고 있으나 속성 값이 다르다.
    2. instance method(함수)
      1. 객체가 할 수 있는 행동, 기능

—> 절차지향에서는 전체 프로그램을 다 봐야하지만.
—> 객체지향에서는 단위로 프로그램을 유추해볼 수 있다.

중요한 이해

클래스의 메모리와 객체의 메모리는 모두 다르다.
객체마다 모두 다른 메모리 공간을 가지고 있다.
각 객체가 인스턴스 멤버를 따로 가지고 있고 메서드 역시 각자 가지고 있다고 생각하는게 좋다.
my_acnt
balance / clnt_name / deposit / withdraw / transfer
your_acnt
balance / clnt_name / deposit / withdraw / transfer

미션 : 클래스를 쓰지 않고 OOP 구현

클래스를 쓰지 않고.
(클래스 멤버, 메소드 제외).
어떤 객체를 만들 수 있어야 하고
그 객체에 대해 함수를 호출하여 돈을 입금
init / deposit / withdraw / transfer.
하나의 unit을 딕셔너리로 고정한다.
class라는 유닛 대신에 딕셔너리로 묶어라.

def person_init(name, money):
    obj = {'name': name, 'money': money}
    obj['give_money'] = Person[1]
    obj['get_money'] = Person[2]
    obj['show'] = Person[3]
    print(obj)
    # --->    obj = {'name' : name, 'money' : money , 'give_money' : Person[1], 'get_money' : Person[2], 'show' : Person[3]}
    return obj


def give_money(self, other, money):  # 3
    self['money'] -= money
    other['get_money'](other, money)  # 4


def get_money(self, money):
    self['money'] += money


def show(self):
    print('{} : {}'.format(self['name'], self['money']))


Person = person_init, give_money, get_money, show

if __name__ == "__main__":
    # 객체 생성
    g = Person[0]('greg', 5000)  # 5
    j = Person[0]('john', 2000)

    g['show'](g)
    j['show'](j)
    print('')

    # 메시지 패싱
    g['give_money'](g, j, 2000)  # 6

    g['show'](g)
    j['show'](j)

+ Recent posts