{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 파이썬의 클래스 구조" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## class 키워드를 사용한 클래스 정의" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "class Page: # 클래스 정의\n", " def __init__(self, num, content):\n", " self.num = num # ページ番号\n", " self.content = content # 페이지 내용\n", " def output(self):\n", " return f'{self.content}'" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "__main__.Page" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Page # 클래스 객체 Page가 정의됨" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 인스턴스 만들기" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# 인스턴스화\n", "title_page = Page(0, 'Python Practice Book')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "__main__.Page" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(title_page) # 인스턴스의 클래스를 확인함" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Page 클래스의 인스턴스인지 확인함\n", "isinstance(title_page, Page)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['__class__',\n", " '__delattr__',\n", " '__dict__',\n", " '__dir__',\n", " '__doc__',\n", " '__eq__',\n", " '__format__',\n", " '__ge__',\n", " '__getattribute__',\n", " '__gt__',\n", " '__hash__',\n", " '__init__',\n", " '__init_subclass__',\n", " '__le__',\n", " '__lt__',\n", " '__module__',\n", " '__ne__',\n", " '__new__',\n", " '__reduce__',\n", " '__reduce_ex__',\n", " '__repr__',\n", " '__setattr__',\n", " '__sizeof__',\n", " '__str__',\n", " '__subclasshook__',\n", " '__weakref__',\n", " 'content',\n", " 'num',\n", " 'output']" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 인스턴스가 가진 속성을 확인함\n", "dir(title_page)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 인스턴스 ── 클래스를 기반으로 만들어진 객체" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 인스턴스 메서드 ── 인스턴스에 묶인 메서드" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "title_page.output() # 인스턴스 메서드 호출" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 메서드 객채와 함수 객체" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "class Klass:\n", " def some_method(self): # 인스턴스 메서드 정의\n", " print('method')" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def some_function(self): # 같은 인수의 함수 정의\n", " print('function')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "function" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 함수는 function 클래스의 인스턴스임\n", "type(some_function)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "function" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 인스턴스 메서드도 function 클래스의 인스턴스\n", "type(Klass.some_method)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "method" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 인스턴스를 통해 접근하면 method 클래스가 됨\n", "kls = Klass()\n", "type(kls.some_method)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "# 클래스 객체의 속성에 함수를 추가\n", "Klass.some_function = some_function" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "function\n" ] } ], "source": [ "# 인스턴스 메서드로 실행\n", "kls.some_function()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 인스턴스 변수 ── 인스턴스가 저장하는 변수" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "title_page.section = 0\n", "title_page.section" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "AttributeError", "evalue": "'Page' object has no attribute 'section'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mfirst_page\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'first page'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mfirst_page\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Page' object has no attribute 'section'" ] } ], "source": [ "first_page = Page(1, 'first page')\n", "first_page.section" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 인스턴스 초기화" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \\_\\_init\\_\\_() ── 인스턴스 초기화를 수행하는 특수 메서드" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# 클래스 정의 \n", "class Page:\n", " def __init__(self, num, content, section=None):\n", " self.num = num\n", " self.content = content\n", " self.section = section\n", " def output(self):\n", " return f'{self.content}'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 인수를 전달해 인스턴스화 하기" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# 인스턴스 작성\n", "title_page = Page(0, 'Python Practice Book')" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "title_page.section # section은 None" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "title_page.output()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# section을 지정해 다른 인스턴스를 작성\n", "first_page = Page(1, 'first page', 1)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "first_page.section # section이 지정되어 있음" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'first page'" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "first_page.output()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \\_\\_init\\_\\_()과 \\_\\_new\\_\\_()의 차이 ── 이니셜라이저와 컨스트럭터" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "class Klass:\n", " def __new__(cls, *args): # 컨스트럭터\n", " print(f'{cls=}')\n", " print('new', args)\n", " # 작성한 인스터스를 반환함 \n", " return super().__new__(cls)\n", " def __init__(self, *args): # 이니셜라이저\n", " # 인스턴스 초기화는 여기에서 수행함\n", " print('init', args)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "cls=\n", "new (1, 2, 3)\n", "init (1, 2, 3)\n" ] } ], "source": [ "# 인스턴스화\n", "kls = Klass(1, 2, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \\_\\_new\\_\\_() 사용 시 주의점" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "class Evil:\n", " def __new__(cls, *args):\n", " return 1" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "# Evil 클래스 인스턴스화\n", "evil = Evil()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(evil, Evil)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(evil)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 인스턴스는 __new__()의 반환값\n", "evil" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "class MyClass(Evil):\n", " def print_class(self):\n", " print('MyClass')" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "my = MyClass() # my 값은 1이 됨" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "AttributeError", "evalue": "'int' object has no attribute 'print_class'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# 추가되었어야 할 메서드를 이용할 수 없음\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mmy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprint_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'int' object has no attribute 'print_class'" ] } ], "source": [ "# 추가되었어야 할 메서드를 이용할 수 없음\n", "my.print_class()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 프로퍼티 ── 인스턴스 메서드를 인스턴스 변수와 같이 다룸" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "class Book:\n", " def __init__(self, raw_price):\n", " if raw_price < 0:\n", " raise ValueError('price must be positive')\n", " self.raw_price = raw_price\n", " self._discounts = 0\n", " @property\n", " def discounts(self):\n", " return self._discounts\n", " @discounts.setter\n", " def discounts(self, value):\n", " if value < 0 or 100 < value:\n", " raise ValueError(\n", " 'discounts must be between 0 and 100')\n", " self._discounts = value\n", " @property\n", " def price(self):\n", " multi = 100 - self._discounts\n", " return int(self.raw_price * multi / 100)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book = Book(2000)\n", "book.discounts # 초기 할인율 0" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2000" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book.price # 초기 가격 2000" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1600" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book.discounts = 20 # 할인율 설정\n", "book.price # 할인 후의 가격" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "discounts must be between 0 and 100", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbook\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdiscounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m120\u001b[0m \u001b[0;31m# 할인율이 100을 초과하면 에러 발생\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36mdiscounts\u001b[0;34m(self, value)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdiscounts\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;36m100\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m raise ValueError(\n\u001b[0m\u001b[1;32m 14\u001b[0m 'discounts must be between 0 and 100')\n\u001b[1;32m 15\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_discounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: discounts must be between 0 and 100" ] } ], "source": [ "book.discounts = 120 # 할인율이 100을 초과하면 에러 발생" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### property ── 값을 얻을 때 호출되는 메서드" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### setter ── 값을 설정할 때 호출되는 메서드" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "discounts must be between 0 and 100", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbook\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdiscounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36mdiscounts\u001b[0;34m(self, value)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdiscounts\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;36m100\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m raise ValueError(\n\u001b[0m\u001b[1;32m 14\u001b[0m 'discounts must be between 0 and 100')\n\u001b[1;32m 15\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_discounts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: discounts must be between 0 and 100" ] } ], "source": [ "book.discounts = -20" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "AttributeError", "evalue": "can't set attribute", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbook\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprice\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1000\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: can't set attribute" ] } ], "source": [ "book.price = 1000" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 클래스와 인스턴스의 프라이빗 속성" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 언더스코어로 시작하는 속성" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "20" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book._discounts # _로 시작하는 변수도 참조할 수 있음" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 언더스코어 2개로 시작하는 속성" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "class Klass:\n", " def __init__(self, x):\n", " self.__x = x" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "AttributeError", "evalue": "'Klass' object has no attribute '__x'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mkls\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mKlass\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mkls\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__x\u001b[0m \u001b[0;31m# 이 이름으로는 참조할 수 없음\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Klass' object has no attribute '__x'" ] } ], "source": [ "kls = Klass(10)\n", "kls.__x # 이 이름으로는 참조할 수 없음" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "kls._Klass__x # 변환 규칙을 알고 있다면 참조할 수 있음" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 프라이빗 속성에 대한 파이썬 커뮤니티의 사상" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 클래스 ── 인스턴스의 모형이 되는 객체" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 클래스 변수 ── 클래스 객체가 유지하는 변수" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "# 클래스 변수를 가진 클래스 정의\n", "class Page:\n", " book_title = 'Python Practice Book'" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Page.book_title # 인스턴스가 없어도 참조할 수 있음" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'No title'" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Page.book_title = 'No title' # 클래스 변수 업데이트\n", "Page.book_title" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 클래스 변수는 인스턴스에서도 참조 가능" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "first_page = Page()\n", "second_page = Page()" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'No title'" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 클래스 변수는 인스턴스에서도 참조 가능\n", "first_page.book_title" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'No title'" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "second_page.book_title" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "# 클래스 변수 업데이트\n", "Page.book_title = 'Python Practice Book'" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 클래스 변수는 모든 인스턴스에서 공유됨\n", "first_page.book_title" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "second_page.book_title" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'[Draft]Python Practice Book'" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 아래는 인스턴스 변수가 됨\n", "first_page.book_title = '[Draft]Python Practice Book'\n", "first_page.book_title" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 클래스 변수는 변경되지 않음\n", "Page.book_title" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'[Draft]Python Practice Book'" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "first_page.book_title # 인스턴스 변수" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [], "source": [ "# 인스턴스 변수 삭제\n", "del first_page.book_title" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Python Practice Book'" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 인스턴스 속성이 아니므로, 클래스 속성이 검색됨\n", "first_page.book_title" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 클래스 메서드 ── 클래스에 속한 메서드" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [], "source": [ "# 속성을 이용한 정렬에 사용할 수 있는 표준 라이브러리를 임포트\n", "from operator import attrgetter" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [], "source": [ "class Page:\n", " book_title = 'Python Practice Book'\n", " def __init__(self, num, content):\n", " self.num = num\n", " self.content = content\n", " def output(self):\n", " return f'{self.content}'\n", " # 클래스 메서드의 첫 번째 인수는 클래스 객체\n", " @classmethod\n", " def print_pages(cls, *pages):\n", " # 클래스 객체 이용\n", " print(cls.book_title)\n", " pages = list(pages)\n", " # 페이지 순으로 정렬해서 출력\n", " for page in sorted(pages, key=attrgetter('num')):\n", " print(page.output())" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "first = Page(1, 'first page')\n", "second = Page(2, 'second page')\n", "third = Page(3, 'third page')" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python Practice Book\n", "first page\n", "second page\n", "third page\n" ] } ], "source": [ "# 클래스 메서드 호출\n", "Page.print_pages(first, third, second)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python Practice Book\n", "first page\n", "second page\n", "third page\n" ] } ], "source": [ "# 인스턴스에서도 호출할 수 있음\n", "first.print_pages(first, third, second)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 스태틱 메서드 ── 함수처럼 동작하는 메서드" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [], "source": [ "class Page:\n", " def __init__(self, num, content):\n", " self.num = num\n", " self.content = content\n", " @staticmethod # 스태틱 메서드로 정의\n", " def check_blank(page):\n", " return bool(page.content)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "page = Page(1, '')\n", "Page.check_blank(page)" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [], "source": [ "def check_blank(page): # 함수로 문제 없음\n", " return bool(page.content)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "check_blank(page)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 클래스 상속" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 메서드 오버라이드와 super()를 사용한 베이스 클래스로의 접근" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "class Page:\n", " def __init__(self, num, content):\n", " self.num = num\n", " self.content = content\n", " def output(self):\n", " return f'{self.content}'" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [], "source": [ "# 메서드 오버라이드 \n", "class TitlePage(Page):\n", " def output(self):\n", " # 베이스 클래스의 메서드는 자동으로 호출되지 않으므로\n", " # 명시적으로 호출함\n", " title = super().output()\n", " return title.upper()" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'PYTHON PRACTICE BOOK'" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "title = TitlePage(0, 'Python Practice Book')\n", "title.output()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 모든 객체는 object 클래스의 서브 클래스" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [], "source": [ "class Length(float): # 내장 타입의 서브 클래스 작성\n", " def to_cm(self):\n", " return super().__str__() + 'cm'" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "16.0cm\n" ] } ], "source": [ "pencil_length = Length(16)\n", "print(pencil_length.to_cm())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 다중 상속 ── 여러 베이스 클래스를 지정" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [], "source": [ "class HTMLPageMixin:\n", " def to_html(self):\n", " return f'{self.output()}'" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "# 다중 상속을 사용한 Mixin 이용\n", "class WebPage(Page, HTMLPageMixin):\n", " pass" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'web content'" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "page = WebPage(0, 'web content')\n", "page.to_html()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 다중 상속 시 주의점" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "class A:\n", " def hello(self):\n", " print('Hello')\n", "\n", "class B(A):\n", " def hello(self):\n", " print('Hola')\n", " super().hello() # 베이스 클래스의 메서드를 실행\n", "\n", "class C(A):\n", " def hello(self):\n", " print('안녕하세요')\n", " super().hello() # 베이스 클래스의 메서드를 실행\n", "\n", "class D(B, C):\n", " def hello(self):\n", " print('Xin Chao')\n", " super().hello() # 베이스 클래스의 메서드를 실행" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Xin Chao\n", "Hola\n", "안녕하세요\n", "Hello\n" ] } ], "source": [ "d = D()\n", "d.hello()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \\_\\_mro\\_\\_ 이용한 시용한 메서드 결정 순서 확인" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(__main__.D, __main__.B, __main__.C, __main__.A, object)" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "D.__mro__ # 메서드 결정 순서 확인" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Xin Chao\n", "Hola\n", "안녕하세요\n", "Hello\n" ] } ], "source": [ "d.hello()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 정리" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.7" } }, "nbformat": 4, "nbformat_minor": 4 }