2.21. 메서드와 속성

메서드 는 클래스 안에 정의된 함수입니다. 첫 번째 매개변수는 메서드가 호출된 인스턴스이며, 관례상 self 로 이름 짓습니다.

2.21.1. 인스턴스 메서드

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def magnitude(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

p = Point(3, 4)
print(p.magnitude())

출력:

5.0

호출 p.magnitude()pself 로 자동으로 전달합니다. 메서드 본문은 함수가 매개변수를 통해 이름을 읽고 갱신하는 것과 같은 방식으로 self 를 통해 속성을 읽고 갱신합니다.

2.21.2. 인스턴스 속성 대 클래스 속성

self 에 할당된 속성 – 일반적으로 __init__ 안에서 – 은 그 하나의 인스턴스에 속합니다:

a = Point(1, 2)
b = Point(10, 20)
a.x = 99
print(a.x, b.x)           # 99 10

a.xb.x 는 서로 다른 저장 공간입니다. 하나를 변경해도 다른 하나에 영향을 주지 않습니다.

메서드 바깥 의 클래스 본문에서 할당된 이름은 클래스의 모든 인스턴스가 공유합니다:

class Counter:
    kind = "tally"        # class attribute -- shared

    def __init__(self):
        self.value = 0    # instance attribute -- per instance

a = Counter()
b = Counter()
print(a.kind, b.kind)     # tally tally
맨 위에 공유 메서드와 클래스 속성 "kind"를 담은 클래스 블록이 있고, 그 아래에 각각 자신의 "value" 속성을 담은 두 개의 인스턴스 상자가 있으며, 각 인스턴스에서 클래스로 향하는 화살표가 있습니다.

클래스 속성은 클래스 자체에 존재하며 공유됩니다. 인스턴스 속성은 각 인스턴스에 존재합니다.

클래스 속성은 인스턴스 속성과 같은 방식으로 접근합니다(a.kind). Python은 먼저 인스턴스에서 찾고, 그다음 클래스에서 찾습니다. a.kind 에 할당하면 클래스 속성을 가리는 새 인스턴스 속성이 생성되고, b.kind 는 그대로 남습니다.

모든 인스턴스가 동일하게 봐야 하는 상수와 기본값에는 클래스 속성을 사용하세요. 각 객체가 자신만의 복사본을 소유해야 하는 상태에는 인스턴스 속성을 사용하세요.

2.21.3. __str__과 __repr__

두 개의 특수 메서드가 인스턴스가 어떻게 출력되는지를 제어합니다. __str__print() 가 사용하는 “친근한” 문자열을 반환하고, __repr__ 은 REPL과 컨테이너 표시 내부에서 사용되는 “개발자용” 문자열을 반환합니다:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "(" + str(self.x) + ", " + str(self.y) + ")"

    def __repr__(self):
        return "Point(" + str(self.x) + ", " + str(self.y) + ")"

p = Point(3, 4)
print(p)            # uses __str__
print([p, p])       # uses __repr__ inside the list

출력:

(3, 4)
[Point(3, 4), Point(3, 4)]

__repr__ 만 정의되어 있으면 print() 는 그것으로 대체합니다 – 그래서 잘 작성된 단일 __repr__ 하나면 보통 충분합니다. 친근한 형태가 개발자용 형태와 다르게 보여야 할 때만 __str__ 도 정의하세요. 객체를 다시 생성할 호출처럼 보이는 __repr__ 을 목표로 하세요. 출력된 값이 명확하면 디버깅이 극적으로 쉬워집니다.