수색…


비고

두 가지 방법 모두 구현에 대한 참고 사항

두 메소드가 모두 구현 될 때 인간 친화적 인 표현 (예 : "Ace of Spaces")을 반환하는 __str__ 메소드를 사용하는 것이 일반적이며 __repr__eval 친숙한 표현을 반환합니다.

사실, repr() 대한 Python 문서는 정확히 다음과 같은 내용을 기록합니다.

많은 함수에서이 함수는 eval ()에 전달 될 때 동일한 값을 가진 객체를 반환하는 문자열을 반환하려고 시도합니다. 그렇지 않으면 표현은 함께 객체 유형의 이름이 포함 된 꺾쇠 괄호로 묶인 문자열입니다 종종 개체의 이름과 주소를 포함하는 추가 정보가 있습니다.

이것이 의미하는 것은 __str__ 이 이전에 보여준 것처럼 "Ace of Spaces"와 같은 것을 반환하도록 구현 될 수 있다는 것입니다. __repr__ 은 대신 Card('Spades', 1) 를 반환하기 위해 구현 될 수 있습니다.

이 문자열은 다소 "왕복"형태로 eval 에 직접 전달 될 수 있습니다.

object -> string -> object

그러한 메소드의 구현 예는 다음과 같습니다.

def __repr__(self):
    return "Card(%s, %d)" % (self.suit, self.pips)

노트

[1]이 출력은 구현에 따라 다릅니다. 표시된 문자열은 cpython에서 가져온 것입니다.

[2] 당신은 이미이 str() / repr() 의 결과를 나누어 그것을 알지 못했을 수도 있습니다. 백 슬래시와 같은 특수 문자가 포함 된 문자열을 str() 통해 문자열로 변환하면 백 슬래시가있는 것처럼 나타납니다 (한 번 나타남). repr() 통해 문자열로 변환되면 (예 : 목록의 요소가 표시됨) 백 슬래시가 이스케이프되므로 두 번 나타납니다.

자극

따라서 방금 재생 카드를 캡슐화하는 깔끔하고 작은 클래스 인 Python으로 첫 번째 수업을 만들었습니다.

class Card:
    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

코드의 다른 부분에서이 클래스의 몇 가지 인스턴스를 만듭니다.

ace_of_spades = Card('Spades', 1)
four_of_clubs = Card('Clubs',  4)
six_of_hearts = Card('Hearts', 6)

"손"을 표현하기 위해 카드 목록을 만들었습니다.

my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]

이제 디버깅하는 동안 손이 어떻게 보이는지보고 싶으므로 자연스럽게 나오고 작성하는 작업을 수행하십시오.

print(my_hand)

그러나 당신이 돌아 오는 것은 횡설수설의 무리 다 :

[<__main__.Card instance at 0x0000000002533788>, 
 <__main__.Card instance at 0x00000000025B95C8>, 
 <__main__.Card instance at 0x00000000025FF508>]

혼란 스러워요, 당신은 단지 하나의 카드를 인쇄하려고합니다 :

print(ace_of_spades)

그리고 다시, 당신은이 이상한 결과를 얻습니다.

<__main__.Card instance at 0x0000000002533788>

두려워하지 마라. 이 문제를 해결하려고합니다.

우선, 여기서 일어나는 일을 이해하는 것이 중요합니다. print(ace_of_spades) 를 쓸 때 파이썬에게 코드에서 ace_of_spades 호출하는 Card 인스턴스에 대한 정보를 인쇄하기를 원했습니다. 그리고 공정하게, 그것은했다.

이 출력은 두 가지 중요한 비트로 구성됩니다. 객체의 type 과 객체의 id 입니다. 두 번째 부분 만 (16 진수) print 호출시 개체를 고유하게 식별하기에 충분합니다. [1]

실제로 진행된 것은 여러분이 파이썬에게 그 객체의 본질을 "말로 표현"하고 그것을 여러분에게 보여달라고 요청한 것입니다. 동일한 기계류의보다 명확한 버전은 다음과 같습니다.

string_of_card = str(ace_of_spades)
print(string_of_card)

첫 번째 줄에서는 Card 인스턴스를 문자열로 변환하고 두 번째 인스턴스에서는 문자열을 표시하려고합니다.

문제

