はじめに
numpyを使っていて、TypeError: loop of ufunc does not support argument 0 of type int which has no callable XXX method
エラーにハマって時間を溶かしてしまったので、そのときに試した検証や対処法などを紹介します。
エラーの原因
先にこのエラーの原因を申し上げると、どうやらnumpyの入力可能な整数型の範囲が、-9223372036854775808 ~ 18446744073709551615
のようで、それよりも範囲外の時にこのエラーが出るようです。
この数字とnumpy
のデータ型との対応を書くと、以下のようになります。
numpy データ型 | 範囲 |
---|---|
int64 | 整数型 (-9223372036854775808 ~ 9223372036854775807) |
uint64 | 符号なし整数 (0 ~ 18446744073709551615) |
つまり、入力可能な範囲は、下限値がint64
の下限値に対応し、上限値はuint64
の上限値ということになります。
エラーの検証
numpyの三角関数(sin、cos、tan)、指数関数(exp)、対数関数(log)、平方根(sqrt)などの関数にこの整数型の制限が設けられているようです。一応以下のコードで検証しておきます。
Google colabでも同様のコードを書いているので、コードだけで良い方はこちらをご覧いただければと思います。
なお、このコードの実行時のnumpyのバージョンは1.22.4です。
import numpy as np
n_lower_lim = [-9223372036854775810, -9223372036854775809, -9223372036854775808, -9223372036854775807]
n_valid_range = [-1000, -1, 0, 1, 1000]
n_upper_lim = [18446744073709551614, 18446744073709551615, 18446744073709551616, 18446744073709551617]
n_verify = n_lower_lim + n_valid_range + n_upper_lim
for n in n_verify:
try:
verify_func = np.sin(n)
except TypeError:
print('Type Errorあり', n)
else:
print('Type Errorなし', n)
Type Errorあり -9223372036854775810
Type Errorあり -9223372036854775809
Type Errorなし -9223372036854775808
Type Errorなし -9223372036854775807
Type Errorなし -1000
Type Errorなし -1
Type Errorなし 0
Type Errorなし 1
Type Errorなし 1000
Type Errorなし 18446744073709551614
Type Errorなし 18446744073709551615
Type Errorあり 18446744073709551616
Type Errorあり 18446744073709551617
確かにその範囲の前後でType Error
エラーが確認できます。
エラーの対処法
float
型にキャストしてから入力
float
型にキャストしてから入力するとエラーを回避できます。
n_lower_lim = [-9223372036854775810, -9223372036854775809, -9223372036854775808, -9223372036854775807]
n_valid_range = [-1000, -1, 0, 1, 1000]
n_upper_lim = [18446744073709551614, 18446744073709551615, 18446744073709551616, 18446744073709551617]
n_verify = n_lower_lim + n_valid_range + n_upper_lim
for n in n_verify:
try:
verify_func = np.sin(float(n))
except TypeError:
print('Type Errorあり', n)
else:
print('Type Errorなし', n)
Type Errorなし -9223372036854775810
Type Errorなし -9223372036854775809
Type Errorなし -9223372036854775808
Type Errorなし -9223372036854775807
Type Errorなし -1000
Type Errorなし -1
Type Errorなし 0
Type Errorなし 1
Type Errorなし 1000
Type Errorなし 18446744073709551614
Type Errorなし 18446744073709551615
Type Errorなし 18446744073709551616
Type Errorなし 18446744073709551617
mathモジュールによる回避
基本的な数学関数は、mathモジュールにも実装されており、mathの関数を使った場合はエラーが出ませんでした。大きな整数値を扱うときは、numpyの代替として、mathを使うのも選択肢としてありだと思います。
import math
n_lower_lim = [-9223372036854775810, -9223372036854775809, -9223372036854775808, -9223372036854775807]
n_valid_range = [-1000, -1, 0, 1, 1000]
n_upper_lim = [18446744073709551614, 18446744073709551615, 18446744073709551616, 18446744073709551617]
n_verify = n_lower_lim + n_valid_range + n_upper_lim
for n in n_verify:
try:
verify_func = math.sin(n)
except TypeError:
print('Type Errorあり', n)
else:
print('Type Errorなし', n)
Type Errorなし -9223372036854775810
Type Errorなし -9223372036854775809
Type Errorなし -9223372036854775808
Type Errorなし -9223372036854775807
Type Errorなし -1000
Type Errorなし -1
Type Errorなし 0
Type Errorなし 1
Type Errorなし 1000
Type Errorなし 18446744073709551614
Type Errorなし 18446744073709551615
Type Errorなし 18446744073709551616
Type Errorなし 18446744073709551617
まとめ
loop of ufunc does not support argument 0 of type int which has no callable XXX method
エラーは、float
型にキャストしてから入力、あるいはmathを使って回避していきましょう。
と言いつつも、筆者は基本numpyで完結したい派なのですが、ただfloat型へのキャストもコードの見栄え悪くなり、さらにこの唐突なキャストは、Python的な発想ではないので、第三者から意図が汲み取れずに削除ということもありコメントで補足する必要があるので、どこかのタイミングで改善されると良いですね。