파이썬은 탄생 이후 줄곧 객체 지향 프로그래밍(Object-Oriented Programming) 언어로 설계되어 왔습니다. 클래스(Class)와 객체(Object)는 객체 지향 프로그래밍을 구성하는 두 가지 핵심 요소입니다.
클래스는 새로운 타입의 객체를 만들어내는 일종의 설계도이며, 그 클래스로부터 생성된 개별 객체를 '인스턴스(instance)'라고 부릅니다.
그럼 가장 간단한 형태의 클래스를 하나 만들어 보겠습니다.
파이썬에서 클래스 정의하기
먼저 아무 내용이 없는 빈 클래스를 정의해 보겠습니다.
#클래스 정의
class Vehicle():
pass # 빈 블록
# 객체 생성(인스턴스화)
v = Vehicle()
print(v)
실행 결과
<__main__.Vehicle object at 0x055DB9F0>
위 코드에서 한 일 살펴보기
먼저 class 문을 사용해 새로운 클래스 Vehicle을 선언했습니다. class 문 바로 아래에는 들여쓰기된 코드 블록이 위치하며, 이 블록이 클래스의 본문(body)을 구성합니다. 위 예제에서는 pass 문으로 표시된 빈 블록을 사용했습니다.
다음으로 Vehicle 클래스를 사용하기 위해, 클래스 이름 뒤에 괄호 한 쌍을 붙여 이 클래스의 객체(인스턴스)를 생성했습니다. 객체가 실제로 만들어졌는지 확인하기 위해 print() 함수로 출력한 결과, __main__ 모듈 안에 Vehicle 클래스의 인스턴스가 존재한다는 정보를 확인할 수 있습니다.
객체(v)는 클래스의 인스턴스입니다. 모든 특정 객체는 특정 클래스의 인스턴스이며, 하나의 클래스로부터 원하는 만큼 여러 개의 인스턴스를 생성할 수 있습니다. 각 인스턴스는 해당 클래스가 가진 메서드와 속성을 포함하게 됩니다.
또한 클래스 내부에 정의된 모든 메서드와 변수는 그 클래스의 객체들을 통해 접근할 수 있습니다.
클래스 안에 메서드 정의하기
class Vehicle():
def car(self):
color = 'Red'
return color
v = Vehicle()
print(v.car())
print(v)
실행 결과
Red <__main__.Vehicle object at 0x05A59690>
인스턴스 메서드(Instance Methods)
파이썬에서 클래스 안에 메서드를 정의할 때는 반드시 첫 번째 매개변수로 self를 지정해야 합니다. self는 해당 클래스로부터 객체가 생성될 때, 그 객체 자신이 메서드에 자동으로 전달된다는 의미입니다.
흥미로운 점은 메서드를 호출할 때는 self에 해당하는 인자를 직접 넘겨주지 않아도 된다는 것입니다. 하지만 클래스 내부에서 함수를 정의할 때는 self 매개변수를 반드시 작성해야 합니다.
다음 예제를 통해 이 개념을 자세히 살펴보겠습니다.
class myClass():
def myMethod(self):
return 'Hello'
myInstance = myClass()
print(myInstance.myMethod())
실행 결과
Hello
위 프로그램에서는 myClass라는 클래스를 정의하고, 그 안에 myMethod() 메서드를 정의하면서 self라는 단 하나의 매개변수만 전달했습니다.
그런데 클래스의 인스턴스를 통해 메서드를 호출할 때는 어떠한 인자도 넘겨주지 않았습니다. 그 이유는 인스턴스에서 메서드를 호출하는 순간, 첫 번째 인자로 그 인스턴스 자신이 자동으로 전달되기 때문입니다.
이번에는 위 프로그램에서 한 줄을 수정해 보겠습니다.
def myMethod():
myMethod() 메서드에서 self 매개변수를 제거했습니다. 이 상태로 프로그램을 다시 실행하면 어떻게 될까요?
================ RESTART: C:\Python\Python361\oops_python.py ================ Traceback (most recent call last): File "C:\Python\Python361\oops_python.py", line 18, in <module> print(myInstance.myMethod()) TypeError: myMethod() takes 0 positional arguments but 1 was given
위와 같이 TypeError가 발생합니다. 즉, 메서드의 첫 번째 매개변수로 self를 반드시 작성해야 한다는 뜻입니다.
인스턴스 속성(Instance Attributes)
인스턴스 속성은 객체마다 고유하게 유지되는 속성으로, 주로 __init__ 메서드의 매개변수로 정의됩니다. 서로 다른 객체는 각각 서로 다른 값을 가질 수 있습니다.
다음 예제를 살펴보겠습니다.
import random
class myClass():
def myMethod(self):
self.attrib1 = random.randint(1, 11)
self.attrib2 = random.randint(1, 21)
myInst = myClass()
myInst.myMethod()
print(myInst.attrib1)
print(myInst.attrib2)
실행 결과
2 18
위 프로그램에서 attrib1과 attrib2가 바로 인스턴스 속성입니다. 무작위(random) 값이 할당되므로 실행할 때마다 결과가 달라질 수 있습니다.
파이썬의 __init__ 생성자(Constructor)
생성자(constructor)는 클래스의 인스턴스 멤버들을 초기화하는 데 사용되는 특수한 메서드입니다.
생성자는 크게 두 가지 유형으로 나눌 수 있습니다.
- 매개변수가 있는 생성자(Parameterized Constructor)
- 매개변수가 없는 생성자(Non-parameterized Constructor)
파이썬에서 "__init__"은 모든 파이썬 클래스에 고유하게 연결되는 특별한 메서드입니다.
파이썬은 클래스로부터 객체가 생성될 때마다 이 메서드를 자동으로 호출하며, 그 목적은 사용자가 제공한 값으로 클래스 속성을 초기화하는 것입니다. 객체 지향 프로그래밍에서는 이를 '생성자'라고 부릅니다.
class Employee:
def __init__(self, name):
self.name = name
def display(self):
print("The name of the employee is: ", self.name)
obj1 = Employee('Zack')
obj2 = Employee('Rajesh')
obj3 = Employee('Tashleem')
obj3.display()
obj1.display()
실행 결과
The name of the employee is: Tashleem The name of the employee is: Zack
위 프로그램에서는 인스턴스(obj1, obj2, obj3)를 생성할 때 name 인자를 함께 전달하고, 생성자(__init__)가 이 값을 인스턴스 속성에 할당합니다.
따라서 특정 인스턴스에서 display 메서드를 호출하면, 그 인스턴스에 저장된 고유한 이름이 출력됩니다.
파이썬의 캡슐화(Encapsulation)
파이썬은 본질적으로 객체 지향 언어이기 때문에, 메서드와 변수에 대한 접근을 제한하는 방법을 제공합니다.
데이터 캡슐화가 적용되면, 객체의 속성에 직접 접근해 값을 수정할 수 없습니다. 외부에서 인스턴스 속성을 마음대로 변경할 수 있다면 애플리케이션이 해커의 공격에 취약해질 수 있기 때문입니다. 대신 인스턴스 속성의 값은 특정 메서드를 통해서만 변경할 수 있습니다.
예제
class Product:
def __init__(self):
self.__maxprice = 1000
self.__minprice = 1
def sellingPrice(self):
print('Our product maximum price is: {}'.format(self.__maxprice))
print('Our product minimum price is: {}'.format(self.__minprice))
def productMaxPrice(self, price):
self.__maxprice = price
def productMinPrice(self, price):
self.__minprice = price
prod1 = Product()
prod1.sellingPrice()
prod1.__maxprice = 1500
prod1.sellingPrice()
prod1.__minprice = 10
prod1.sellingPrice()
prod1.productMaxPrice(1500)
prod1.sellingPrice()
prod1.productMinPrice(10)
prod1.sellingPrice()
실행 결과
Our product maximum price is: 1000 Our product minimum price is: 1 Our product maximum price is: 1000 Our product minimum price is: 1 Our product maximum price is: 1000 Our product minimum price is: 1 Our product maximum price is: 1500 Our product minimum price is: 1 Our product maximum price is: 1500 Our product minimum price is: 10
위 프로그램에서는 Product 클래스의 인스턴스를 생성한 후, 인스턴스 변수의 값을 직접 수정하려고 시도했지만 여전히 생성자 안에서 설정된 값이 출력됩니다. 이는 더블 언더스코어(__)로 시작하는 속성이 네임 맹글링(name mangling)을 통해 외부에서의 직접 접근이 제한되기 때문입니다.
결국 인스턴스 속성의 값을 변경할 수 있는 유일한 방법은 productMaxPrice() 또는 productMinPrice() 메서드를 호출하는 것입니다. 이것이 바로 캡슐화를 통해 데이터를 안전하게 보호하는 원리입니다.