본문 바로가기

Python

17. 객체지향과 클래스

1. 객체지향 프로그래밍

  • 문제를 여러개의 객체 단위로 나눠 작업하는 방식
 

 

1-1. 객체(Object)란?

  • 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말함
 

 

1-2. 클래스(Class)란?

  • 객체를 생성하기 위한 일종의 설계도와 같음
  • 클래스는 프로퍼티(필드), 메소드(함수)로 구성되어 있음
    • 프로퍼티(Property): 데이터가 저장되는 곳
    • 메소드(method): 객체의 동작에 해당하는 실행 블록

 

1-3. 클래스와 객체

  • 건축 설계도가 클래스라면, 실제로 지어진 집은 객체
  • 객체는 클래스로 생성되어 구체화된 인스턴스
  • 실제로 클래스가 인스턴스화 되어 메모리에 상주하는 형태를 객체라고 부름
  • 파이썬의 모든 변수와 함수는 객체로 저장
 

 

2. 클래스 만들기

class 클래스명:
    프로퍼티명1 = 값1
    프로퍼티명2 = 값2
    ...

    def 메소드명1(self, 변수1, 변수2 ..):
        메소드가 호출되면 실행할 문장
        ...

    def 메소드명2(self, 변수1, 변수2 ..):
        메소드가 호출되면 실행할 문장
        ...
  • 클래스를 통해 호출되는 변수를 프로퍼티(필드)라고 부름
  • 클래스를 통해 호출되는 함수를 메소드라고 부름
  • self: 클래스의 각 호출한 객체를 가리킴
class Dog:
    pass # pass : 내용이 없는 블록을 만들 때 사용
    
def func1():
    pass
# 클래스를 통해 객체를 생성
Rucy = Dog()
print(Rucy) # <__main__.Dog object at 0x7fb8b4668970>
print(type(Rucy)) #<class '__main__.Dog'>

li1 = list([1, 2, 3, 4, 5])
print(li1) # [1, 2, 3, 4, 5]
print(type(li1)) # <class 'list'>
print(id(li1)) # 140431277354048

PPomi = Dog()
print(PPomi) # print(PPomi)
print(type(PPomi)) # print(type(PPomi))

class Dog:
    name = '루시'
    age = 13
    family = '포메'

    def eat(self):
        print(self)
        print('사료를 먹습니다!')
        
Rucy = Dog() # Rucy 객체 생성
print(Rucy.name) # 루시
print(Rucy.age) # 13
print(Rucy.family) # 포메
Rucy.eat() 
# <__main__.Dog object at 0x7f5d841b7970>
# 사료를 먹습니다!
print(Rucy) # <__main__.Dog object at 0x7f5d841b7970>

# 다른 객체를 만들어도 프로퍼티 값은 같다
PPomi = Dog() # PPomi 생성
print(PPomi.name) # 루시
print(PPomi.age) # 13
print(PPomiPPomi.family) # 포메
PPomi.eat() 
# <__main__.Dog object at 0x7f5d841b7970>
# 사료를 먹습니다!
print(PPomi) # <__main__.Dog object at 0x7f5d841b7970>

3. 생성자(Constructor)

  • 클래스를 객체화 시킬 때 가장 먼저 자동으로 실행되는 메소드
  • __ init __(self)
  • 생성자에서는 해당 클래스가 다루는 데이터를 정의하고 초기화 함
class Dog:
    def __init__(self):
        print(self, 'init 호출!')
        
Rucy = Dog() # = 기준 왼쪽이 객체 오른쪽이 생성자
# <__main__.Dog object at 0x7f5d841bf3a0> init 호출!

class Dog:
    def __init__(self):
        self.name = '이름없음' 
        self.age = 0
        
Rucy = Dog() # Rucy 객체 생성
print(Rucy) # <__main__.Dog object at 0x7f5d841bfdf0>
print(Rucy.name) # 이름없음
print(Rucy.age) # 0

PPomi = Dog() # PPomi 객체 생성
print(PPomi) # <__main__.Dog object at 0x7f5d841b7490>
print(PPomi.name) # 이름없음
print(PPomi.age) # 0

