TIL

TIL. 31 클래스의 속성, 비공개 속성 사용하기

codermun 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
반응형