[Python 입문 강좌 - 16] 파이썬 클래스와 객체 정리 및 사용법

 

더보기

 


1. 객체 지향 프로그래밍이란?

 

객체 지향 프로그래밍(Object-Oriented Programming, OOP)은 현실 세계의 사물이나 개념을 프로그램 안에서 '객체(Object)'로 만들어 관리하는 방법입니다. 객체는 클래스라는 틀을 사용해 만들어진 것인데, 클래스는 객체의 '속성(Attribute)'과 '행위(Behavior)'를 정의합니다. '속성'은 객체의 특성이나 상태를 나타내고, '행위'는 객체가 할 수 있는 일을 의미합니다. 행위는 '메소드(Method)'라고 부르는 함수를 사용해 구현합니다.

 

예를 들어, '동물'이라는 클래스를 만들어 보겠습니다. 동물 클래스의 속성에는 종(species), 나이(age), 이름(name) 등이 있을 수 있고, 행위에는 먹다(eat), 움직이다(move), 소리내다(make_sound) 등이 있을 수 있습니다. 이렇게 정의된 클래스를 사용해 실제 동물 인스턴스를 만들 수 있습니다.

 

실제 어플리케이션 개발에선 프로그램이 매우 크고 복잡해질 수 있는데, 객체 지향 프로그래밍을 사용하면 이를 좀 더 쉽게 관리할 수 있습니다. 클래스는 자체적으로 데이터와 메소드를 가지고 있어 다른 클래스들로부터 독립성을 가지기 때문에, 프로그램의 각 부분을 서로 분리하여 관리할 수 있습니다.

 


1.1 객체 지향 프로그래밍의 장점

 

  • 코드 재사용성: 클래스를 잘 설계하면, 비슷한 기능을 하는 다른 객체를 쉽게 만들 수 있습니다.
  • 유지 보수성: 각 클래스는 독립적이기 때문에, 문제가 생긴 부분만 수정하면 됩니다.
  • 확장성: 새로운 기능이 필요하면, 기존 클래스를 수정해 쉽게 추가할 수 있습니다.

 


1.2 절차적 프로그래밍 언어와 객체지향 프로그래밍 언어의 차이

 

절차적 프로그래밍 언어와 객체 지향 프로그래밍 언어는 프로그래밍의 접근 방식에 큰 차이가 있습니다. 이 차이를 이해하기 위해 각각의 프로그래밍 방식을 간단하게 살펴보겠습니다.

 


1.2.1 절차적 프로그래밍 언어

 

절차적 프로그래밍은 프로그램을 일련의 순차적인 절차들로 구성하는 방식입니다. 이러한 절차는 함수나 프로시저로 구현되며, 프로그램은 이러한 함수들을 차례로 호출해 작업을 수행합니다. 절차적 프로그래밍의 대표적인 예로는 C, Pascal, Fortran 등의 언어가 있습니다.

 

절차적 프로그래밍은 다음과 같은 특징을 가지고 있습니다. 첫 번재로 프로그램의 흐름을 순차적으로 구성합니다. 두 번째는 데이터와 함수를 분리하여 관리합니다. 세 번째는 전역 변수를 사용하여 데이터를 공유할 수 있습니다. 네 번째는 대규모 프로젝트에서 코드 관리가 어려울 수 있습니다.

 

아래는 C언어를 이용해 절차적 프로그래밍 예시를 보여주는 코드입니다. Person이라는 구조체를 사용하여 사람의 정보를 저장하고, print_person_info라는 함수를 사용하여 사람의 정보를 출력합니다.

 

#include <stdio.h>

typedef struct {
    char name[20];
    int age;
} Person;

void print_person_info(Person person) {
    printf("이름: %s, 나이: %d\n", person.name, person.age);
}

int main() {
    Person person1;
    strcpy(person1.name, "홍길동");
    person1.age = 30;

    print_person_info(person1);

    return 0;
}

 


1.2.2 객체 지향 프로그래밍 언어

 

객체 지향 프로그래밍은 프로그램을 객체라는 독립적인 단위로 구성하는 방식입니다. 객체는 데이터와 이를 조작하는 메소드를 함께 가지고 있으며, 객체 간의 상호작용을 통해 프로그램이 동작합니다. 객체 지향 프로그래밍의 대표적인 예로는 Java, C++, Python 등의 언어가 있습니다.

 

