4.11 Class

객체 지향 프로그래밍(Object Oriented Programming) 또는 OOP는 속성 및 동작이 개별 객체에 고정적으로 포함되도록 프로그램을 구성하는 수단을 제공하는 프로그래밍 패러다임입니다.

예를 들어, 사람이라는 객체는 이름, 나이, 주소 등을의 속성을 가지고 있으며 걷고, 말하고, 호흡하고, 달리기와 같은 행동으로 표현 할 수 있습니다. 또 전자메일은 받는 사람 목록, 제목, 본문 등과 같은 속성 과 첨부 파일 추가 및 보내기와 같은 동작을 포함한 객체입니다.

다른 말로 하자면, 객체 지향 프로그래밍은 회사와 직원, 학생과 교사 등의 관계뿐만 아니라 자동차와 같은 실제의 물건을 모델링하는 접근법입니다. OOP는 객체를 소프트웨어 객체로 모델링합니다. 어떤 데이터는 그들과 연관되어 특정 기능을 수행 할 수 있습니다.

핵심은 개체가 절차 형 프로그래밍 에서처럼 데이터를 표현할뿐만 아니라 프로그램의 전체 구조에서도 객체 지향 프로그래밍 패러다임의 중심에 있다는 것입니다.

클래스란 객체의 설계도(blueprint)를 코드로 나타낸 것을 의미합니다. 다시 말해, 객체를 프로그램적으로 만들기 위한 설계 코드란 의미입니다. 객체를 클래스로 나타낼 때, 추상화라는 과정을 거칩니다. 추상화란 말 그대로 추상적이게, 단순하게 나타내는 것을 의미합니다. 그렇게 객체를 단순화시켜 필요한 정보와 행위를 모은 것을 클래스라고 합니다.

객체는 데이터에 대한 파이썬의 추상화입니다. 파이썬 프로그램의 모든 데이터는 객체 또는 객체 간의 관계로 표현됩니다. 모든 객체에는 ID(Identity), 유형(Type) 및 값(Value)이 있습니다.

클래스에 의해서 만들어진 객체를 인스턴스라고도 합니다. 클래스를 만들었다고 해서, 우리가 실제로 사용할 수 있는 것은 아닙니다. 클래스라는 것은 단지 객체가 가질 수 있는 상태 정보와 행동들에 대한 정의이기 때문입니다. 클래스를 실제로 나타나게 하는 것을, 다시 말해서 클래스에 대한 변수를 선언하는 것을 “인스턴스를 생성한다”라 하고, 이렇게 생성된 변수를 인스턴스라 하며, 이 인스턴스는 메모리 공간을 차지하게 됩니다. 그리고, 인스턴스의 메소드를 이용하여 클래스의 속성을 설정 및 변경할 수 있습니다.

Define a Class

파이썬에서 클래스의 정의는 간단 합니다.

class Dog:
    pass

클래스를 정의하려면 class 키워드와 클래스의 이름을 사용하면 됩니다. 또한 여기에서는 Python 키워드 pass를 사용했습니다. 이것은 코드가 결국 진행할 place holder로 자주 사용됩니다. 이 코드를 사용하면 오류가 발생하지 않고 실행할 수 있습니다.

Instance Attributes

모든 클래스는 객체를 만들고 모든 객체는 속성(attribute)이라는 특징을 포함합니다. 객체의 초기 속성을 기본값으로 지정하는 init () 메서드를 사용하여 초기화 합니다. 이 메소드에는 객체 자체 (예 : Dog)를 참조하는 self 변수뿐만 아니라 하나 이상의 인수가 있어야합니다.

class Dog:

    # Initializer / Instance Attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age

Dog() 클래스의 경우 각 개(dog)마다 특정 이름과 나이가 있습니다. 실제로 개를 만들 때 알아 두어야 할 중요한 사항입니다. 이 클래스는 실제로 개를 정의하기위한 것으로, 특정 이름과 나이를 가진 개별 개 인스턴스를 생성하지 않습니다.

마찬가지로, self 변수는 클래스의 인스턴스이기도합니다. 클래스의 인스턴스는 값이 다양하기 때문에 self.name = name 대신 Dog.name = name으로 지정할 수도 있습니다. 그러나 모든 개가 동일한 이름을 사용하지 않기 때문에 우리는 다른 인스턴스에 다른 값을 할당 할 수 있어야합니다. 따라서 각 클래스의 개별 인스턴스를 추적하는 데 도움이되는 유일한 특별한 self 변수가 필요합니다.

Class Attributes

인스턴스 속성은 각 객체에 고유하게 지정되지만 클래스 속성은 모든 인스턴스에 대해 동일합니다. 다음 코드를 보면 개마다 고유한 이름과 나이가 있지만 모든 개는 포유류입니다.

class Dog:

    # Class Attribute
    species = '포유류'

    # Initializer / Instance Attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age