마주 치게되는 문제는 파이썬에게 Card만드는 데 필요한 Card 클래스에 대해 알아야 할 모든 것을 말했지만 Card 인스턴스를 문자열로 변환하는 방법을 알려주지 않았기 때문에 발생합니다.

그리고 그것은 몰랐기 때문에 여러분이 (암시 적으로) str(ace_of_spades) 쓸 때, 그것은 여러분이 보았던 것, 즉 Card 인스턴스의 일반적인 표현을 여러분에게주었습니다.

해결책 (1 부)

그러나 우리는 우리가 어떻게 커스텀 클래스의 인스턴스를 문자열로 변환 할 것인지 파이썬에게 말할 수 있습니다 . 그리고 우리가하는 일은 __str__ "dunder"(이중 밑줄) 또는 "magic"방법입니다.

파이썬에게 클래스 인스턴스로부터 문자열을 생성하라고 말할 때마다, 클래스에서 __str__ 를 찾아서 호출 할 것이다.

다음과 같이 업데이트 된 Card 클래스를 고려하십시오.

class Card:
    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    def __str__(self):
        special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

        card_name = special_names.get(self.pips, str(self.pips))

        return "%s of %s" % (card_name, self.suit)

이제 우리는 Card 클래스에서 __str__ 메서드를 정의했습니다.이 메서드는 얼굴 카드에 대한 간단한 사전 검색 후에 형식이 지정된 문자열을 반환 하지만, 우리는 결정합니다.

( "return"은 문자열을 반환하는 것의 중요성을 강조하기 위해 여기에 굵게 표시되어 있습니다. 단순히 인쇄하는 것만으로는 인쇄되지 않을 수도 있지만 str(ace_of_spades) , 주 프로그램에서 print 함수 호출을하지 않아도된다. 그래서 명확하게하려면 __str__ 이 문자열을 반환하는지 확인해야한다.

__str__ 메서드는 메서드이므로 첫 번째 인수는 self 되며 인수를 수락하거나 인수를 전달해서는 안됩니다.

카드를보다 사용자 친화적 인 방법으로 표시하는 문제로 돌아가서 다시 실행하면

ace_of_spades = Card('Spades', 1)
print(ace_of_spades)

우리는 우리의 산출물이 훨씬 더 좋음을 보게 될 것입니다 :

Ace of Spades

좋아, 끝났어. 그렇지?

우리 기지를 커버하기 위해, Card 인스턴스의 목록 인 hand 인쇄하면서 우리가 직면했던 첫 번째 문제를 해결했는지 다시 한번 확인합시다.

따라서 다음 코드를 다시 확인하십시오.

my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]
print(my_hand)

놀랍게도 재미있는 16 진수 코드를 다시 얻습니다.

[<__main__.Card instance at 0x00000000026F95C8>, 
 <__main__.Card instance at 0x000000000273F4C8>, 
 <__main__.Card instance at 0x0000000002732E08>]

무슨 일이야? 파이썬에게 우리의 Card 인스턴스가 어떻게 표시되기를 원하는지, 왜 분명히 잊어 버린 것 같습니까?

해결책 (2 부)

글쎄, 비하인드 머신은 파이썬이 목록에있는 항목의 문자열 표현을 원할 때 약간 다릅니다. 파이썬은이 목적으로 __str__ 을 신경 쓰지 않습니다.

대신 다른 방법을 찾습니다 __repr__ , 그 발견되어 있지 않은 경우, 그것은 다시 "16 진수 것"에 떨어진다. [2]

그래서 나는 똑같은 일을하는 두 가지 방법을 만들어야한다는 말입니까? 하나는 내 카드를 print 하고 다른 하나는 컨테이너에 print 할 때 사용하는 카드입니까?

아니요. 우선 __str____repr__ 메서드를 모두 구현하는 경우 클래스 어떻게 될지 살펴 보겠습니다.

class Card:
    special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    def __str__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s (S)" % (card_name, self.suit)

    def __repr__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s (R)" % (card_name, self.suit)

여기서는 __str____repr__ 의 두 메소드를 구별하기 위해 두 메소드를 구별하기 위해 __str__ 반환 한 문자열에 (S) 를 추가하고 __repr__ 반환 한 문자열에 (R) 을 추가합니다.

