페이지

2022년 8월 27일 토요일

21.3 문제점1: 첫 번째 인수가 flaot나 int인 경우

 현재의 DeZero는 x * 2.0이라는 코드를 제대로 실행할 수 있습니다(x는 Variable 인스턴스). 하지만 2.0 * x를 실행하면 오류가 납니다. 어떤 오류가 나는지 볼까요?

y = 2.0 * x

원인은 2.0 * x를 실행했을 때 오류가 발생하는 과정을 보면 알수 있습니다. 2.0 * x 는 다음 순서로 처리됩니다.

1. 연산자 왼쪽에 있는 2.0의 __mul__메서드를 호출하려 시도한다.

2. 하지만 2.0은  float 타입이므로 __mul__ 메서드는 구현되어 있지 않다.

3. 다음은 * 연산자 오른쪽에 있는 x의 특수 메서드를 호출하려 시도한다.

4. x가 오른쪽에 있기 때문에 (__mul__대신) __mul__ 메서드를 호출하려 시도한다.

5. 하지만 Variable 인스턴스에는 __mul__메서드가 구현되어 있지 않다.

이상이 오류 발생 과정입니다. 핵심은 * 같은 이항 연산자의 경우 피연산자(항)의 위치에 따라 호출되는 특수 메서드가 다르다는 것입니다. 곱셈의 경우 피연사자가 촤항이면 __mul__메서드가 호출되고, 우항이면 __rmul__메서드가 호출됩니다.

따라서 이번 문제는 __rmul__메서드를 구현하면 해결됩니다. 이때 __rmul__메서드의 인수는 [그림 21-1]처럼 전달됩니다.

Variable.__add__ = add
Variable._radd__ =  add
Variable.__mul__ = mul
Variable.__rmul__ = mul

[그림 21-1]과 같이 __rmul__(self, other)의 인수 중 self는 자신인 x에 대응하고, other는  다른 쪽 항인 2.0에 대응합니다. 그런데 곱셈에서는 좌항과 우항을 바꿔도 결과가 같기 때문에 둘을 구별할 필요가 없습니다(2.0 * x 와 x * 2.0의 결과가 똑같죠). 덧셈도 마찬가지이므로 + 와 * 의 특수 메서드는 다음처럼 설정하면 됩니다.


이제 float와 int를 자류롭게 계산할 수 있습니다. 연습삼아 실제로 해보죠

x = Variable(np.array(2.0))
y = 3.0 * x + 1.0
print(y)

이제 Variable 인스턴스와 float, int 를 함께 사용할 수 있습니다. 이어서 나머지 문제 하나를 마저 해결해보죠.




댓글 없음: