파이썬 객체를 인스턴스화 하는법

파이썬 객체를 인스턴스화 하는법

객체를 인스턴스화(instantiate) 하기 위해서는, 클래스의 이름을 적고, 다음으로 클래스의 __init__() 메서드에 전달되어야 하는 모든 값을 포함한 괄호를 적어주면 된다.

다음은 새로운 Dog 클래스를 속성과 메서드 없이 생성한다.

>>> class Dog:
...	 pass

새로 만든 Dog 객체를 인스턴스화 해보자.

>>> Dog()
<__main__.Dog object at 0x106702d30>

출력 내용을 보면, 메모리 주소 0x106702d30에 위치한 새로운 Dog 객체가 생겼음을 확인할 수 있다.

다시 Dog 객체를 인스턴스화 해보자.

>>> Dog()
<__main__.Dog object at 0x0004ccc90>

보이는 것과 같이, 새로운 Dog 인스턴스는 다른 메모리 주소에 위치한다. 그 이유는 이 Dog 인스턴스가 전적으로 새로운 인스턴스이고, 처음 인스턴스화 한 Dog 객체로부터 완전히 고유하기 때문이다.

다음과 같이 다른 방법으로도 두 인스턴스가 다른 인스턴스라는 것을 확인할 수 있다.

>>> a = Dog()
>>> b = Dog()
>>> a == b
False

두 새로운 Dog 객체는 생성되고 각 변수 ab에 할당된다. == 연산자를 사용하여 변수 ab를 비교했을 때 보이는 것과 같이 결과는 False가 반환된다. 사용자가 정의한 클래스의 경우, == 연산자는 두 객체의 메모리 주소를 비교하고 주소가 같으면 True, 다르면 False를 반환한다.

즉, 객체 ab같은 클래스의 인스턴스이면서 같은 속성과 메서드를 가진다해도, ab메모리 속의 두 개의 다른 객체이다.

객체의 클래스를 확인하기 위해서 type() 함수를 사용할 수 있다.

>>> type(a)
<class '__main__.Dog'>

객체 ab가 다른 Dog 인스턴스이지만, 같은 타입을 가진다.

>>> type(a) == type(b)
True

클래스와 인스턴스 속성

조금은 더 복잡한 Dog 클래스 예제를 들여다보자. 다음의 예제에서는 새로운 Dog 클래스를 선언되고, Buddy와 Miles라는 두 개의 새로운 인스턴스가 생성된다.

>>> class Dog:
... 	species = "Canis familiaris"
... 	def __init__(self, name, age):
... 		self.name = name
... 		self.age = age
...
>>> buddy = Dog("Buddy", 9)
>>> miles = Dog("Miles", 4)

Dog 객체를 인스턴스화 하는 과정에서 조금 이상한 부분이 있는데, 바로 __init__() 메서드는 세 개의 매개변수를 가지지만, 단 두 개의 인수만이 전달되는 부분이다.

Dog 객체를 인스턴스화 할 때, 파이썬은 새로운 인스턴스를 만들고 __init__()첫 매개변수에 전달한다. 그럼으로 본질적으로 self 매개변수가 지워지고, 다음 매개변수인 nameage만 고려하면 되는 것이다

새로운 인스턴스를 생성한 후, 마침표(.)를 사용하면 인스턴스의 속성에 접근할 수 있다.

>>> buddy.name
'Buddy'
>>> buddy.age
9
>>> miles.name
'Miles'
>>> miles.age
4

클래스 속성 또한 같은 방법으로 접근할 수 있다.

>>> buddy.species
'Canis familiaris'

클래스를 사용해서 데이터를 구성할 때 얻을 수 있는 가장 큰 이점은 인스턴스가 사용자가 예상하는 속성을 가지도록 보장된다는 것이다.

>>> buddy.species == miles.species
True

인스턴스와 클래스 속성 둘 다 동적으로 수정될 수 있다.

>>> buddy.age = 10
>>> buddy.age
10

>>> miles.species = "Felis silvestris"
>>> miles.species
'Felis silvestris'
커스텀 객체는 기본적으로 가변객체이다.
동적으로 변경되기 위해서는 객체가 가변객체여야 한다는 점을 기억하자.

인스턴스 메서드

인스턴스 메서드는 클래스 안에서 정의된 함수를 의미한다. 즉, 인스턴스 메서드는 객체 자체의 컨텍스트 내에서만 존재하고 객체를 참조하지 않고서는 호출 될 수 없다. 인스턴스 메서드는 __init__()과 동일하게 첫 번째 인수가 항상 self여야 한다.

class Dog:
	species = "Canis familiaris"

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

	# 인스턴스 메서드
	def description(self):
		return f"{self.name} is {self.age} years old"

	# 인스턴스 메서드
	def speak(self, sound):
		return f"{self.name} says {sound}"

작성한 인스턴스 메서드는 다음과 같이 사용할 수 있다.

>>> miles = Dog("Miles", 4)

>>> miles.description()
'Miles is 4 years old'

>>> miles.speak("Woof Woof")
'Miles says Woof Woof'

>>> miles.speak("Bow Wow")
'Miles says Bow Wow'

Dog 클래스에서 정의된 description() 메서드는 Dog의 인스턴스인 miles의 관한 유용한 정보를 반환하지만, 사실 파이써닉한 방법이라고는 볼 수 없다.

리스트 객체를 생성할 때, print() 함수를 사용하면 리스트처럼 보이는 문자열을 출력할 수 있다.

>>> names = ["Fletcher", "David", "Dan"]
>>> print(names)
['Fletcher', 'David', 'Dan']

miles 객체를 print() 함수로 출력하면 어떤 일이 발생하는지 확인해보자.

>>> print(miles)
<__main__.Dog object at 0x00aeff70>

print(miles)를 실행하면 객체 miles0x00aeff70에 위치한 Dog 객체라는 메시지를 접하게 된다. 숫자 0x00aeff70는 사용자의 컴퓨터 메모리에 있는 Dog 객체의 주소이다.

하지만 print(miles)를 호출 했을 때 표시되는 메시지는 크게 도움이 되지 않는다. 이럴 때는 __str__()라고 불리는 특별한 인스턴스 메서드를 정의함으로써 출력되는 메시지를 변경할 수 있다.

Dog 클래스의 description() 메서드를 __str__() 메서드로 변경해보자.

class Dog:

	# description()를 __str__()로 교체
	def __str__(self):
		return f"{self.name} is {self.age} years old"

수정하고 나면 다음과 같이 더 나은 출력을 확인할 수 있다.

>>> miles = Dog("Miles", 4)
>>> print(miles)
'Miles is 4 years old'
__str__()와 같은 메서드는 두 개의 밑 줄로 시작하고 끝나기 때문에 던더 메서드(dunder method - double underscores)나 매직 메서드(magic method)로 흔히 불린다. 던더 메서드는 강력하면서 파이썬의 OOP의 중요한 부분이다.

Reference