ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL.32 클래스의 속성과 메서드
    TIL 2020. 11. 9. 17:50
    728x90

    ## 속성에는 클래스 속성과 인스턴스 속성으로 나눈다.

    ## 이전까지 배웠던 속성은 인스턴스 속성이었다.


    ## 클래스 속성

    ## 클래스 속성은 클래스 아래에 바로 속성을 만들면 된다.

    # class 클래스이름:

    #     속성 = 값

     

    # 가방에 물건을 넣는 동작으로 알아보자.

    class Person:
        bag = []    # 클래스 속성 bag
    
         def put_bag(self, stuff):
            self.bag.append(stuff)   
    
    james = Person()
    james.put_bag('책')
    
    
    maria = Person()
    maria.put_bag('열쇠')
    
    
    print(james.bag) # ['책', '열쇠']
    print(maria.bag) # ['책', '열쇠']

    ## 예상되는 결과로는 "책" // "열쇠" 처럼 따로따로 결과가 나와야하는데 

        물건이 합쳐져서 출력이 되는 것을 볼 수 있다.

    ## 즉, 클래스 속성은 클래스에 속해 있으며 "모든 인스턴스"에서 공유한다.

     

    class Person:
        bag = []
    
        def put_bag(self, stuff):
            self.bag.append(stuff)  ## self 사용하여 클래스 속성 bag 접근

    ## put_bag 메서드에서 클래스 속성에 접근하기 위해 self를 사용하였다.

    ## 사실 self는 현재 인스턴스를 뜻하므로 클래스 속성을 지정할때 사용하기에는 에매한 부분이 있다.

    ### 따라서, 클래스 속성에 접글할때는 클래스 이름으로 접근하면 코드가 더 명확해진다.

    # 클래스.속성

    class Person:
        bag = []
    
        def put_bag(self, stuff):
            Person.bag.append(stuff)    # 클래스 이름으로 클래스 속성에 접근
    
    print(Person.bag)

    ## print 함수를 사용한 것과 같이 클래스 바깥에서도 클래스.속성으로 접근할 수 있다.


    ## 속성, 메서드 이름을 찾는 순서

    ## 파이썬에서는 속성, 메서드 이름을 찾을때 인스턴스 < 클래스 순으로 찾아간다.

    ## 그래서 인스턴스 속성이 없으면 클래스 속성을 찾게 되므로 james.bag, maria.bag도 문제 없이 동작한다. 

    ## 겉보기에는 인스턴스 속성을 사용하는 것 같지만 실제로는 클래스 속성이다.

     

    # 인스턴스와 클래스에서 __dict__ 속성을 출력해보면 

       현재 인스턴스와 클래스의 속성을 딕셔너리로 확인할 수 있습니다.

    # 인스턴스.__dict__

    # 클래스.__dict__

     

    ## james.bad 을 사용했을때의 클래스 속성을 찾는 과정

     

     


    ## 인스턴스 속성 사용하기

    ## 위 물건을 가방에 넣는 동작에서 여러 사람이 가방을 공유하지 않으려면 인스턴스 속성을 사용하면 된다.

    ## 그냥 bag을 인스턴스 속성으로 만들어주자

    class Person:
        def __init__(self):
            self.bag = []
            
        def put_bag(self, stuff):
            self.bag.append(stuff)
    
     
    james = Person()
    james.put_bag('책')
    
     
    maria = Person()
    maria.put_bag('열쇠')
     
    
    print(james.bag) # 책
    print(maria.bag) # 열쇠

    ### 즉, 인스턴스 속성은 인스턴스 별로 독립되어 서로 영향을 주지 않음을 알 수 있다.


    ### 클래스 속성과 인스턴스 속성의 차이점

    ## 클래스 속성: 모든 인스턴스가 공유. 인스턴스 전체가 사용해야 하는 값을 저장할 때 사용

    ## 인스턴스 속성: 인스턴스별로 독립되어 있음. 각 인스턴스가 값을 따로 저장해야 할 때 사용


    ## 비공개 클래스 속성 사용하기

    ## 클래스 속성도 __(밑줄 두개)로 비공개 클래스 속성을 만들 수 있으며, 

        클래스 안에서만 접근이 가능하며 클래스 바깥에서는 접근이 불가능하다.

    # class 클래스이름:

    #     __속성 = 값    # 비공개 클래스 속성

     

    ## 게임 케릭터는 아이템을 최대 10개 까지 보유 할 수 있다는 코드로 알아보자.

    class Knight:
        __item_limit = 10    # 비공개 클래스 속성
    
         def print_item_limit(self):
            print(Knight.__item_limit)    # 클래스 안에서만 접근할 수 있음
    
     
    
    x = Knight()
    
    x.print_item_limit()    # 10
    
    print(Knight.__item_limit)    # 클래스 바깥에서는 접근할 수 없음 // error

     

    ## 아이템이 최대 10개 보유 제한인데 클래스를 사용하는 사람이 마음대로 1000으로 수정하면 곤란하기 때문에,

         비공개 클래스 속성으로 사용한 것이다.


    ## 클래스와 메서드의 독스트링 사용하기

    ## 함수와 마찬가지로 클래스와 메서드에서도 독스트링을 사용할 수 있다.

    ## :(콜론) 바로 다음 줄에 """ """(큰따옴표 세 개) 또는 ''' '''(작은따옴표 세 개)로 문자열을 입력

    ## 클래스의 독스트링 -> 클래스.__doc__   

    ## 메서드의 독스트링 -> 클래스.메서드.__doc__ 또는 인스턴스.메서드__doc__ 형식을 사용한다.

    class Person:
        '''사람 클래스입니다.'''
      
    
        def greeting(self):
            '''인사 메서드입니다.'''
            print('Hello')
            
    print(Person.__doc__)             # 사람 클래스입니다.
    
    print(Person.greeting.__doc__)    # 인사 메서드입니다.
    
    maria = Person()
    print(maria.greeting.__doc__)     # 인사 메서드입니다.
    
    

    ## 정적 메서드 사용하기

    ## 지금까지는 클래스의 메서드를 호출할때 인스턴스를 생성하고 이를 통해 호출하였다.

    ## 이번에는 인스턴스를 사용하지 않고 클래스에서 바로 호출 할 수 있는 정적 메서드와 클레스 메서드를 알아보자.

     

    ## 정적 메서드

    ## 클래스에서 바로 호출 할 수 있는 메서드를 정적 메서드라 한다.

    ## @staticmethod 를 붙히는 것으로 정적 메서드를 생성할 수 있으며, 이때 매개변수에 self를 지정하지 않는다.

    # class 클래스이름:

    #     @staticmethod

    #     def 메서드(매개변수1, 매개변수2):

    #         코드

    ## @staticmethod 처럼 @가 붙은 것을 "데코레이터"라고 하며 메서드(함수)에 추가 기능을 구현 할 때 사용한다.

    class Calc:
        @staticmethod
        def add (a, b):
            print(a + b)
    
        def mul (a, b):
            print(a * b)

    ## Calc 클래스에서 @staticmethod를 붙혀서 add 메서드와 mul 메서드를 만들었다.

    ## 정적 메서드를 호출할때는 아래와 같이 클래스에서 메서드를 바로 호출하면 된다.

    # 클래스.메서드()

    Calc.add(10, 20) # 30
    
    Calc.mul(20, 30) # 600

    ## 정적 메서드에서는 self를 받지 않으므로 인스턴스 속성에는 접근 할 수 없다.

    ## 그래서 보통 정적 메서드는 인스턴스 속성, 인스턴스 메서드가 필요 없을때 사용한다.

    ## 만든 Calc 클래스에 들어있는 add, mul 메서드는 숫자 두개를 받아서 더하거나 곱할 뿐 

        인스턴스의 속성은 필요하지 않다.


    ## 정적 메서드 사용하는 이유

    ## 정적 메서드는 실행이 외부 상태에 영향을 끼치지 않는 순수 함수 (pure function)을 만들 때 사용한다.

    ## 즉, 정적 메서드는 인스턴스의 상태를 변화시키지 않는 메서드를 만들때 사용한다.


    ## 파이썬 자료형의 인스턴스 메서드와 정적 메서드

    ## 파이썬의 자료형도 인스턴스 메서드와 정적 메서드로 나누어져 있다.

    ## 아래의 예로 세트에 요소를 더할때는 인스턴스 메서드를 사용하고, 

        합집합을 구할때는 정적 메서드를 사용하도록 만들어져 있다.

    a = {1, 2, 3, 4}
    
    a.update({5})    # 인스턴스 메서드
    
    a
    # {1, 2, 3, 4, 5}
    
    set.union({1, 2, 3, 4}, {5})    # 정적(클래스) 메서드
    
    # {1, 2, 3, 4, 5}

     

    ## 이처럼 내용을 변경해야할 때 --> 인스턴스 메서드 

    ## 인스턴스 내용과 상관없이 결과만 구현하면 될때 --> 정적 메서드를 사용하면 된다. 


    ## 클래스 메서드 사용하기

    ## 정적 메서드와 비슷하지만, 차이점이 있는 클래스 메서드 

    ## 클래스 메서드는 @classmethod를 붙이면 된다. 여기서, 첫번째 매개변수는 반드시 cls (class) 로 지정해야한다.

    # class 클래스이름:

    #     @classmethod

    #     def 메서드(cls, 매개변수1, 매개변수2):

    #         코드

    class Person:
        count = 0   # 클래스 속성
    
        
        def __init__(self):
            Person.count += 1     # 인스턴스를 만들때 클래스 속성 count에 1을 누적시킴 /
            ## self.count도 가능하지만 클래스 속성에 사용할때는 클래스명.속성으로 접근하자
                                  # 코드가 더 명확해진다.
    
        @classmethod
        def pi_count(cls):
            print('{}명 생성되었습니다.'.format(cls.count))
    
    
    james = Person()
    maria = Person()
    
    
    james.pi_count()      # 2명 생성되었습니다. (클래스 속성은 "모든 인스턴스에 공유한다")
    
    maria.pi_count()      # 2명 생성되었습니다. (클래스 속성은 "모든 인스턴스에 공유한다")
    
    Person.pi_count()     # 2명 생성되었습니다.

    ## 먼저, 인스턴스가 만들어질때마다 호출되는 __init__메서드를 이용해 

        인스턴스가 만들어질때마다 count에 1을 더하는 코드를 만들어준다.(누적)

    ## 클래스 속성에 접근하기 위해 self.속성 보다는 클래스.속성을 사용하는 것으로 하자.

        @classmethod
        def pi_count(cls):
             print('{}명 생성되었습니다.'.format(cls.count))

    ## @classmethod를 붙혀 클래스 메서드를 만들어 준다.

    ## 클래스 메서드는 첫 번째 매개변수는 cls이며, 여기에는 현재 클래스(Person)이 들어온다.

    ## 따라서 cls.count 처럼 "cls로 클래스 속성 count에 접근 할 수 있다."

    Person.pi_count()    # 2명 생성되었습니다.

    ## pi_count는 클래스 메서드이므로 클래스.메서드() 형식 처럼 클래스로 호출해준다.


    ### 클래스 메서드와 정적 메서드의 공통점과 차이점

    ## 공통점 == 인스턴스 없이 호출 할 수 있다는 점

    ## 차이점 == 클래스 메서드는 메서드 안에서 클래스 속성, 클래스 메서드에 접근해야 할 때 사용함

    ## 특히 cls를 사용하면 메서드 안에서 현재 클래스의 인스턴스를 만들 수 있다는 점

    ## 즉, cls == 클래스 이므로 cls() == Person() 과 같다

        @classmethod
        def create(cls):
            p = cls()    # cls()로 인스턴스 생성
            return p
    
    

     

     




     

    728x90
Designed by Tistory.