객체 지향 프로그래밍은 다음과 같은 특징을 가지고 있습니다. 첫 번째 프로그램을 객체 단위로 구성합니다. 두 번째 데이터와 함수(메소드)를 하나의 객체로 묶어 관리합니다. 세 번째 캡슐화, 상속, 다형성 등의 객체 지향 원칙을 지원합니다. 네 번째 코드의 재사용성과 확장성이 높습니다.


아래는 파이썬을 이용해 객체 지향 프로그래밍 예시를 보여주는 코드입니다. Person이라는 클래스를 만들고, 그 안에 __init__ 메소드와 print_person_info 메소드를 정의합니다. 그리고 Person 객체를 생성하고, 해당 객체의 메소드를 호출하여 정보를 출력합니다.

 

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def print_person_info(self):
        print(f"이름: {self.name}, 나이: {self.age}")

person1 = Person("홍길동", 30)
person1.print_person_info()

 


요약하면, 절차적 프로그래밍 언어는 순차적인 절차를 따르며 데이터와 함수를 분리해서 관리하는 반면, 객체 지향 프로그래밍 언어는 객체라는 독립적인 단위를 중심으로 데이터와 함수를 함께 묶어 관리하는 것이 가장 큰 차이점입니다. 객체 지향 프로그래밍이 절차적 프로그래밍에 비해 코드의 재사용성과 확장성이 높아 대규모 프로젝트에서 더 효율적으로 코드를 관리할 수 있습니다.

 


1.3 추상화 개념

 

프로그래밍에서 추상화는 복잡한 기능이나 데이터를 간단한 형태로 만드는 것을 의미합니다. 클래스는 추상화의 도구로, 어떤 것의 공통된 특징을 모아서 하나의 틀로 만듭니다. 그리고 이 틀을 이용해서 구체적인 객체를 만드는데, 이 구체적인 객체를 인스턴스라고 합니다.

예를 들어, 동물을 생각했을 때, 동물은 이름, 나이, 종 등의 특징이 있고, 먹고 움직이고 소리 내는 행동이 있습니다. 이렇게 동물의 공통된 특징을 모아 '동물'이라는 클래스를 만들 수 있습니다. 그리고 이 클래스를 기반으로 실제 개나 고양이와 같은 구체적인 동물 객체를 만들 수 있는데, 이 객체들을 인스턴스라고 부릅니다.

결국 추상화는 복잡한 것들을 간단하게 만들어 관리하기 쉽게 하는 방법입니다. 이를 통해 프로그램을 이해하기 쉽고, 변경하기 쉬운 구조로 만들 수 있습니다.

 


2. 클래스란?

 

클래스(Class)는 객체 지향 프로그래밍에서 중요한 개념으로, 객체를 만들기 위한 틀(template)이라고 볼 수 있습니다. 클래스는 데이터(속성)와 기능(메서드)을 함께 묶어서 표현하며, 이를 통해 프로그램의 복잡성을 줄이고 가독성과 재사용성을 높입니다.

 


2.1 __init__

 

클래스에 대해 자세히 설명하기 전에 __init__에 대해 알아보도록 하겠습니다. __init__은 파이썬에서 특별한 메소드로, 클래스의 인스턴스가 생성될 때 자동으로 호출되는 초기화 메소드입니다. 이 메소드는 주로 클래스의 속성을 초기화하는데 사용되며, 객체가 생성되고 나서 바로 실행되어야 하는 코드를 포함합니다.

 

구조는 아래 코드와 같습니다. 여기서 'self'는 인스턴스 자신을 참조하는 변수입니다. 파이썬에서는 인스턴스 메소드의 첫 번째 인자로 항상 'self'를 사용합니다. 그리고 '인자'들은 객체를 생성할 때 전달해야 하는 인자들입니다.

 

class 클래스명:
    def __init__(self, 인자1, 인자2, ...):
        # 초기화 코드

 


2.2 클래스 정의하기

 

