ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL. 31 클래스의 속성, 비공개 속성 사용하기
    TIL 2020. 11. 8. 17:45
    728x90

    ## 클래스 속성 사용하기

    ## 클래스에서 속성 만들기

    ## 속성(attribute)를 만들때는 "__init__ 메서드" 를 사용하며, 안에서 self.속성에 값을 할당하면 된다.

    # class 클래스이름:

    #     def __init__(self):

    #         self.속성 = 값

    class Person:
        def __init__(self):  ## 속성을 정의한다는 뜻
            self.hello = '안녕하세요.'
    
        def greeting(self):
            print(self.hello)
    
    james = Person()
    
    james.greeting()    
    ::
    안녕하세요.

     

    ## __init__ 메서드

    ## __init__ 메서드는 james = Person()처럼 클래스에 ( )(괄호)를 붙여서 인스턴스를 만들 때 

        호출되는 특별한 메서드이다 (클래스로 인스턴스를 만들때 호출되는 메서드)

    ## __init__(initialize)이라는 이름 그대로 인스턴스(객체)를 초기화한다.

    class Person:
        def __init__(self):
            self.hello = '안녕하세요.'

    ## 이처럼 앞, 뒤로 __(밑줄 두개)가 붙은 메서드는 파이썬이 자동으로 호출해주는 메서드로

    ## 스페셜 메서드 (special method) 또는 매직 메서드 (magic method)라 부른다.

    ## 앞으로 파이썬의 여러 가지 기능을 사용할때는 이러한 스페셜 메서드를 채우는 식으로 사용하게 된다.

     

    ## 위 식에서의 인스턴스 및 메서드 호출

    james = Person()
    
    james.greeting()    # 안녕하세요.

     

    ## 지금까지 __init__로 속성을 만들고 greeting 메서드에서 속성을 사용하였다.

    ### 속성은 "__init__ 메서드"에서 만든다는 점 // self에 .(점)을 붙인 뒤 값을 할당한다는 점이 중요

    ## 클래스 안에서 속성을 사용할 때도 self.hello 처럼 self에 점을 붙여서 사용해야 한다.


    ## self의 의미

    ## self는 인스턴스 자기 자신을 의미합니다.

    # 인스턴스가 생성될 때 self.hello = '안녕하세요.'처럼 자기 자신에 속성을 추가했다

    # 여기서 __init__의 매개변수 self에 들어가는 값은 Person()이라 할 수 있다. 

    # 그리고 self가 완성된 뒤 james에 할당되고 

    # 이후 메서드를 호출하면 현재 인스턴스가 자동으로 매개변수 self에 들어온다. 그래서 greeting 메서드에서 print(self.hello)처럼 속성을 출력할 수 있는 것이다.

     


    ## 인스턴스를 만들때 값 받기

    ## 클래스로 인스턴스를 만들때의 값을 받는 방법

    # class 클래스이름:

    #     def __init__(self, 매개변수1, 매개변수2):

    #         self.속성1 = 매개변수1

    #         self.속성2 = 매개변수2

    class Person:
        def __init__(self, name, age, address):
            self.hello = '안녕'
            self.name = name
            self.age = age
            self.address = address    ## name, age, address (매개변수 )를 그대로 self에 넣어 속성으로 만들었다.
    
        def greeting(self):
            print('{0} 저는 {1} 입니다.'.format(self.hello, self.name))  ## 속성에 접근하기 위해 self. 꼭 사용
    
    maria = Person('마리아', 20, '서울시 서초구 반포동')
    maria.greeting()
    :: 안녕 저는 마리아 입니다.
    
    
    print('이름:', maria.name)       # 마리아
    print('나이:', maria.age)        # 20
    print('주소:', maria.address)    # 서울시 서초구 반포동

    ## __init__메서드를 보면 self 다음 매개변수 3개를 지정하였다.

    ## 여기서 maria라는 인스턴스를 생성하면서 이름, 나이, 주소 등을 클래스의 ()안에 변수로 할당해준다.

    ## 이렇게 하면 이름은 '마리아', 나이는 20, 주소는 '서울시 서초구 반포동'인 maria 인스턴스가 만들어진다.

    ## 아래 greeting에 인수로 넣어주는 것은 greeting 메서드 안에서 __init__ 속성 값을 불러와 출력하는 형태이므로 

    ## __init__ 메서드의 name, age, address 값이 입력된 상태가 아니게되어 error 가 발생한다.

    ## 매개변수가 들어있는 메서드에 인수를 넣어주는것에 맞다.

    ### 클래스   안에서 속성에 접근할때는 self.속성 형식을 이용한다.

     def greeting(self):
            print('{0} 저는 {1} 입니다.'.format(self.hello, self.name))

    ### 클래스 바깥에서 속성에 접글할때는 인스턴스.속성 형식

    print('이름:', maria.name)       # 마리아
    
    print('나이:', maria.age)        # 20
    
    print('주소:', maria.address)    # 서울시 서초구 반포동

    ## 위처럼 인스턴스를 통해 접근하는 속성을 "인스턴스 속성"이라 부른다.


    ## 클래스에서의 위치 인수와 키워드 인수

    ## 클래스로 인스턴스를 만들 경우 위치, 키워드 인수를 사용할 수 있으며, 규칙은 함수와 같다.

     

    ## 위치인수

    ## 위치인수에서 리스트 언패킹을 사용하려면 *args를 사용, 

        이때 매개변수에서 값을 가져오려면 args[0]과 같이 인덱스로 접근해야 한다.

    class Person:
        def __init__(self, *args):
            self.name = args[0]
            self.age = args[1]
            self.address = args[2]
    
    maria = Person(*['마리아', 20, '서울시 서초구 반포동'])

     

    ## 키워드 인수

    ## 키워드 인수와 딕셔너리 언패킹을 사용하려면 **kwargs를 사용, 

        이때 매개변수에서 값을 가져오려면 kwargs['name']과 같이 "키"값을 이용해 접근해야 한다.

    class Person:
        def __init__(self, **kwargs):    # 키워드 인수
            self.name = kwargs['name']
            self.age = kwargs['age']
            self.address = kwargs['address']
    
    maria1 = Person(name='마리아', age=20, address='서울시 서초구 반포동')
    maria2 = Person(**{'name': '마리아', 'age': 20, 'address': '서울시 서초구 반포동'})

    ### 인스턴스 생성 한 뒤에 속성 추가하기 및 특정 속성만 허용하기

    ## 지금까지는 클래스의 인스턴스 속성은 __init__ 메서드에서 추가한 뒤 사용했지만, 

         클래스를 먼저 만든 뒤에도 속성을 계속 추가할 수 있다.

    # 인스턴스.속성 = 값 

     

    ## 빈 클래스를 이용해 속성 추가하기

    class Person:
        pass
    
    
    maria = Person()         # 인스턴스 생성
    
    maria.name = '마리아'    # 인스턴스를 만든 뒤 속성 추가
    
    print(maria.name)
    ::
    '마리아'
    james = Person()    # james 인스턴스 생성
    
    james.name    # maria 인스턴스에만 name 속성을 추가했으므로 james 인스턴스에는 name 속성이 없음
    
    Traceback (most recent call last):
      File "<pyshell#11>", line 1, in <module>
        james.name
    AttributeError: 'Person' object has no attribute 'name'

    ## 이렇게 추가한 속성은 해당 인스턴스(여기서는 maria)에만 생성이 된다.

    ## 클래스로 다른 인스턴스를 만들 경우 추가한 name 이라는 속성은 다른 인스턴스에 생성되지 않는다.

     

    ## 인스턴스 생성 후, __init__메서드가 아닌 다른 메서드로 속성 생성하기

    class Person:
        def greeting(self):
            self.hello = '안녕하세요'    # greeting 메서드에서 hello 속성 추가
    
    
    maria = Person()
    
    maria.hello    # 아직 hello 속성이 없음
    
    
    Traceback (most recent call last):
      File "<pyshell#22>", line 1, in <module>
        maria.hello
    AttributeError: 'Person' object has no attribute 'hello'
    
    maria.greeting()    # greeting 메서드를 호출해야
    
    maria.hello         # hello 속성이 생성됨
    ::
    '안녕하세요'

     

    ## 특정 속성만 허용하고 다른 속성은 제한하는 방법

    ## 인스턴스는 자유롭게 속성을 추가 할 수 있지만 특정 속성만 허용하고 다른 속성은 제한을 둘 수 있다.

    ## 이떄 클래스에서 __slots__에 허용할 속성 이름을 리스트로 넣어주면 되며, 반드시 속성이름은 문자열 이여야만 한다.

    # __slots__ = ['속성이름1, '속성이름2']

    class Person:
        __slots__ = ['name', 'age']    # name, age만 허용(다른 속성은 생성 제한)
    
    
    maria = Person()
    
    maria.name = '마리아'                     # 허용된 속성
    
    maria.age = 20                            # 허용된 속성
    
    maria.address = '서울시 서초구 반포동'    # 허용되지 않은 속성은 추가할 때 에러가 발생함
    
    Traceback (most recent call last):
      File "<pyshell#32>", line 1, in <module>
        maria.address = '서울시 서초구 반포동'
    AttributeError: 'Person' object has no attribute 'address'

    ## 앞서 만든 Person 클래스에서 hello, name, age, address 속성이 있었다.

    ## 이 속성들은 메서드에서 self로 접근 할 수 있고, 

        인스턴스.속성 형식으로 클래스 바깥에서 접근 할 수 있었다.

    class Person:
        def __init__(self, name, age, address):
            self.hello = '안녕하세요.'
            self.name = name
            self.age = age
            self.address = address
    
    maria = Person('마리아', 20, '서울시 서초구 반포동')
    
    maria.name
    ::
    '마리아'

     

     

    ## 비공개 속성 사용하기

    ## 클래스 바깥에서는 접근 할 수 없고, 클래스 안에서만 사용할 수 있는 비공개 속성(private attribute)

    ## __속성 (밑줄 두개) // __속성__ 밑줄이 양옆으로 올 경우 비공개 속성이 아님

    # class 클래스이름:

    #     def __init__(self, 매개변수)

    #         self.__속성 = 값

    class Person:
        def __init__(self, name, age, address, wallet):
            self.name = name
            self.age = age
            self.address = address
            self.__wallet = wallet  # 변수 앞에 __를 붙혀 비공개 속성으로 만듬
    
    
    maria = Person('마리아', 20, '서울시 서초구 반포동', 10000)
    
    maria.__wallet -= 10000 # 클래스 바깥에서 비공개 속성에 접근하였으므로 error
    
    Traceback (most recent call last):
      File "C:\project\class_private_attribute_error.py", line 9, in <module>
        maria.__wallet -= 10000    # 클래스 바깥에서 비공개 속성에 접근하면 에러가 발생함
    AttributeError: 'Person' object has no attribute '__wallet' 

     

     

    ## 비공개 속성은 클래스 안의 메서드에서만 접근이 가능하다.

    ## 아래와 같이 pay 메서드를 이용해 돈을 내고 남은 금액이 얼마인지 알아보는 함수를 작성해보자

    class Person:
        def __init__(self, name, age, address, wallet):
            self.name = name
            self.age = age
            self.address = address
            self.__wallet = wallet    # 변수 앞에 __를 붙여서 비공개 속성으로 만듦
    
        def pay(self, amount):
            self.__wallet -= amount
            print('이제 돈이 {} 남았네요.'.format(self.__wallet))
    
    
    
    maria = Person('마리아', 20, '서울시 서초구 반포동', 10000)
    
    maria.pay(3000)
    ::
    이제 돈이 7000 남았네요.

    ## 지불해야하는 금액에 따라 지갑 안의 돈보다 많으면 결제를 진행하고 부족하면 잔액 부족을 출력한다.

    def pay (self, amount):
            if amount > self.__wallet:
                print('잔액부족') # 잔액 출력하지 않고 return 만 사용하기도 함
                return
            self.__wallet -= amount
            print(self.__wallet) 
    
    
    maria = Person('마리아', 20, '서울시 서초구 반포동', 10000)
    
    maria.pay(5000)
    ::
    5000

     


     

     

    ### 이처럼 비공개 속성은 클래스 바깥으로 드러내고 싶지 않은 값에 사용한다.

    ### 즉, 중요한 값인데 바깥에서 함부로 바꾸면 안될 때 비공개 속성을 주로 사용한다.

    ### 따라서 비공개 속성을 바꾸는 경우는 클래스 안의 메서드로 한정한다.

     

     


     

     

    ### 지금까지 클래스 사용 방법에 대해 알아보았다.

    ### 클래스는 특정 개념을 표현(정의)만 할 뿐 사용을 하려면 인스턴스로 만들어야 한다는 점이 중요

    ### 그리고 속성, 메서드를 사용할 때는 self와 인스턴스를 통해 사용해야 한다는 점도 기억하자




    ## 공개 속성과 비공개 속성

    ## 공개 속성(public attribute) == 클래스 바깥에서 접근할 수 있는 속성

    ## 비공개 속성(private attribute) == 클래스 바깥에서 접근할 수 없는 속성


    ## 비공개 메서드 

    ## 속선 뿐 아닌 메서드에서도 __(밑줄 두개)로 시작하는 비공개 매서드를 만들 수 있다.

    class Person:
        def __greeting(self):
            print('Hello')
    
        def hello(self):
            self.__greeting()    # 클래스 안에서는 비공개 메서드를 호출할 수 있음
    
    
    james = Person()
    
    james.__greeting()    # 에러: 클래스 바깥에서는 비공개 메서드를 호출할 수 없음

     

    ## 보통 내부에서만 호출되어야 하는 메서드를 비공개 메서드로 만드는데

    ## 예로 게임 케릭터가 마나를 소비하여 스킬을 사용한다고 가정하자

    ## 마나 소비량을 계산해서 차감하는 메서드는 비공개로 만들고, 스킬을 쓰는 메서드는 공개 메서드로 만들면 된다.

    ## 만약 마나를 차감하는 메서드가 공개로 되어있으면,

         마음대로 마나를 차감 시 킬 수 있으므로 잘못된 클래스 설계가 된다.



     

    728x90
Designed by Tistory.