Rucy.name = '루시'
Rucy.age = 13

print(Rucy) # 위의 Rucy 객체의 주소와 같음
# <__main__.Dog object at 0x7f5d841bfdf0>
print(Rucy.name) # 루시
print(Rucy.age) # 13

print(PPomi) # 위의 PPomi 객체의 주소와 같음
# <__main__.Dog object at 0x7f5d841b7490>
print(PPomi.name) # 뽀미
print(PPomi.age) # 7
class Dog:
    def __init__(self):
        self.name = '이름없음'
        self.age = 0
        # nickname = '닉네임없음' # 메소드 안에서만 사용할 수 있는 지역변수
        self.nickname = '닉네임없음'
        # print(f'{nickname} 객체가 생성됨')
    
    # def go(self):
    #     print(f'{nickname}가 달립니다!') # NameError: name 'nickname' is not defined

    def go(self):
        print(f'{self.nickname}가 달립니다!')
        
Rucy = Dog()
Rucy.name = '루시'
Rucy.go() # 닉네임없음가 달립니다!

class Dog:
    def __init__(self, name, age, nickname='닉네임없음'):
        self.name = name
        self.age = age
        self.nickname = nickname
        
        
# Rucy = Dog() # 매개변수를 보내지 않아 에러가 발생!
# TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'

Rucy = Dog('루시', 13) # 매개변수를 보내어 객체 생성
print(Rucy.name) # 루시
print(Rucy.age) # 13
print(Rucy.nickname) # 닉네임없음

4. 메소드

  • 해당 클래스의 객체에서만 호출가능한 함수
  • 해당 객체의 속성에 대한 연산을 행함
  • 객체이름.메소드명() 형태로 호출됨
class Counter:
    def __init__(self):
        self.num = 0
    def increment(self):
        self.num += 1
    def decrement(self):
        self.num -= 1
    def current_value(self):
        return self.num
    def reset(self):
        self.num = 0
        
KBbank = Counter()
print(KBbank.num) # 0

KBbank.increment()
print(KBbank.num) # 1

KBbank.decrement()
print(KBbank.num) # 0

# 객체의 파라미터에 직접 접근하는건 좋지 않는 방법이므로 메소드를 통하여 접근
print(KBbank.current_value()) 

KBbank.increment()
KBbank.increment()
KBbank.increment()
KBbank.increment()
KBbank.increment()
print(f'현재 대기인원 : {KBbank.current_value()}') # 현재 대기인원 : 5

HanaBank = Counter()
print(f'현재 대기인원 : {HanaBank.current_value()}') # 현재 대기인원 : 0

HanaBank.increment()
HanaBank.increment()
HanaBank.increment()
print(f'현재 대기인원 : {HanaBank.current_value()}') # 현재 대기인원 : 3

HanaBank.reset()
print(f'현재 대기인원 : {HanaBank.current_value()}') # 현재 대기인원 : 0

4-2. 메소드 타입

  • instance method: 객체 형태로 호출되기 때문에 해당 메소드를 호출한 객체에서만 사용
  • class method: 클래스 이름으로 호출하는 메소드(메소드 선언 위에 @staticmethod라고 표기)
class Math:
    def add(self, x, y):
        return x + y
    def multiply(self, x, y):
        return x * y
        
math = Math()

result1 = math.add(10, 3)
print(result1) # 13

result2 = math.multiply(10, 3)
print(result2) # 30

class Math:
    @staticmethod # 어노테이션을 붙여서 staticmethod를 선언
    def add(x, y):
        return x + y
    @staticmethod
    def multiply(x, y):
        return x * y
        
# staticmethod이므로 객체를 생성하지 않고도 바로 사용 가능
result1 = Math.add(10, 3)
print(result1) # 13

result2 = Math.multiply(10, 3)
print(result2) # 30

'Python' 카테고리의 다른 글

19. 스페셜 메소드  (0) 2023.03.10
18. 상속  (0) 2023.03.10
16. 랜덤 모듈  (0) 2023.03.10
15. 콜백함수와 람다함수  (0) 2023.03.09
14. 변수의 범위.  (0) 2023.03.09