클래스를 정의하기 위해서는 class 키워드를 사용합니다. 클래스 이름은 대문자로 시작하는 것이 관례입니다. 위에서 언급한 동물 클래스를 만들어 보도록 하겠습니다.

 

예에서 동물 클래스의 속성에는 종(species), 나이(age), 이름(name) 등이 있을 수 있고, 행위(메소드)에는 먹다(eat), 움직이다(move), 소리내다(make_sound) 등이 있을 수 있다고 했습니다. 이를 바탕으로 'Animal' 클래스를 정의하면 아래 코드와 같이 됩니다.

 

__init__ 메소드는 이 클래스의 초기화 메소드로, 인스턴스가 생성될 때 자동으로 호출되며 종, 나이, 이름 세가지 인자를 받아 속성을 초기화 합니다.(self.species = species, self.age = age, self.name = name) 초기화된 속성은 클래스의 인스턴스에 저장되며, 인스턴스가 생성된 후에도 사용할 수 있습니다. eat, move, make_sound는 동물의 행위를 나타내는 메소드로 메소드가 호출되면 해당된 메시지가 출력됩니다.

 

class Animal:
    def __init__(self, species, age, name):
        self.species = species
        self.age = age
        self.name = name
        
    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    def make_sound(self):
        print(f"{self.name}이(가) 소리를 냅니다.")

 


2.3 객체

 

객체란 프로그램에서 사용되는 실체입니다.  객체는 클래스(class)에 의해 정의됩니다. 클래스를 이용하여 객체를 생성하면, 각 객체는 고유한 상태와 행동을 가지게 됩니다.

 


2.4 객체 생성하기

 

클래스를 이용하여 객체를 생성하려면 클래스 이름에 괄호를 붙이면 됩니다. 예를 들어, 위에서 정의한 Animal클래스로 객체를 생성하는 방법은 아래 코드와 같습니다. 아래 코드에서는 Animal 클래스를 이용하여 dog와 cat 객체를 생성했습니다. dog와 cat 객체는 서로 다른 속성 값을 가지고 있으며 (종, 나이, 이름), 독립적으로 사용할 수 있습니다. 

 

dog = Animal("개", 3, "멍멍이")
cat = Animal("고양이", 2, "야옹이")

 


2.5 객체 속성과 메서드

 

객체는 클래스에서 정의한 속성과 메서드를 가집니다. 위에서 정의한 Animal 클래스에서 종과 나이 그리고 이름이 객체의 속성이며, eat, move, make_sound는 객체의 메소드입니다. 객체의 속성과 메소드에 접근하려면 점(.) 연산자를 사용합니다. 예를 들어, dog 객체의 속성들을 출력하려면 아래 코드와 같이 사용하면 됩니다.

 

print(dog.species)  # 출력: 개
print(dog.age)      # 출력: 3
print(dog.name)     # 출력: 멍멍이

 

아래 코드에서 dog와 cat 객체의 메소드를 호출하여 각 동물의 행동을 출력하는 코드입니다. 객체의 메소드는 해당 클래스에 정의된 메소드를 사용하며, 객체 간에 독립적으로 동작됩니다.

 

dog.eat()
dog.move()
dog.make_sound()

cat.eat()
cat.move()
cat.make_sound()

 


3. 클래스 상속


클래스 상속은 한 클래스가 다른 클래스의 속성과 메소드를 물려받아 사용하는 것을 의미합니다. 상속을 통해 코드를 재사용하고 중복을 줄일 수 있으며, 계층적인 클래스 구조를 만들 수 있습니다.

 

위에서 작성한 Animal 클래스를 기반으로 상속을 설명해보겠습니다. 먼저 Animal 클래스를 상속받는 Dog클래스와 Cat클래스를 만들어 보겠습니다. 여기서 Dog와 Cat 클래스는 Animal 클래스를 상속받았습니다. 상속은 클래스 정의 시 괄호안에 부모 클래스를 명시함으로써 구현할 수 있습니다. 이렇게 상속받은 클래스는 부모 클래스의 속성과 메소드를 사용할 수 있습니다. Dog 클래스와 Cat클래스는 각각 Bark와 meow라는 메소드를 추가로 정의했습니다. 이렇게 상속을 통해 기존 클래스의 기능을 확장하거나 변경할 수 있습니다.

 