__str__ 메서드와 마찬가지로 __repr__ 도 인수를받지 않고 문자열을 반환 합니다.

이제 우리는 각각의 경우에 어떤 방법으로 책임이 있는지를 볼 수 있습니다.

ace_of_spades = Card('Spades', 1)
four_of_clubs = Card('Clubs',  4)
six_of_hearts = Card('Hearts', 6)

my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]

print(my_hand)           # [Ace of Spades (R), 4 of Clubs (R), 6 of Hearts (R)]

print(ace_of_spades)     # Ace of Spades (S)

덮었다으로, __str__ 우리가 통과 할 때 메서드가 호출 된 Card 에 인스턴스를 print 하고 __repr__ 우리가 우리의 인스턴스의 목록 통과 할 때 메소드가 호출 된 print .

이 시점에서 str() 을 사용하여 커스텀 클래스 인스턴스로부터 명시 적으로 스트링을 생성 할 수있는 것처럼 우리는 명시 적으로 클래스의 스트링 표현repr() 이라는 내장 함수로 생성 할 수있다. repr() .

예 :

str_card = str(four_of_clubs)
print(str_card)                     # 4 of Clubs (S)

repr_card = repr(four_of_clubs)
print(repr_card)                    # 4 of Clubs (R)

추가적으로 정의 된 경우, 메소드를 직접 호출 할 있습니다 (약간은 불분명하고 불필요한 것으로 보이지만).

print(four_of_clubs.__str__())     # 4 of Clubs (S)

print(four_of_clubs.__repr__())    # 4 of Clubs (R)

그 복제 된 기능들에 관해서 ...

파이썬 개발자는 str()repr() 에서 동일한 문자열을 반환하기를 원했을 때 함수를 복제하여 메서드를 복제해야한다는 것을 알았습니다.

그래서 대신에 그 필요성을 제거하는 메커니즘이 있습니다. 하나는 너를이 시점까지 지나치게 snuck했다. 클래스가 __repr__ 메소드를 구현 하지만 __str__ 메소드를 구현 하지 않고 해당 클래스의 인스턴스를 str() (암시 적 또는 명시 적이든간에)에 전달하면 Python이 __repr__ 구현에서 대체되어이를 사용합니다.

따라서, 다음과 같은 버전의 Card 클래스를 고려해보십시오.

class Card:
    special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    def __repr__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s" % (card_name, self.suit)

이 버전은 __repr__ 메소드 구현합니다. 그럼에도 불구하고 str() 호출하면 사용자 친화적 인 버전이됩니다.

print(six_of_hearts)            # 6 of Hearts  (implicit conversion)
print(str(six_of_hearts))       # 6 of Hearts  (explicit conversion)

repr() 호출도 마찬가지입니다.

print([six_of_hearts])          #[6 of Hearts] (implicit conversion)
print(repr(six_of_hearts))      # 6 of Hearts  (explicit conversion)

개요

클래스 인스턴스가 사용자 친화적 인 방식으로 "스스로 표시"하도록 권한을 부여하려면 적어도 클래스의 __repr__ 메소드를 구현하는 것이 좋습니다. 메모리가 작동한다면 Raymond Hettinger는 클래스가 __repr__ 구현한다는 것이 파이썬 코드 리뷰를 할 때 가장 먼저 찾은 것 중 하나라고 말했고 지금까지는 그 이유를 분명히해야합니다. 간단한 방법으로 디버깅 문, 충돌 보고서 또는 로그 파일에 추가 할 있는 정보의 양은 기본적으로 제공되는 유용하지 않은 (유형, ID) 정보와 비교할 때 압도적입니다.

예를 들어 컨테이너 내부에서 다른 표현을 원한다면 __repr____str__ 메소드를 모두 구현해야합니다. (아래 두 가지 방법을 어떻게 다르게 사용하는지 더 자세히).

두 메소드 모두 구현, eval-round-trip 스타일 __repr __ ()

class Card:
    special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    # Called when instance is converted to a string via str()
    # Examples:
    #   print(card1)
    #   print(str(card1)
    def __str__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s" % (card_name, self.suit)

    # Called when instance is converted to a string via repr()
    # Examples:
    #   print([card1, card2, card3])
    #   print(repr(card1))
    def __repr__(self):
        return "Card(%s, %d)" % (self.suit, self.pips)


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow