Python

클래스(1)

haventmetyou 2023. 10. 18. 14:51

class

클래스는 객체의 구조와 행동을 정의, 복잡한 문제를 다루기 쉽도록 만듦

객체의 클래스는 초기화를 통해 제어

클래스와 메서드 만들기

class에 이름 지정하고 :(콜론) 붙인 뒤 다음 줄부터 def로 메서드 작성 > 반드시 들여쓰기

보통 파이썬에서 클래스 이름은 대문자로 시작

메서드의 첫 번째 매개변수는 반드시 self를 지정해야 함

>>> class Person:
...     def greeting(self):
...         print('hello')
...
>>> james = Person()    # Person 클래스로 james 인스턴스 만들기

메서드 호출

>>> james.greeting()    # 인스턴스를 통해 클래스의 메서드에 접근
hello

↑ 인스턴스 메서드

 

파이썬에서 흔히 볼 수 있는 클래스

>>> a = int(10)             # a = 10과 같음
>>> a
10
>>> b = list(range(10))
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> c = dict(x=10, y=20)    # c = {'x':10, 'y':20}
>>> c
{'x': 10, 'y': 20}
>>>
>>>
>>> maria = Person()
>>>
>>>
>>> b = list(range(10))
>>> b.append(20)
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20]
>>>
>>> 
>>> # 자료형 확인
>>> a = 10
>>> type(a)
<class 'int'>
>>>
>>> b = [0, 1, 2]
>>> type(b)
<class 'list'>
>>>
>>> c = {'x':10, 'y':20}
>>> type(c)
<class 'dict'>
>>>
>>> maria = Person()
>>> type(maria)
<class '__main__.Person'>

빈 클래스 만들기

class Person:
    pass

메서드 안에서 메서드 호출

>>> # self.메서드()
>>>
>>> class Person():
...     def greeting(self):
...         print('hello')
...     def hello(self):
...         self.greeting()
...
>>> james = Person()
>>> james.hello()
hello

특정 클래스의 인스턴스인지 확인

>>> class Person:
...     pass
...
>>> james = Person()
>>> isinstance(james, Person)
True
>>>
>>>
>>> def factorial(n):
...     if not isinstance(n, int) or n < 0:    # n이 정수가 아니거나 음수이면 함수를 끝냄
...         return None
...     if n == 1:
...         return 1
...     return n * factorial(n-1)
...
>>> factorial(5)
120
>>> factorial(-5)
>>> factorial(5.0)
>>>

 

속성 사용
# class의 선언
# class 클래스이름:
#     def __init__(self):
#         self.속성 = 값

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

    def greeting(self):
        print(self.hello)

james = Person()
james.greeting()

# 실행 결과
안녕하세요

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

__init__(initialize) 이름 그대로 인스턴스(객체) 초기화

앞뒤로 __ 밑줄 두 개가 붙은 메서드는 파이썬이 자동으로 호출해 주는 메서드 > 스페셜 메서드, 매직 메서드라고 부름

 

self의 의미

self는 인스턴스 자기 자신

__init__의 매개변수 self에 들어가는 값은 Person() 그리고 self가 완성된 뒤 james에 할당

 

인스턴스를 만들 때 값 받기

# class 클래스이름:
#     def __init__(self, 매개변수1, 매개변수2):
#         self.속성1 = 매개변수1
#         self.속성2 = 매개변수2

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

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

maria = Person('마리아', 20, '수원시')
maria.greeting()

print('이름:', maria.name)
print('나이:', maria.age)
print('주소:', maria.addr)

# 실행 결과
안녕하세요 저는 마리아입니다.
이름: 마리아
나이: 20
주소: 수원시

클래스 안에서 속성에 접근할 때는 self.속성 형식, 클래스 바깥에서 속성에 접근할 때는 인스턴스.속성 형식으로 접근

 

클래스의 위치 인수, 키워드 인수

# 1. 위치 인수와 리스트 언패킹 *args
class Person:
    def __init__(self, *args):
        self.hello = '안녕하세요'
        self.name = args [0]
        self.age = args [1]
        self.addr = args [2]

    def greeting(self):
        print(self.name, self.age, self.addr)
        
# 리스트로 묶어서 호출
maria = Person(*['마리아', 20, '수원시']) 
maria.greeting()

# 실행 결과
마리아 20 수원시


# 2. 키워드 인수와 딕셔너리 언패킹 **kwargs
class Person:
    def __init__(self, **kwargs):
        self.hello = '안녕하세요'
        self.name = kwargs ['name']
        self.age = kwargs ['age']
        self.addr = kwargs ['addr']
    def greeting(self):
        print(self.name, self.age, self.addr)


maria1 = Person(name='마리아', age=20, addr='수원시')
maria2 = Person(**{'name':'마리아', 'age':21, 'addr':'서울시'})

maria1.greeting()
maria2.greeting()

# 실행 결과
마리아 20 수원시
마리아 21 서울시

인스턴스를 생성한 뒤에 속성 추가, 특정 속성만 허용

# 인스턴스를 생성한 뒤 속성 추가
class Person:
    pass

maria = Person()
maria.name = '마리아'
print(maria.name)