class Dog(Animal):
    def bark(self):
        print(f"{self.name}이(가) 멍멍 짖습니다.")

class Cat(Animal):
    def meow(self):
        print(f"{self.name}이(가) 야옹 소리를 냅니다.")

 

아래 코드에서 Dog와 Cat 클래스의 객체를 생성하고, 각각의 메소드를 호출해 보았습니다. 이때 Dog와 Cat 인스턴스는 부모 클래스인 Animal의 메소드인 eat와 move를 사용할 수 있음을 확인할 수 있습니다. 또한 각 클래스에 추가로 정의한 bark와 meow 메소드도 사용할 수 있습니다.


dog = Dog("개", 3, "멍멍이")
cat = Cat("고양이", 2, "야옹이")

dog.eat()
dog.move()
dog.bark()

cat.eat()
cat.move()
cat.meow()

 



4. 캡슐화(Encapsulation)

 

캡슐화는 객체 지향 프로그래밍에서 중요한 개념으로, 객체의 속성과 메소드를 하나의 캡슐처럼 묶어서 관리하는 것을 의미합니다. 이를 통해 객체 내부의 구현 상세를 외부로부터 숨기고, 외부에서는 객체의 속성과 메소드에 접근하는 인터페이스만 제공함으로써 코드의 안정성을 높이고 유지 보수를 용이하게 합니다.

 

클래스의 멤버(속성과 메소드)는 접근 제어자(Access Modifier)를 통해 캡슐화를 구현할 수 있습니다. 접근 제어자에는 주로 public, private 등이 있으며, 이를 통해 클래스 멤버의 접근 가능 범위를 제한할 수 있습니다. public 멤버는 어떤 클래스에서든 접근이 가능한 멤버입니다. 일반적으로 클래스의 인터페이스를 제공하는 메소드와 속성에 대해 사용됩니다. private 멤버는 오직 해당 클래스 내부에서만 접근이 가능한 멤버입니다. 클래스 외부에서는 접근할 수 없으며, 클래스 내부에서만 사용되는 메소드와 속성에 대해 사용됩니다. 클래스의 내부 구현을 외부로부터 숨기기 위해 사용됩니다. private 멤버로 설정하는 방법은 간단합니다. 앞에 ' __ '를 붙여주면됩니다.

 

아래 코드는 접근 제어자를 사용하여 멤버를 캡슐화한 코드입니다. 코드에서 public_attribute와 public_method는 public 멤버로, 어떤 클래스에서든 접근이 가능합니다. 반면, __private_attribute와 __private_method는 private 멤버로, 오직 MyClass 내부에서만 접근이 가능합니다.

class MyClass:
    def __init__(self):
        self.public_attribute = "public 속성"
        self.__private_attribute = "private 속성"

    def public_method(self):
        print("public 메소드")

    def __private_method(self):
        print("private 메소드")

    def access_private_members(self):
        self.__private_method()
        print(self.__private_attribute)

 


5. 다형성(Polymorphism)

 

다형성은 같은 이름의 메소드나 연산자를 사용하면서도 다양한 동작이 이루어지도록 하는 것을 말합니다. 다형성을 통해 코드를 보다 유연하고 확장하기 쉽게 만들 수 있습니다.

 


5.1 메서드 오버라이딩과 오버로딩

 

메서드의 오버로딩(overloading)과 오버라이딩(overriding)은 객체지향 프로그래밍에서 중요한 개념입니다. 오버로딩은 같은 이름의 메소드나 연산자를 여러개 정의하고, 이들이 다른 매개변수의 개수, 타입 또는 순서를 가지도록 하는 것입니다. 오버로딩을 통해 메소드나 연산자의 기능을 다양한 상황에 맞게 확장할 수 있습니다. 오버라이딩은 상속을 통해 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의하는 것입니다. 오버라이딩을 통해 부모 클래스의 메소드를 자식 클래스의 요구 사항에 맞게 수정할 수 있습니다.

 

