«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

Code IT

Python - self 본문

Python & Django

Python - self

Codit 2019. 2. 3. 14:47

https://developtip.tistory.com/110 - Python - class


링크된 위의 글에서 self라는 아귀먼트가 메서드마다 등장하고 있다.

이 키워드를 보면서 의아해했을 것 같아 추가로 글을 작성한다.


객체지향프로그래밍을 지원하는 언어들은 클래스 내부에 멤버변수와 메서드를 정의하게 된다. 물론 멤버변수 혹은 메서드만 존재하는 클래스도 정의할 수 있다.

아무튼, 클래스 내부에 정의되는 멤버변수들은 그 자체로는 큰 의미나 역할이 없다. 이 멤버변수는 항상 메서드라는 행위로만 접근할 수 있고 그 행위에 따라 의미가 변경될 수도 있다.


이 때, 메서드는 클래스(인스턴스) 내부의 멤버변수에 접근이 필요한데 그냥은 접근할 수 없다.


class Kona:
	""" 주석 : 자동차를 클래스로 표현해보자. """
	accel_pedal = "플라스틱 엑셀레이터"
	break_pedal = "플라스틱 브레이크"
	engine = "휘발유 8기통"
	
	def __init__(self):
		"""인스턴스가 만들어질 때 실행되는 생성자. 단 한번만 실행된다."""
		print("현대 코나가 만들어졌습니다.")
	
	def __del__(self):
		"""
			인스턴스가 소멸(제거)될 때 실행되는 소멸자. 단 한번만 실행된다.
			Reference Count가 0이 될 때 인스턴스가 소멸된다.
		"""
		print("현대 코나가 폐차되었습니다.")
	
	def start(self):
		print(self.engine + "이 켜집니다.")

	def go(self):
		print(self.accel_pedal + "을 밟아 " + self.engine + "엔진이 움직입니다.")
		
	def stop(self):
		print(self.break_pedal + "을 밟아 바퀴가 멈춥니다.")

위 코드의 start(self): 메서드의 내용을 잘 살펴보자.

self.engine 이 사용되고 있는데 이 코드는 현재 인스턴스에 존재하는 멤버 변수 engine을 참조하겠다는 의미가 된다.

만약 self가 없다면? 파이썬은 engine이라는 변수가 존재하지 않는다는 에러를 내뱉게 된다.


또한, self는 메서드 내부에서 다른 메서드를 호출할 수도 있다.


class Board:
	articles = []
	
	def print_welcome_message(self):
		print("""############################
# Welcome to Python Boards #
############################""")
	
	def print_menu(self):
		print("""##################################################################
# 1. List # 2. Search # 3. Read # 4. Delete # 5. Write # 0. Quit #
##################################################################""")	
	
	def input_menu(self):
		id = input("Choice Menu : ")
		return int(id)
		
	def print_all_articles(self):
		if len(self.articles) == 0:
			print("Have no articles.")
			return
		
		for artcl in self.articles:
			self.print_article(artcl)
	
	def print_article(self, article):
		print("Subject : " + article["subject"] + ", Read : " + str(article["read"]))
	
	def search_article(self):
		search_keyword = input("Input search keyword : ")
		
		for artcl in self.articles:
			if search_keyword in artcl["subject"]:
				self.print_article(artcl)
					
	def read_article(self):
		id = input("Choice article id : ")
		id = int(id)
		
		if len(self.articles) - 1 < id:
			print(id, " isn't exists.'")
		else:
			self.articles[id]["read"] += 1
			self.print_article(self.articles[id])
	
	def delete_article(self):
		id = input("Choice article id : ")
		id = int(id)
		
		if len(self.articles) - 1 < id:
			print(id, " isn't exists.'")
		else:
			self.articles.pop(id)
	
	def write_article(self):
		subject = input("Input Subject : ")
		article = {
			"subject": subject,
			"read": 0
		}
		
		self.articles.append(article)
	
	def run(self):
		self.print_welcome_message()
		
		while(True):
			self.print_menu()
			id = self.input_menu()
			
			if id == 1:
				self.print_all_articles()
			elif id == 2:
				self.search_article()
			elif id == 3:
				self.read_article()
			elif id == 4:
				self.delete_article()
			elif id == 5:
				self.write_article()
			elif id == 0:
				print("Quit!")
				break
			print("")
			
def start_board_app():
	board = Board()
	board.run()
	
if __name__ == "__main__":
	start_board_app()


