Vector 생성자는 Vector2d 생성자와 호환되지 않도록 설계하여, init() 메서드에서 임의의 인수 *args를 받아서 Vector(3,4) 나 Vector(3,4,5)형태로 작동하게 만들 수 있으나 시퀀스 생성자는 내장 시퀀스처럼 반복형을 인수로 받게 만드는 것이 좋다.
#Vector.__init__ , Vector.__repr__() 테스트
Vector([3.1, 4.2])
Vector((3,4,5))
Vector(range(10))
생성자 시그니처가 달라진 점 외에 요소 두 개를 가진 Vector 클래스는 Vector2로 수행했던 모든 테스트와 동일한 결과가 나오도록 만들어졌다.
#vector_v1.py: vector2d_v1.py에서의 유도
from array import array
import reprlib
import math
class Vector:
typecode = 'd'
def __init__(self, components):
self._components = array(self.typecode, components)
def __iter__(self):
return iter(self._components)
def __repr__(self):
components = reprlib.repr(self._components)
components = components[components.find('['):-1]
return 'Vector({})'.format(components)
def __str__(self):
return str(tuple(self))
def __bytes__(self):
return (bytes([ird(self.typecode)]) +
bytes(self._components))
def __eq__(self,other):
return tuple(self) == tuple(other)
def __abs__(self):
return math.sqrt(sum(x * x for x in self))
def __bool__(self):
return bool(abs(self))
@classmethod
def frombytes(cls, octets):
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
return cls(memv)
reprlib.repr()을 사용한 방법을 자세히 설명하면, 이 함수는 생략 기호를 이용해서 생성할 문자열의 길이를 제한하므로 대형 구조체나 재귀적 구조체도 안전하게 표현하고, repr()이 Vector객체를 배열의 형태로 사용하여 구현 내용을 외부로 노출하지 않길 원한다.
repr()을 구현할 때, reprlib.repr(list(self._components))문장으로 components를 간략히 출력할 순 있으나 시간소요가 많으므로 바깥쪽에 글자들을 잘라낸다.
생성자가 호환되지 않으므로 상속받는 것은 좋지 않고, init()에서 매개변수를 영리하게 처리해서 이 문제를 해결할 수 있지만, 두 번째가 더 중요하고 Vector클래스가 시퀀스 프로토콜을 구현하는 독자적이길 원한다.