str 과 repr
파이썬 내장함수에는 str과 repr이라는 어찌보면 매우 비슷한 기능을 해 주는 함수가 있다.
str과 repr은 모두 객체를 문자열로 리턴해 주는 함수이다. 하지만 두개의 함수에는 약간의 차이가 있다.
str과 repr의 차이점
어떤 차이가 있는지 예제를 보며 알아보자. 먼저 숫자에 적용해 보자.
>>> a = 123
>>> str(a)
'123'
>>> repr(a)
'123'
숫자는 아무런 차이가 없어 보인다. 이번에는 문자열에 적용해 보자.
>>> a = "Life is too short"
>>> str(a)
'Life is too short'
>>> repr(a)
"'Life is too short'"
문자열은 str과 repr이 다른 결과값을 리턴해 주었다. str은 문자열 그대로를 리턴해 주었는데 repr은 단일인용부호(')가 좌우로 감싸여진 형태의 문자열을 리턴해 주었다.
음 왜 그럴까?
한가지 예를 더 들어보자.
>>> a = datetime.datetime(2017, 9, 27)
>>> str(a)
'2017-09-27 00:00:00'
>>> repr(a)
'datetime.datetime(2017, 9, 27, 0, 0)'
datetime으로 만들어진 객체는 매우 다른 결과를 리턴해 주었다.
str과 repr에는 다음과 같은 차이점들이 있다.
구분 | str | repr |
---|---|---|
성격 | 비공식적인 문자열을 출력 | 공식적인 문자열을 출력 |
사용목적 | 사용자가 보기 쉽게 하기 위해 | 문자열로 객체를 다시 생성할 수 있기 위해 |
누구를 위해 | 프로그램 사용자(end user) | 프로그램 개발자(developer) |
repr의 사용목적을 보면 "문자열로 객체를 다시 생성할 수 있기 위해" 라고 되어 있다. 문자열로 객체를 생성하기 위해서는 eval함수를 사용한다. 즉, 다음과 같이 datetime객체의 repr로 생성된 문자열에 다시 eval을 수행하면 datetime객체가 만들어 져야 한다는 말이다.
>>> a = datetime.datetime(2017, 9, 27)
>>> b = repr(a)
>>> eval(b)
datetime.datetime(2017, 9, 27, 0, 0)
위 예제에서 알아본 문자열도 마찬가지이다.
>>> a = "Life is too short"
>>> b = repr(a)
>>> eval(b)
'Life is too short'
하지만 str으로 리턴된 문자열을 eval로 수행했을 때는 다음과 같은 오류가 발생한다.
>>> a = "Life is too short"
>>> b = str(a)
>>> eval(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
Life is too short
^
SyntaxError: unexpected EOF while parsing
문자열을 repr했을때 왜 단일 인용부호(')가 덧붙여서 나왔는지 이제 이해가 될 것이다.
클래스의 __str__ 과 __repr__
이번에는 사용자가 만든 클래스에서 repr과 str이 어떻게 적용되는지 확인해 보자.
class MyRepr:
pass
obj = MyRepr()
print(repr(obj))
print(str(obj))
MyRepr이라는 아무런 내용도 없는 클래스를 작성한 후 obj라는 객체를 생성하였다. 그리고 repr과 str로 해당 객체를 출력해 보았다. 결과는 다음과 같이 출력된다.
<__main__.MyRepr object at 0x100656cc0>
<__main__.MyRepr object at 0x100656cc0>
repr이나 str으로 객체 출력시 디폴트 문자열이 출력되는 것을 확인 할 수 있다. 이번에는 repr 호출시 의미있는 문자열이 출력되도록 다음과 같이 수정해 보자.
class MyRepr:
def __repr__(self):
return "Hello MyRepr"
obj = MyRepr()
print(repr(obj))
print(str(obj))
클래스에 __repr__
메서드를 구현하면 repr메서드 호출시 수행되게 된다. 따라서 repr로 obj호출시 다음과 같은 문자열이 출력될 것이다.
Hello MyRepr
마찬가지로 클래스에 __str__
메서드를 구현하면 str메서드 호출시 수행되게 된다. 하지만 위 예제에서는 __str__
메서드를 구현하지 않았는데도 str(obj) 출력시 다음과 같은 문자열이 출력되었다.
Hello MyRepr
이렇게 되는 이유는 str메서드 호출시 제일먼저 __str__
메서드가 구현되어 있는지 확인하고 없으면 __repr__
메서드를 호출하게 되기 때문이다.
이번에는 반대로 __repr__
대신 __str__
메서드만 구현해 보자.
class MyRepr:
def __str__(self):
return "Hello MyRepr"
obj = MyRepr()
print(repr(obj))
print(str(obj))
수행결과는 다음과 같이 출력된다.
<__main__.MyRepr object at 0x100656d68>
Hello MyRepr
repr은 호출시 __repr__
메서드가 없으면 __str__
메서드가 호출되지 않고 디폴트 값이 출력된다는 점을 알 수 있다. 즉 str은 __str__
이 없을 경우 __repr__
을 참조하지만 repr은 오직 __repr__
만 참조한다는 사실을 알 수 있다.
이번에는 repr 메서드의 사용목적인 "문자열로 다시 객체를 생성"을 만족하기 위해서 다음과 같이 코드를 수정해 보자. (참고. repr의 출력 문자열을 eval을 이용하여 다시 객체로 만들 수 있어야 한다는 것은 필수 조건은 아니다. 다만 권고사항 정도라고 보면 된다)
class MyRepr:
def __repr__(self):
return "MyRepr()"
def __str__(self):
return "Hello MyRepr"
obj = MyRepr()
obj_repr = repr(obj)
new_obj = eval(obj_repr)
print(type(new_obj))
repr 호출시 "MyRepr()"을 리턴하여 eval수행시 MyRepr()
이 수행되어 새로운 MyRepr 클래스의 객체가 생성되는 것을 확인할 수 있다.
eval로 생성된 new_obj의 type을 출력한 결과는 다음과 같다.
<class '__main__.MyRepr'>
박응용 님
1000
2020년 7월 8일 9:16 오후