위 코드는  https://developtip.tistory.com/112 (Python - 실습- 게시판 만들기(클래스) 에 있는 코드의 전부다.


print_article(self, article) 이라는 메서드가 하나 존재한다. 이 메소드는 전달받은 article 아귀먼츠를 출력하는 역할을 수행한다.

print_article(self, article) 메서드는 print_all_articles(self), search_article(self), read_article(self) 세 메서드에서 호출되고 있다. 이 때에도 self.print_article(...)이 사용되고 있는 모습을 볼 수 있다. 이처럼 self 통해서 멤버변수나 메서드를 호출 할 수 있도록 해준다.


자, 그러면 self.멤버변수, self.메서드명()의 역할은 이해했다고 하고 넘어가보도록 하자.


그러면 self는 무엇일까? 단순히 인스턴스의 멤버변수와 메서드를 참조 할 수 있도록 이어주는 매개체일까?

사실, self는 현재 호출하고 있는 인스턴스 그 자체이다.


무슨말인지 잘 모르겠다면 아래 코드를 한번 보도록하자.

단순하게 self만 전달받아 출력하는 메서드를 가진 클래스코드다.

하나의 클래스를 3개의 인스턴스로 만들어 각각 print_self()를 호출하고 있다.


class Self_Test:
	
	def print_self(self):
		print(self)
		
	
test = Self_Test()
test.print_self()

test1 = Self_Test()
test1.print_self()

test2 = Self_Test()
test2.print_self()

이 코드를 실행시키면 아래와 같은 결과를 볼 수 있다.

<__main__.Self_Test object at 0x11242d710> # test <__main__.Self_Test object at 0x11242d128> # test1 <__main__.Self_Test object at 0x11242d978> # test2

결과를 보면 같은 내용이 3번 나온것처럼 보이지만, 자세히 보면 서로 다른 값들이 출력된 것을 볼 수 있다.

결과의 의미를 쉽게 해석해보자면 결과 각각의 줄 끝의 숫자들은 인스턴스들의 메모리 주소값이라 생각해도 무방하다.


즉, self는 현재 호출되고 있는 인스턴스의 메모리 주소를 가지고 있다. 그러니 self는 인스턴스 자신이라 표현을 해도 무방하다.


그런데, 아직까지 궁금증이 해소되지 않은 것 하나가 더 있다.


함수나 클래스의 메서드는 한 가지의 규칙이 있다.

아귀먼츠의 개수가 3개라면, 파라미터의 개수도 3개여야만 한다.


그런데, 지금까지 보았던 메서드는 아귀먼츠가 맞는것이 단 하나도 없다. 특히 self 아귀먼츠가 파라미터로 전달이 단 하나도 안되고 있다. 그런데 실행이 잘된다!!!


왜 그럴까?

self 아귀먼츠는 파이썬 인터프리터에 의해서 자동으로 전달된다.

무슨 말이냐면 개발자가 메서드에 첫 번째 아귀먼츠를 self라고 적어 두기만 했다면 나머지는 파이썬이 알아서 해준다.

즉, self를 우리 스스로가 전달할 필요가 전혀 없다는 의미다.


“음... 아귀먼츠에 파라미터를 안줘도 된다고? 그러면 파라미터를 줘도 되긴 하겠네..” 라는 접근법은 좋았지만, 아쉽게도 그 코드는 에러가 발생한다.


class Self_Test:
	
	def print_self(self):
		print(self)
		
	
test = Self_Test()
test.print_self(test)

test1 = Self_Test()
test1.print_self(test1)

test2 = Self_Test()
test2.print_self(test2)


글이 길어졌다. self에 대해 정리를 해본다면

1. self는 인스턴스 자신을 가진 특별한 변수다.

2. self를 통해 인스턴스 내부의 멤버변수나 메서드에 접근할 수 있다.

3. 글에는 없지만, 메서드 아귀먼츠에 self가 없다면 내/외부에서 절대 호출할 수 없다.

4. self는 예약어가 아니다. 다른 이름으로 주어도 아무 상관이 없다. 그냥 첫 번째 아귀먼츠에 변수 하나를 정의하면 된다.

'Python & Django' 카테고리의 다른 글

Python - 상속  (0) 2019.02.03
Python - Class Method, Instance Method  (0) 2019.02.03
Python - 실습 - 게시판 만들기 (클래스)  (0) 2019.01.31
Python - 실습 - 게시판 만들기 (함수)  (0) 2019.01.31
Python - class  (0) 2019.01.31
Comments