Instantiating Objects

인스턴스 생성이란 새로운 고유한 클래스 인스턴스를 만드는 용어입니다.

python
>>> class Dog:
...     pass
...
>>> Dog()
<__main__.Dog object at 0x1004ccc50>
>>> Dog()
<__main__.Dog object at 0x1004ccc90>
>>> a = Dog()
>>> b = Dog()
>>> a == b
False

위의 코드를 보면 새로운 Dog() 클래스를 정의한 다음 두 개의 새로운 개를 만들고 각각 다른 객체에 할당했습니다. 따라서 클래스의 인스턴스를 만들려면 클래스 이름을 사용하고 그 뒤에 괄호를 사용합니다. 그런 다음 각 인스턴스가 실제로 다르다는 것을 입증하기 위해 두 개의 개를 인스턴스화하고 각 인스턴스에 변수를 할당 한 다음 해당 변수가 동일한 지 테스트했습니다.

클래스 인스턴스의 유형(type)이 무엇으로 나오는지 확인해 보겠습니다.

>>> class Dog:
...     pass
...
>>> a = Dog()
>>> type(a)
<class '__main__.Dog'>

조금 복잡한 예를 들어 보겠습니다.

class Dog:

    # Class Attribute
    species = '포유류'

    # Initializer / Instance Attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age


# Instantiate the Dog object
philo = Dog("두부", 5)
mikey = Dog("뭉치", 6)

# Access the instance attributes
print("{} is {} and {} is {}.".format(
    philo.name, philo.age, mikey.name, mikey.age))

# Is Philo a mammal?
if philo.species == "mammal":
    print("{0} is a {1}!".format(philo.name, philo.species))

위의 코드를 실행하면 다음과 같은 결과가 출력 됩니다.

두부 is 5 and 뭉치 is 6.

Dog() 클래스의 새 인스턴스를 만들어 변수 "philo"에 할당했습니다. 우리는 그 다음에 개명과 나이를 나타내는 "두부"와 5 살이라는 인자를 각각 전달했습니다.

이러한 속성은 init 메쏘드로 전달됩니다. init 메쏘드는 새로운 인스턴스를 생성 할 때마다 호출되며, 객체에 이름과 나이를 붙입니다. 클래스의 새 인스턴스를 만들면 Python은 자동으로 자체 정의 (이 경우 Dog)를 결정하고이를 init 메소드에 전달합니다.

Instance Methods

인스턴스 메소드는 클래스 내부에서 정의되며 인스턴스의 내용을 가져 오는 데 사용됩니다. 또한 객체의 속성을 사용하여 작업을 수행하는 데에도 사용할 수 있습니다. init 메쏘드와 마찬가지로, 첫번째 인자는 항상 self입니다.

class Dog:

    # Class Attribute
    species = 'mammal'

    # Initializer / Instance Attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # instance method
    def description(self):
        return "{} is {} years old".format(self.name, self.age)

    # instance method
    def speak(self, sound):
        return "{} says {}".format(self.name, sound)

# Instantiate the Dog object
mikey = Dog("뭉치", 6)

# call our instance methods
print(mikey.description())
print(mikey.speak("멍  멍"))
뭉치 is 6 years old
뭉치 says 멍  멍

메서드 speak ()에서는 행동을 정의합니다.

Object Inheritance

상속(inheritance)이란 한 클래스가 다른 클래스의 속성 및 메소드를 사용하는 프로세스입니다. 새로 형성된 클래스를 하위 클래스라고하며 하위 클래스가 파생 된 클래스를 상위 클래스라고합니다.

하위 클래스는 상위 클래스의 기능 (예 : 속성 및 동작)을 재정의하거나 확장한다는 점에 유의해야합니다. 즉, 하위 클래스는 부모의 모든 특성과 동작을 상속하지만 다른 동작을 지정하여 수행 할 수도 있습니다. 가장 기본적인 유형의 클래스는 객체입니다. 일반적으로 다른 모든 클래스는 부모로부터 상속됩니다.

새로운 클래스 인 Python 3을 정의하면이 클래스는 암묵적으로 객체를 부모 클래스로 사용합니다. 따라서 다음의 두 정의는 동일합니다.

class Dog(object):
    pass

# In Python 3, this is the same as:
class Dog:
    pass

Dog 객체가 여러 개 있다고 가정합니다. 각 Dog 객체는 이름과 나이가 다르고 하는 행동들도 다르다고 가정 합니다. 한 개와 다른 개를 구별하는 방법이 어던것이 있을 까요?

# Parent class
class Dog:

    # Class attribute
    species = '포유류'

    # Initializer / Instance attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # instance method
    def description(self):
        return "{} is {} years old".format(self.name, self.age)

    # instance method
    def speak(self, sound):
        return "{} says {}".format(self.name, sound)