아래  코드에서 Dog와 Cat 클래스는 부모 클래스인 Animal로 부터 make_sound 메서드를 상속 받아 각자의 소리를 낼 수 있도록 오버라이딩 하였습니다. 또한 Dog 클래스에서는 play메서드를 오버로딩하여 인자의 타입에 따라 다른 동작을 하도록 구현하였습니다. 이를 통해 다형성을 구현할 수 있습니다. 아래에서 isinstance() 함수는 파이썬에서 객체의 타입을 확인하는 내장 함수입니다. 이 함수는 객체와 클래스를 인자로 받아서 객체가 해당 클래스의 인스턴스인지를 검사하여 True나 False를 반환합니다.

 

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    def make_sound(self):
        print(f"{self.name}이(가) 소리를 냅니다.")

class Dog(Animal):
    # 오버라이딩 예시
    def make_sound(self):
        print(f"{self.name}이(가) 멍멍 소리를 냅니다.")

    # 오버로딩 예시
    def play(self, toy):
        if isinstance(toy, str):
            print(f"{self.name}이(가) {toy}로 놀고 있습니다.")
        else:
            print(f"{self.name}이(가) 놀고 있습니다.")

class Cat(Animal):
    # 오버라이딩 예시
    def make_sound(self):
        print(f"{self.name}이(가) 야옹 소리를 냅니다.")

dog = Dog("멍멍이", 3)
cat = Cat("야옹이", 2)

dog.eat()
dog.move()
dog.make_sound()  # 오버라이딩 된 메소드 호출
dog.play("뽀로로 인형")  # 오버로딩 된 메소드 호출 (문자열 인자 사용)
dog.play(123)  # 오버로딩 된 메소드 호출 (정수 인자 사용)

cat.eat()
cat.move()
cat.make_sound()  # 오버라이딩 된 메소드 호출

 


5.2 추상 클래스와 추상 메서드

 

추상 클래스는 추상 메서드를 가지고 있는 클래스입니다. 추상 메서드는 메서드의 선언만 있고 구현이 없는 메서드입니다. 추상 클래스를 상속받은 클래스는 반드시 추상 메서드를 구현해야 합니다. 파이썬에서 추상 클래스를 정의하는 방법은 abc 모듈을 이용하는 것입니다. 

 

아래 코드에서 Animal 클래스는 추상 클래스로 정의되어 있으며 make_sound 메서드는 추상 메서드로 선언되어 있습니다. 이렇게 추상 메서드로 선언된 make_sound 메서드는 자식 클래스인 dog와 cat에서 오버라이딩되어 각 동물이 낼 수 있는 소리에 맞게 구현되었습니다.

 

from abc import ABC, abstractmethod

class Animal(ABC):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    @abstractmethod
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        print(f"{self.name}이(가) 멍멍 소리를 냅니다.")

class Cat(Animal):
    def make_sound(self):
        print(f"{self.name}이(가) 야옹 소리를 냅니다.")

dog = Dog("멍멍이", 3)
cat = Cat("야옹이", 2)

dog.eat()
dog.move()
dog.make_sound()

cat.eat()
cat.move()
cat.make_sound()

 

 


6.  클래스 변수와 인스턴스 변수

 

클래스 변수는 해당 클래스로 생성된 모든 인스턴스가 공유하는 변수입니다. 클래스 변수는 클래스 정의 내부에서 선언되며, 클래스 이름으로 접근할 수 있습니다. 반면에 인스턴스 변수는 각 인스턴스에 속하는 변수로, 인스턴스 메서드 내부에서 self를 사용하여 접근할 수 있습니다.

 

클래스 변수는 모든 인스턴스가 공통적으로 사용하는 값을 저장하며, 인스턴스 변수는 각 인스턴스의 고유한 상태를 저장하는 데 사용됩니다. 클래스 변수의 값을 변경하면 해당 클래스로 생성된 모든 인스턴스에서 변경된 값을 참조할 수 있습니다. 하지만 인스턴스 변수는 각 인스턴스의 상태에 대해 독립적으로 값을 가지며, 한 인스턴스의 인스턴스 변수를 변경하더라도 다른 인스턴스의 인스턴스 변수에는 영향을 미치지 않습니다.

 

코드에서 species_count는 클래스 변수이며, __init__ 메서드에서 인스턴스가 생성될 때마다 클래스 변수가 1씩 증가합니다. species, age, name은 각각 인스턴스 변수이며, 인스턴스마다 다른 값을 가집니다. 예시에서는 dog와 cat 인스턴스를 생성하고, 인스턴스 변수에 접근하여 각각의 정보를 출력합니다. 마지막으로 Animal.species_count를 통해 클래스 변수에 접근하여 동물의 종류 수를 출력합니다.

 

class Animal:
    # 클래스 변수
    species_count = 0
    
    def __init__(self, species, age, name):
        self.species = species  # 인스턴스 변수
        self.age = age  # 인스턴스 변수
        self.name = name  # 인스턴스 변수
        Animal.species_count += 1  # 클래스 변수 증가
        
    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    def make_sound(self):
        print(f"{self.name}이(가) 소리를 냅니다.")


# Animal 클래스의 인스턴스 생성
dog = Animal("개", 3, "멍멍이")
cat = Animal("고양이", 2, "야옹이")

# 인스턴스 변수에 접근
print(f"{dog.name}은(는) {dog.age}살이고, {dog.species}입니다.")
print(f"{cat.name}은(는) {cat.age}살이고, {cat.species}입니다.")

# 클래스 변수에 접근
print(f"동물의 종류 수는 총 {Animal.species_count}개입니다.")

 


7. 네임스페이스


네임스페이스는 변수가 정의되는 범위를 말합니다. 파이썬에서는 각각의 변수가 정의되는 위치에 따라 네임스페이스가 결정됩니다. 위의 강아지와 고양이 예시에서 각각의 인스턴스가 가지는 인스턴스 변수(species, age, name)는 해당 인스턴스의 네임스페이스에 저장됩니다. 이렇게 인스턴스 변수는 해당 인스턴스의 네임스페이스 내에서만 접근할 수 있습니다. 또한, 클래스 변수(species_count)는 해당 클래스의 네임스페이스에 저장됩니다. 이렇게 클래스 변수는 클래스의 네임스페이스 내에서 접근할 수 있습니다.

 

아래 코드에서 dog와 cat 인스턴스를 생성하고, 각각의 네임스페이스에 있는 변수를 출력합니다. dog와 cat 인스턴스는 species, age, name 변수를 각각 가지고 있습니다. 이 변수들은 각 인스턴스의 네임스페이스에 저장되어 있으며, __dict__를 통해 접근할 수 있습니다. 마지막으로 Animal 클래스의 네임스페이스에 있는 변수인 species_count를 출력합니다.

 

_dict__는 파이썬에서 객체가 가지고 있는 속성들을 담고 있는 딕셔너리(dictionary)입니다. 객체의 속성으로는 클래스 변수, 인스턴스 변수, 메서드 등이 있습니다. __dict__를 사용하면 해당 객체가 가지고 있는 속성을 딕셔너리 형태로 반환받을 수 있습니다. 딕셔너리의 각 항목은 속성의 이름과 값으로 구성됩니다.

 

class Animal:
    # 클래스 변수
    species_count = 0
    
    def __init__(self, species, age, name):
        self.species = species  # 인스턴스 변수
        self.age = age  # 인스턴스 변수
        self.name = name  # 인스턴스 변수
        Animal.species_count += 1  # 클래스 변수 증가
        
    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    def make_sound(self):
        print(f"{self.name}이(가) 소리를 냅니다.")


# Animal 클래스의 인스턴스 생성
dog = Animal("개", 3, "멍멍이")
cat = Animal("고양이", 2, "야옹이")

# 각 인스턴스의 네임스페이스에 있는 변수 출력
print(dog.__dict__)
print(cat.__dict__)

# 클래스의 네임스페이스에 있는 변수 출력
print(Animal.__dict__)

 


8. 인스턴스 생성자와 소멸자

 

인스턴스 생성자와 소멸자는 파이썬 클래스에서 객체의 생성과 소멸과 관련된 메서드입니다. 인스턴스 생성자는 객체가 생성될 때 호출되며, 객체를 초기화하는 데 사용됩니다. 생성자는 클래스 내에 __init__이라는 이름의 특수 메서드로 정의됩니다. 소멸자는 객체가 소멸될 때 호출되며, 객체가 사용한 자원을 해제하는 데 사용됩니다. 소멸자는 클래스 내에 __del__이라는 이름의 특수 메서드로 정의됩니다. 

