KDT 수업/Python

[파이썬] 16. 객체지향과 클래스

니니는 진짜 전설이다 2023. 3. 10. 16:53

1. 객체지향 프로그래밍

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

1-1. 객체(Object)란?

  • 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른것과 식별 가능한 것을 말함(in real life)
  • 클래스에 정의된 내용대로 메모리에 생성된 것을 객체라고 함(in programming)
 

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

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

1-3. 클래스와 객체

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

2. 클래스 만들기

```
class 클래스명:
    프로퍼티명1 = 값1
    프로퍼티명2 = 값2
    ...
    def 메소드명(self, 변수1, 변수2, ...):
        메소드가 호출되면 실행할 문장
        ...
    def 메소드명2(self, 변수1, 변수2, ...):
        메소드가 호출되면 실행할 문장
        ...

```
  • 클래스를 통해 호출되는 변수를 프로퍼티(필드)라고 부름
  • 클래스를 통해 호출되는 함수를 메소드라고 부름
  • self: 클래스의 각 호출한 객체를 가리킴(어떤 곳에서 메소드를 호출하는지 알기 위해) (-> 셀프를 붙여야 다른 곳에서도 사용 가능)
  • 클래스의 앞글자는 항상 대문자로 쓴다
class Dog:
    pass    #내용이 없는 블록을 만들 때 사용
    
def func1():
    pass

 

# 클래스를 통해 객체를 생성
Rucy = Dog()
print(Rucy)
print(type(Rucy))
>>
<__main__.Dog object at 0x7fb09c33e700>
<class '__main__.Dog'>

PPomi = Dog()
print(PPomi)
print(type(PPomi))
>>
<__main__.Dog object at 0x7fb09c5ac160>
<class '__main__.Dog'>

>> 같은 클래스를 이용하지만 메모리 주소는 다름을 알 수 있다

 

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

    def eat(s):   
        print(s)                 
        print('사료를 먹습니다!')
Rucy = Dog()
print(Rucy.name)
print(Rucy.age)
print(Rucy.family)
Rucy.eat()
print(Rucy)
>>
루시
13
포메
<__main__.Dog object at 0x7fb09c33ea60>
사료를 먹습니다!
<__main__.Dog object at 0x7fb09c33ea60>
PPomi = Dog()
print(PPomi.name)
print(PPomi.age)
print(PPomi.family)
PPomi.eat()
print(PPomi)
>>
루시
13
포메
<__main__.Dog object at 0x7fb09c33e9a0>
사료를 먹습니다!
<__main__.Dog object at 0x7fb09c33e9a0>

 

3.생성자(Constructor)

  • 클래스를 객체화시킬 때 가장 먼저 실행되는 메소드
  • __ init __(self)
  • 생성자에서는 해당 클래스가 다루는 데이터를 정의하고 초기화 함
class Dog():
    def __init__(self):
        print(self, 'init 호출!')
        
Rucy = Dog()
>> <__main__.Dog object at 0x7fb09c33ec70> init 호출!
class Dog():
    def __init__(self):
        self.name = '이름없음'
        self.age = 0
        
Rucy = Dog()
print(Rucy)
print(Rucy.name)
print(Rucy.age)
>>
<__main__.Dog object at 0x7fb08c8218b0>
이름없음
0

PPomi = Dog()
print(PPomi)
print(PPomi.name)
print(PPomi.age)
>>
<__main__.Dog object at 0x7fb09c33ed90>
이름없음
0
Rucy.name = '루시'
Rucy.age = 13
PPomi.name = '뽀미'
PPomi.age = 7

print(Rucy)
print(Rucy.name)
print(Rucy.age)
>>
<__main__.Dog object at 0x7fb08c8218b0>
루시
13

print(PPomi)
print(PPomi.name)
print(PPomi.age)
>> 
<__main__.Dog object at 0x7fb09c33ed90>
뽀미
7

 

class Dog():
    def __init__(self):
        self.name = '이름없음'
        self.age = 0
        # nickname = '닉네임없음'    #메소드 안에서만 사용할 수 있는 지역변수
        self.nickname = '닉네임없음'
        # print(f'{nickname} 객체가 생성됨')

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

 

class Dog:
    def __init__(self, name, age, nickname = 'no 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)
print(Rucy.nickname)
>>
루시
13
no nickname

PPomi = Dog('뽀미', 7)
print(PPomi.name)
print(PPomi.age)
print(PPomi.nickname)
>>
뽀미
7
no nickname

 

 

4. 메소드 정의하기

  • 해당 클래스의 객체에서만 호출 가능한 함수를 메소드라고 한다
  • 해당 객체의 속성에 대한 연산을 행함
  • 객체이름.메소드명()형태로 호출됨
 

4-1. 메소드 정의하기

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())
>> 0

 

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()}')
>> 현재 대기인원: 6

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는 객체 생성 안해서 self 필요 없음. 그냥 바로 클래스를 통해 값을 받을 수 있다.
    def add(x, y):
        return x + y
    @staticmethod
    def multiply(x, y):
        return x * y
result1 = Math.add(10, 3)
print(result1)
>> 13

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

 

class Math:
    @staticmethod     
    def add(x, y):
        return x + y
    @staticmethod
    def multiply(x, y):
        return x * y

    def div(self, x, y):   #self -> 객체 생성해서 호출 해야함
        return x/y
math = Math()
result3 = math.div(10, 3)
print(result3)
>> 3.3333333333333335