james = Person()
print(james.name)

# 실행 결과
마리아
    print(james.name)
          ^^^^^^^^^^
AttributeError: 'Person' object has no attribute 'name'

마리아 인스턴스에만 name 속성을 추가했으므로 james 인스턴스에는 name 속성이 없음

class Person:
    # __init__ 속성값이 없음
    def greeting(self):
        self.hello = '하이'

maria = Person()
# print(maria.hello)    # 아직 hello 속성이 없음
maria.greeting()        # greeting 메서드를 호출해야
print(maria.hello)      # hello 속성이 생성됨

# 실행 결과
하이

인스턴스는 생성한 뒤에 속성을 추가할 수 있으므로 __init__ 메서드가 아닌 다른 메서드에서도 속성을 추가할 수 있음

단, 이때는 메서드를 호출해야 속성이 생성됨

# 특정 속성만 허용 __slots__
class Person:
    __slots__ = ['name', 'age']


maria = Person()
maria.name = '마리아'
maria.age = 20
maria.addr = '수원시'

# 실행 결과
    maria.addr = '수원시'
    ^^^^^^^^^^
AttributeError: 'Person' object has no attribute 'addr'

특정 속성만 허용하고 다른 속성은 제한하고 싶을 때 허용할 속성 이름만 slots에 리스트로 넣어 주면 됨

반드시 문자열로 지정

 

비공개 속성 사용
# class 클래스이름:
#     def __init__(self, 매개변수):
#         self.__속성 = 값

class Person:
    def __init__(self, name, age, addr, wallet):
        self.name = name
        self.age = age
        self.addr = addr
        self.__wallet = wallet    # 변수 앞에 __를 붙여 비공개 속성으로 만듦


maria = Person('마리아', 20, '수원시', 10000)
print(maria.name)
print(maria.__wallet)    # 클래스 바깥에서 비공개 속성에 접근하면 에러 발생

# 실행 결과
마리아
    print(maria.__wallet)
          ^^^^^^^^^^^^^^
AttributeError: 'Person' object has no attribute '__wallet'

예제: 돈 내는 pay 메서드

class Person:
    def __init__(self, name, age, addr, wallet):
        self.name = name
        self.age = age
        self.addr = addr
        self.__wallet = wallet    # 변수 앞에 __를 붙여 비공개 속성으로 만듦
    def pay(self, amount):
        self.__wallet -= amount   # 비공개 속성은 클래스 안의 메서드에서만 접근 가능
        print('이제 {0}원 남았습니다.'.format(self.__wallet))

maria = Person('마리아', 20, '수원시', 10000)
maria.pay(3000)

# 실행 결과
이제 7000원 남았습니다.

# + 지갑에 든 돈이 얼마인지 확인하고 돈이 모자라면 쓰지 못하도록

    def pay(self, amount):
        if amount > self.__wallet:
            print('돈이 모자라네....')
            return
        self.__wallet -= amount
        print('이제 {0}원 남았습니다.'.format(self.__wallet))
        
maria = Person('마리아', 20, '수원시', 10000)
maria.pay(13000)

# 실행 결과
돈이 모자라네....

비공개 메서드 사용

class Person:
    def __greeting(self):
        print('hello')

    def hello(self):
        self.__greeting()

james = Person()
james.__greeting()    # 오류

james.hello()

# 실행 결과
    james.__greeting()
    ^^^^^^^^^^^^^^^^
AttributeError: 'Person' object has no attribute '__greeting'

 

연습 문제 예제
# 34.5번 연습문제: 게임 캐릭터 클래스 만들기
# 다음 소스 코드에서 클래스를 작성하여 게임 캐릭터의 능력치와 '베기'가 출력되게 만드세요.

class Knight:
    def __init__(self, health, mana, armor):
        self.health = health
        self.mana = mana
        self.armor = armor
        
    def slash(self):
        print('베기')
        
x = Knight(health=542.4, mana=210.3, armor=38)
print(x.health, x.mana, x.armor)
x.slash()


# 실행 결과
542.4 210.3 38
베기

# 34.6번 심사문제: 게임 캐릭터 클래스 만들기
# 표준 입력으로 게임 캐릭터 능력치(체력, 마나, AP)가 입력됩니다
# 다음 소스 코드에서 애니(Annie) 클래스를 작성하여 티버(tibbers) 스킬의 피해량이 출력되게 만드세요
# 티버의 피해량은 AP * 0.65 + 400이며 AP(Ability Power, 주문력)는 마법 능력치를 뜻합니다

class Annie:
    def __init__(self, health, mana, ability_power):
        self.health = health
        self.mana = mana
        self.ability_power = ability_power
        
    def tibbers(self):
        ap = self.ability_power * 0.65 + 400
        print('티버: 피해량 {}'.format(ap))
        
health, mana, ability_power = map(float, input().split())

x = Annie(health=health, mana=mana, ability_power=ability_power)
x.tibbers()


# 실행 결과

511.68 334.0 298      # 표준 입력
티버: 피해량 593.7    # 표준 출력

1803.68 1184.0 645     # 표준 입력
티버: 피해량 819.25    # 표준 출력