# Child class (inherits from Dog class)
class Maltise(Dog):
    def run(self, speed):
        return "{} runs {}".format(self.name, speed)


# Child class (inherits from Dog class)
class Bulldog(Dog):
    def run(self, speed):
        return "{} runs {}".format(self.name, speed)
        
# Child classes inherit attributes and behaviors from the parent class
jim = Bulldog("뭉치", 12)
print(jim.description())

# Child classes have specific attributes and behaviors as well
print(jim.run("천천히"))
뭉치 is 12 years old
뭉치 runs 천천히

말티즈와 불독을 구별 할 수있는 특별한 속성이나 메소드는 추가하지 않았지만 이제는 서로 다른 클래스이므로 각각의 속도를 정의하는 클래스 속성을 서로 다르게 지정할 수 있습니다.

# Parent class
class Dog:

    # Class attribute
    species = 'mammal'

    # Initializer / Instance attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # instance method
    def description(self):
        return "{} is {} years old".format(self.name, self.age)

    # instance method
    def speak(self, sound):
        return "{} says {}".format(self.name, sound)


# Child class (inherits from Dog() class)
class Maltise(Dog):
    def run(self, speed):
        return "{} runs {}".format(self.name, speed)


# Child class (inherits from Dog() class)
class Bulldog(Dog):
    def run(self, speed):
        return "{} runs {}".format(self.name, speed)


# Child classes inherit attributes and behaviors from the parent class
jim = Bulldog("Jim", 12)
print(jim.description())

# Child classes have specific attributes and behaviors as well
print(jim.run("slowly"))

# Is jim an instance of Dog()?
print(isinstance(jim, Dog))

# Is julie an instance of Dog()?
julie = Dog("Julie", 100)
print(isinstance(julie, Dog))

# Is johnny walker an instance of Bulldog()
johnnywalker = Maltise("Johnny Walker", 4)
print(isinstance(johnnywalker, Bulldog))

# Is julie and instance of jim?
print(isinstance(julie, jim))
C:\Users\Nainsys\Anaconda3\envs\onebook\python.exe C:/Users/Nainsys/PycharmProjects/OneBook/JustTest.py
Jim is 12 years old
Traceback (most recent call last):
Jim runs slowly
  File "C:/Users/Nainsys/PycharmProjects/OneBook/JustTest.py", line 52, in <module>
True
    print(isinstance(julie, jim))
True
False
TypeError: isinstance() arg 2 must be a type or tuple of types

이해가 되십니까? johnnywalker는 Bulldog () 클래스의 인스턴스가 아니지만 jim과 julie는 모두 Dog () 클래스의 인스턴스입니다. 그런 다음 julie가 jim의 인스턴스인지 테스트합니다. Jim은 클래스 자체가 아닌 클래스의 인스턴스이므로 불가능합니다. 따라서 TypeError가 발생합니다.

Overriding

하위 클래스는 상위 클래스의 특성 및 동작을 재정의 할 수 있습니다. 오버라이딩(Overriding)이란 : 상위 클래스가 가지고 있는 메소드를 하위 클래스가 재정의 해서 사용하는 것을 말합니다.

# 부모 클래스
class Pets:
    dogs = []

    def __init__(self, dogs):
        self.dogs = dogs


# 부모 클래스
class Dog:

    # 클래스 속성
    species = 'mammal'

    # Initializer / Instance attributes
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.is_hungry = True

    # Instance method
    def description(self):
        return self.name, self.age

    # Instance method
    def speak(self, sound):
        return "%s says %s" % (self.name, sound)

    # Instance method
    def eat(self):
        self.is_hungry = False


# Dog class로 부터 상속 받은 자식 클래스
class RussellTerrier(Dog):
    def run(self, speed):
        return "%s runs %s" % (self.name, speed)


#  Dog class로 부터 상속 받은 자식 클래스
class Bulldog(Dog):
    def run(self, speed):
        return "%s runs %s" % (self.name, speed)

# Create instances of dogs
my_dogs = [
    Bulldog("Tom", 6),
    RussellTerrier("Fletcher", 7),
    Dog("Larry", 9)
]

# Instantiate the Pets class
my_pets = Pets(my_dogs)

# Output
print("I have {} dogs.".format(len(my_pets.dogs)))
for dog in my_pets.dogs:
    dog.eat()
    print("{} is {}.".format(dog.name, dog.age))

print("And they're all {}s, of course.".format(dog.species))

are_my_dogs_hungry = False
for dog in my_pets.dogs:
    if dog.is_hungry:
        are_my_dogs_hungry = True

if are_my_dogs_hungry:
    print("My dogs are hungry.")
else:
    print("My dogs are not hungry.")
I have 3 dogs.
Tom is 6.
Fletcher is 7.
Larry is 9.
And they're all mammals, of course.
My dogs are not hungry.

Last updated