아래 코드는 강아지와 고양이 예시에서 생성자와 소멸자를 사용하는 방법입니다. 코드에서 Animal 클래스의 생성자 __init__ 메서드에서는 객체의 species, age, name을 초기화합니다. 소멸자 __del__ 메서드에서는 객체가 소멸될 때 출력되는 메시지를 작성합니다.

class Person:
    def __init__(self, name):
        self.name = name
        print(f"{self.name} 객체가 생성되었습니다.")

    def __del__(self):
        print(f"{self.name} 객체가 삭제되었습니다.")




9. 정적 메서드와 클래스 메서드



정적 메서드는 클래스와 관련이 있는 메서드이지만, 클래스나 인스턴스와는 별개로 독립적으로 사용될 수 있는 메서드입니다. 정적 메서드는 클래스 내부에 @staticmethod 데코레이터를 사용하여 정의됩니다. 클래스 메서드는 클래스와 관련이 있는 메서드이며, 클래스 자체를 첫 번째 인자로 받습니다. 클래스 메서드는 클래스 내부에 @classmethod 데코레이터를 사용하여 정의됩니다.

아래 코드는 강아지와 고양이 예시에서 정적 메서드와 클래스 메서드를 사용하는 방법입니다. 코드에서 description 메서드는 정적 메서드이며, species 메서드는 클래스 메서드입니다. 각각의 데코레이터(@staticmethod, @classmethod)를 이용하여 메서드를 정의합니다. 정적 메서드는 Animal.description()와 같이 클래스를 이용하여 직접 호출할 수 있습니다. 클래스 메서드는 Animal.species()와 같이 클래스를 이용하여 호출할 수 있습니다.

 

class Animal:
    # 클래스 변수
    species_count = 0
    
    def __init__(self, species, age, name):
        self.species = species  # 인스턴스 변수
        self.age = age  # 인스턴스 변수
        self.name = name  # 인스턴스 변수
        Animal.species_count += 1  # 클래스 변수 증가
        
    def eat(self):
        print(f"{self.name}이(가) 먹이를 먹습니다.")

    def move(self):
        print(f"{self.name}이(가) 움직입니다.")

    def make_sound(self):
        print(f"{self.name}이(가) 소리를 냅니다.")
        
    @staticmethod
    def description():
        print("동물 클래스입니다.")
        
    @classmethod
    def species(cls):
        print(f"동물의 종류는 총 {cls.species_count}개입니다.")
        

# Animal 클래스의 인스턴스 생성
dog = Animal("개", 3, "멍멍이")
cat = Animal("고양이", 2, "야옹이")

# 정적 메서드 호출
Animal.description()

# 클래스 메서드 호출
Animal.species()

 


10. 특수 메서드

 

파이썬 클래스는 특수 메서드(special method)를 포함할 수 있습니다. 특수 메서드는 클래스 내부에서 특별한 이름을 가진 메서드로, 객체의 생성, 연산자 오버로딩 등을 지원합니다. 특수 메서드는 메서드 이름 앞뒤로 언더스코어(__)가 붙어 있습니다. 아래는 파이썬 클래스에서 자주 사용되는 특수 메서드의 목록입니다.

 

메서드 설명
__init__(self, ...) 객체 초기화 메서드
__str__(self) 객체의 문자열 표현을 반환하는 메서드
__repr__(self) 객체의 "공식" 문자열 표현을 반환하는 메서드
__eq__(self, other) 객체의 동등성 비교를 위한 메서드
__lt__(self, other) 객체의 작음을 비교하기 위한 메서드
__gt__(self, other) 객체의 큼을 비교하기 위한 메서드
__len__(self) 객체의 길이를 반환하는 메서드
__getitem__(self, key) 객체에서 인덱스나 키를 사용하여 요소를 가져오는 메서드
__setitem__(self, key, value) 객체에서 인덱스나 키를 사용하여 요소를 설정하는 메서드
__delitem__(self, key) 객체에서 인덱스나 키를 사용하여 요소를 삭제하는 메서드