(12주차) 5월23일
클래스 공부 4단계
-
(1/4) motivating example
-
(2/4) __str__
, 파이썬의 비밀2
-
(3/4) __repr__
, 파이썬의 비밀3
-
(4/4) 주피터노트북의 비밀 (_repr_html_
), __repr__
와 __str__
의 우선적용 순위
import numpy as np
-
가위바위보
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
def throw(self):
print(np.random.choice(self.candidate))
a=RPS() # __init__는 암묵적으로 실행
a.throw()
-
생각해보니까 throw는 choose + show 의 결합인것 같다.
class RPS: ## 시점1
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
def choose(self):
self.actions = np.random.choice(self.candidate)
def show(self):
print(self.actions)
a=RPS() ## 시점2
a.actions ## 시점3
a.choose() ## 시점4
a.actions ## 시점5
a.show() ## 시점6
보충학습: 위와 같은코드
class _RPS: ## 시점1
pass # <- 이렇게하면 아무기능이 없는 비어있는 클래스가 정의된다
_a = _RPS() ## 시점2
def _init(_a,candidate=['가위','바위','보']):
_a.candidate = candidate
_init(_a)
_a.actions ## 시점3
def _choose(_a): ## 시점4
_a.actions = np.random.choice(_a.candidate)
_choose(_a)
_a.actions ## 시점5
def _show(_a): ## 시점6
print(_a.actions)
_show(_a)
-
또 다른 인스턴스 b를 만들자. b는 가위만 낼 수 있다.
b=RPS(['가위'])
b.candidate
b.choose()
b.show()
-
a,b의 선택들을 모아서 기록을 하고 싶다.
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
a=RPS()
b=RPS(['가위'])
for i in range(5):
a.choose()
a.show()
a.actions
for i in range(5):
b.choose()
b.show()
b.actions
-
info라는 함수를 만들어서 a,b 오브젝트가 가지고 있는 정보를 모두 보도록 하자.
(예비학습) 문자열 \n
이 포함된다면?
'asdf\n1234'
print('asdf\n1234')
예비학습 끝
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def info(self):
print("낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions))
a=RPS()
b=RPS(['가위'])
for i in range(5):
a.choose()
a.show()
for i in range(5):
b.choose()
b.show()
a.info()
b.info()
-
만들고보니까 info와 print의 기능이 거의 비슷함 $\to$ print(a)를 하면 a.info()와 동일한 효과를 내도록 만들 수 있을까?
-
말도 안되는 소리같다. 왜?
- 이유1: print는 파이썬 내장기능, 내장기능을 우리가 맘대로 커스터마이징해서 쓰기는 어려울 것 같다.
- 이유2: 이유1이 해결된다고 쳐도 문제다. 그럼 지금까지 우리가 사용했던 수 많은 print()의 결과는 어떻게 되는가?
-
그런데 a의 자료형(RPS자료형)에 해당하는 오브젝트들에 한정하여 print를 수정하는 방법이 가능하다면? (그럼 다른 오브젝트들은 수정된 print에 영향을 받지 않음)
-
관찰1: 현재 print(a)의 결과는 아래와 같다.
print(a)
- a는 RPS클래스에서 만든 오브젝트이며 a가 저장된 메모리 주소는 0x7fef32fef8b0라는 의미
-
관찰2: a에는 __str__
이 있다.
set(dir(a)) & {'__str__'}
이것을 함수처럼 사용하니까 아래와 같이 된다.
a.__str__()
?? print(a)를 해서 나오는 문자열이 리턴된다..
print(a.__str__()) # 이거 print(a)를 실행한 결과와 같다?
-
생각: 만약에 내가 a.__str__()
라는 함수를 재정의하여 리턴값을 'guebin hahaha'로 바꾸게 되면 print(a)해서 나오는 결과는 어떻게 될까? (약간 해커같죠)
(예비학습) 함수덮어씌우기
def f():
print('asdf')
f()
def f():
print('guebin hahaha')
f()
이런식으로 함수가 이미 정의되어 있더라도, 내가 나중에 덮어씌우면 그 함수의 기능을 다시 정의한다.
(해킹시작)
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def __str__(self):
return 'guebin hahaha'
def info(self):
print("낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions))
a=RPS()
print(a)
print(a.__str__())
-
__str__
의 리턴값을 info에서 타이핑했던 문자열로 재정의한다면?
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def __str__(self):
return "낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions)
a=RPS()
print(a)
a.choose()
a.show()
print(a)
-
print(a)
와 print(a.__str__())
는 같은 문법이다.
-
참고로 a.__str__()
와 str(a)
도 같은 문법이다.
a.__str__()
str(a)
-
지금까지 우리가 썼던 기능들 확인!
(예제1)
a=[1,2,3]
print(a)
a.__str__()
str(a)
(예제2)
a={1,2,3}
print(a)
a.__str__()
str(a)
(예제3)
a=np.array(1)
a.shape
print(a.shape)
a.shape.__str__()
str(a.shape)
(예제4)
a=range(10)
print(a)
a.__str__()
str(a)
(예제5)
a = np.arange(100).reshape(10,10)
print(a)
a.__str__()
str(a)
-
생각해보니까 print를 해서 우리가 원하는 정보를 확인하는건 아니었음
a=[1,2,3]
a
print(a)
-
a + 엔터
는 print(a) + 엔터
와 같은효과인가?
(반례)
a=np.array([1,2,3,4]).reshape(2,2)
a
print(a)
-
a + 엔터
는 print(a) + 엔터
가 다른 경우도 있다. $\to$ 추측: 서로 다른 숨겨진 기능이 있다! $\to$ 결론: 추측이 맞다. 그 기능은 __repr__
에 저장되어있음.
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def __repr__(self):
return "낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions)
a=RPS()
a # print(a.__repr__())
-
그럼 우리가 지금까지 했던것은?
a = np.array([1,2,3])
a
print(a)
a.__repr__()
a.__str__()
-
대화형콘솔에서 오브젝트이름+엔터
를 쳐서 나오는 출력은 __repr__
의 결과와 연관있다.
a = np.array(range(10000)).reshape(100,100)
a
a.__repr__()
-
참고로 a.__repr__()
은 repr(a)
와 같다.
repr(a)
-
요즘에는 IDE의 발전에 따라서 오브젝트이름+엔터
칠떄 나오는 출력의 형태도 다양해지고 있음
import pandas as pd
df = pd.DataFrame({'a':[1,2,3],'b':[2,3,4]})
df
- 예쁘게나온다.
-
위의결과는 print(df.__repr__())
의 결과와 조금 다르게 나온다?
print(df.__repr__())
-
print(df.__repr__())
는 예전 검은화면에서 코딩할때가 나오는 출력임
Python 3.10.2 | packaged by conda-forge | (main, Feb 1 2022, 19:28:35) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
> >> import pandas as pd
>>> df = pd.DataFrame({'a':[1,2,3],'b':[2,3,4]})>>> df
a b
0 1 2
1 2 3
2 3 4
>>>
-
주피터에서는? "오브젝트이름+엔터"치면 HTML(df._repr_html_())
이 실행되고, _repr_html_()
이 정의되어 있지 않으면 print(df.__repr__())
이 실행된다.
df._repr_html_()
- html코드!
from IPython.core.display import HTML
HTML(df._repr_html_())
-
물론 df._repr_html_()
함수가 내부적으로 있어도 html이 지원되지 않는 환경이라면 print(df.__repr__())
이 내부적으로 수행된다.
(예제1)
-
아래의 예제를 관찰하자.
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def __repr__(self):
return "낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions)
a=RPS()
a
a.__repr__()
repr(a)
-
여기까지는 상식수준의 결과임. 이제 아래를 관찰하라.
print(a) # print(a.__str__())
a.__str__()
str(a)
-
__str__()
은 건드린적이 없는데? $\to$ 건드린적은 없는데 기능이 바껴있음
a.__str__??
a.__repr__??
(예제2)
-
아래의 예제를 관찰하자.
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def __str__(self):
return "낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions)
a=RPS()
print(a)
a
a.__str__()
a.__repr__()
a.__str__??
a.__repr__??
(예제3)
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def __repr__(self):
return "guebin hahaha"
def __str__(self):
return "낼 수 있는 패: {}\n기록: {}".format(self.candidate,self.actions)
a=RPS()
a
print(a)
-
__str__
와 __repr__
을 건드리지 않고 출력결과를 바꾸고 싶다면?
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def _repr_html_(self):
html_str = """
낼 수 있는 패: {} <br/>
기록: {}
"""
return html_str.format(self.candidate,self.actions)
a=RPS()
str(a)
repr(a)
a
for i in range(5):
a.choose()
a.show()
a
아래의 클래스를 수정하여
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def _repr_html_(self):
html_str = """
낼 수 있는 패: {} <br/>
기록: {}
"""
return html_str.format(self.candidate,self.actions)
클래스에서 생성된 인스턴스의 출력결과가 아래와 같도록 하라.
학번: 202143052
낼 수 있는 패: ['가위', '바위', '보']
기록: ['가위', '가위', '보', '보', '바위']