Object-Oriented Programming - Classes

Contents

  • Classes
    • Methods
    • Attributes

Classes

‘Know Yourself.’ - Socrates

전공수업으로 객체지향을 들었었지만, 당시엔 왜 배우는지도 모르고 정확히 어떻게 동작하는지 신경도 안쓰며 무작정 외우기만 해서 남는게 거의 없다. 하지만 파이토치와 배포되어 있는 end to end 라이브러리들을 효과적으로 사용하기 위해 객체지향이 필수이기 때문에, 당시에 이해하지 못하고 넘어간 것들 위주로 다시 공부를 했다.

파이썬에서의 객체지향적 프로그래밍은 class 만 완벽히 이해하면 다른 프레임워크들을 다루는데 크게 문제가 없다. Class 란 객체의 청사진 역할을 하며, boilerplate 코드를 짤 필요 없이 객체들을 생성하고 다룰 수 있게 해주는 파이썬의 builtin OOP object 다.

class Student:

    def __init__(self, first, last, health):
        self.first = first
        self.last = last
        self.health = health
        self.email = first + '.' + last + '@korea.ac.kr'

    def fullname(self):
        return f'{self.first} {self.last}'

stu_1 = Student('Tom', 'Lee', 100)
stu_2 = Student('Ian', 'Goodfellow', 100)

>>> print(stu_1.email)
Tom.Lee@korea.ac.kr
>>> print(stu_1.fullname())
Tom Lee

class Student 로 학생이란 클래스를 정의한다. 해당 클래스로 객체를 만들면 이를 인스턴스 라고 하고, 위 코드 예시에서 두개의 인스턴스 stu_1, stu_2 를 만든다. 클래스 안에서 사용하는 객체들은 일반적인 terminology 가 다른데, 클래스 내부의 함수는 method, 클래스 내부의 변수는 attribute 라고 한다.

클래스를 처음 접할때 가장 헷갈리는 것은 단연코 self 인자다. 인스턴스 stu_1 를 만들 때 3개의 인자 Tom, Lee, 100 을 받지만 인스턴스를 생성할때 사용되는 def __init__() 함수엔 4개의 인자 self, first, last, health 를 받는다. 이때 self 인자는 생성되는 인스턴스 자체 를 의미한다. 즉, Student 라는 클래스를 통해 stu_1 이라는 인스턴스를 만들 때, stu_1 이 곧 인스턴스와 클래스의 첫번째 인자가 되는 것이다.

stu_1 = Student('Tom', 'Lee', 100)

def __init__(self, first, last, health):
  stu_1.first = 'Tom'
  stu_1.last = 'Lee'
  stu_1.health = 100

위 코드를 보면 이해가 쉽다. self 는 생성되는 인스턴스 자체를 의미하기 때문에 stu_1.first 의 리턴값이 Tom 이 되는 것이다. 이 def __init__(self) 라는 메서드 (클래스 내부의 함수) 는 인스턴스를 생성할 때 가장 처음 invoke 되는 메서드이고, 이렇게 특별한 작업을 수행하는 __x__ 형식의 메서드는 ‘매직 메서드’, 혹은 ‘dunder method’ 라고도 불린다.

Methods

def fullname(self):
  return f'{self.first} {self.last}'

>>> print(stu_1.fullname())
Tom Lee

클래스 내부의 함수는 메서드 라고 부른다. 위 코드는 stu_1 인스턴스의 fullname 을 출력해주는 메서드이며, 메서드도 self 를 인자로 받는다. 처음 보면 유독 헷갈리지만, 다음 코드를 보면 이해가 쉽다.

def fullname(self):
  return f'{self.first} {self.last}'

>>> print(Student.fullname(stu_1))
Tom Lee

두 코드는 완전히 동일하게 작동한다. stu_1.fullname()Student.fullname(stu_1) 은 같은 방식으로 작동한다. Student 클래스 내에 있는 fullname() 메서드는 self 를 인자로 받고, self 는 해당 클래스로 생성된 인스턴스를 의미한다. 그렇기에 fullname(self) 메서드의 인자로 self 를 받아야 하는 것이다. 이때 self.first, self.last 라는 리턴값을 보면 더 와닿는다. 해당 인스턴스를 인자로 받아야 그 인스턴스의 이름인 self.first 와 성인 self.last 를 access 하여 사용 할 수 있다.

Attributes

클래스 내부의 변수는 포괄적으로 Attribute 라고 불리지만, 해당 Attribute 가 어디에 정의되었느냐에 따라 Class variable 혹은 instance variable 라고도 부른다. 이상하게 Class attribute 라는 말은 들어본적이 없지만 instance variable, instance attribute 는 혼용되어 쓰인다.

메서드가 클래스 내부의 함수면, Attribute 는 클래스 내부의 변수다. 이때 Attribute 는 어디에 정의되었는냐에 따라 Class variable, 또는 instance variable 로 나뉜다. 예시를 보자.

class Student:

    reduce_health = 0.9

    def __init__(self, first, last, health):
        self.first = first
        self.last = last
        self.health = health
        self.email = first + '.' + last + '@korea.ac.kr'

    def allnighter(self):
        self.health = self.health * Student.reduce_health
        return self.health

stu_1 = Student('Tom', 'Lee', 100)
stu_2 = Student('Ian', 'Goodfellow', 100)

>>> print(stu_1.allnighter())
90.0

Instance variable 은 인스턴스에 할당되는 고유의 변수이다. stu_1 인스턴스의 instance variable firstTom 이고, stu_2 인스턴스의 instance variable firstIan 이다. 이처럼 instance variable 은 각 인스턴스를 생성할 때 각자 할당하는 반면, class variable 은 클래스 자체에 할당된 변수다. 위 예시에선 reduce_health 라는 class variable 을 정의했고, allnighter() 라는 메서드를 통해 사용된다.

이때 이 class variable 은 Student.reduce_health 로 사용할 수 있지만, self.reduce_health 로도 invoke 해서 사용할 수 있다. 이는 self, 즉 인스턴스가 해당 클래스를 통해 생성되었기 때문에 클래스의 class variable 또한 함께 정의되기 때문이다.

보통 instance variable 은 각 인스턴스 고유의 변수를 할당할때 쓰이며, class variable 은 클래스 전체에서 쓰일 변수를 할당할 때 쓰인다.