

pyhonの高速化のためにnumbaを導入しました。  
その中で、ある関数だけ@jitでの型指定ができずプログラムを動かすことができません。  
その関数では引数として他の関数を引っ張ってきてるのですが、関数が引数の場合の型指定がわからない状況です。  
どなたか解決策ご存知ないでしょうか。  
もしくはそもそも@jitでは関数を引数として扱う関数は使えないということなのでしょうか

* * *

**12/25追記**  
コードを以下のように書き換えました。  
型が正しく認識されないためにNoneTypeとして処理されているのではないかと考えています。

**ソースコード**

[code]

    from numba import jit, int32, float64
    from numba import types
    
    @jit(int32(int32))
    def a(x):
      return 2 + x
    
    @jit(int32(int32))
    def b(x):
      return 2 * x
    
    @jit(float64(int32))
    def c(x):
      return 2 / x
    
    @jit([print((f._type.get_call_signatures()) for f in globals().values() if hasattr(f, '_type') and isinstance(f._type, types.Dispatcher))]) 
    def f(x, g):
      return g(x)
    
    if __name__ == '__main__':
      print(f'Signature of function a: {a._type.get_call_signatures()[0]}')
      print(f'Signature of function b: {b._type.get_call_signatures()[0]}')
      print(f'Signature of function c: {c._type.get_call_signatures()[0]}')
      print(f'Signature of function f:\n{f._type.get_call_signatures()[0]}')
      print(f'f(1, a) = {f(1, a)}')
      print(f'f(1, b) = {f(1, b)}')
      print(f'f(3, c) = {f(3, c)}')
    
[/code]

**エラーメッセージ**

[code]

    runfile('C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py', wdir='C:/Users/nakada/Desktop/DIC/python/code')
    <generator object <genexpr> at 0x00000257391877C8>
    Traceback (most recent call last):
    
      File "<ipython-input-134-e1e163fb48a4>", line 1, in <module>
        runfile('C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py', wdir='C:/Users/nakada/Desktop/DIC/python/code')
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, in runfile
        execfile(filename, namespace)
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
        exec(compile(f.read(), filename, 'exec'), namespace)
    
      File "C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py", line 23, in <module>
        @jit([print((f._type.get_call_signatures()) for f in globals().values() if hasattr(f, '_type') and isinstance(f._type, types.Dispatcher))])
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\numba\decorators.py", line 186, in wrapper
        disp.compile(sig)
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\numba\compiler_lock.py", line 32, in _acquire_compile_lock
        return func(*args, **kwargs)
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\numba\dispatcher.py", line 676, in compile
        args, return_type = sigutils.normalize_signature(sig)
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\numba\sigutils.py", line 37, in normalize_signature
        parsed.__class__.__name__
    
    TypeError: invalid signature: None (type: 'NoneType') evaluates to 'NoneType' instead of tuple or Signature
    
[/code]

**1/6追記**  
最初に頂いたコードを実行したところ以下のエラーが出ました。

**ソースコード**

[code]

    from numba import jit, int32, float64
    from numba import types
    
    @jit(int32(int32))
    def a(x):
      return 2 + x
    
    @jit(int32(int32))
    def b(x):
      return 2 * x
    
    @jit(float64(int32))
    def c(x):
      return 2 / x
    
    @jit([
      (f._type.get_call_signatures()[0][0].return_type)(int32, f._type)
      for f in globals().values()
      if hasattr(f, '_type') and
         isinstance(f._type, types.Dispatcher) and
         f._type.get_call_signatures()[0][0] in
           (int32(int32), float64(int32))
    ])
    def f(x, g):
      return g(x)
    
    if __name__ == '__main__':
      print(f'Signature of function a: {a._type.get_call_signatures()[0]}')
      print(f'Signature of function b: {b._type.get_call_signatures()[0]}')
      print(f'Signature of function c: {c._type.get_call_signatures()[0]}')
      print(f'Signature of function f:\n{f._type.get_call_signatures()[0]}')
      print(f'f(1, a) = {f(1, a)}')
      print(f'f(1, b) = {f(1, b)}')
      print(f'f(3, c) = {f(3, c)}')
    
[/code]

**エラーコード**

[code]

    unfile('C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py', wdir='C:/Users/nakada/Desktop/DIC/python/code')
    Traceback (most recent call last):
    
      File "<ipython-input-135-e1e163fb48a4>", line 1, in <module>
        runfile('C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py', wdir='C:/Users/nakada/Desktop/DIC/python/code')
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, in runfile
        execfile(filename, namespace)
    
      File "C:\ProgramData\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
        exec(compile(f.read(), filename, 'exec'), namespace)
    
      File "C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py", line 18, in <module>
        for f in globals().values()
    
      File "C:/Users/nakada/Desktop/DIC/python/code/タイトル無し4.py", line 21, in <listcomp>
        f._type.get_call_signatures()[0][0] in
    
    IndexError: list index out of range
    
[/code]

このエラーを解決するために  
@jit([print(f._type.get_call_signatures()) for f in globals().values() if
hasattr(f, '_type') and isinstance(f._type, types.Dispatcher)])  
を使うのでしょうか？

**1/6追記その2**  
最初に頂いたコードの18行目のfor文は関数a,bと関数cの型が異なるために必要だと認識しているのですが、それは正しいですか？  
また、関数cもa,bと同じ型の場合for文以下を省略もしくは書き換えることは可能でしょうか？  
何度も質問して申し訳ありません、回答よろしくお願いします。


CC BY-SA 4.0
2019-12-17T01:45:20.207
61492
2020-01-06T07:55:35.090
2020-01-06T07:55:35.090
37096
37096
question
python python3
numbaの@jitでの、関数引数の型指定について


`numba.types.functions.Dispatcher._type` を利用する方法はどうでしょうか。以下は単純な実行例です。

[code]

    from numba import jit, int32, float64
    from numba import types
    
    @jit(int32(int32))
    def a(x):
      return 2 + x
    
    @jit(int32(int32))
    def b(x):
      return 2 * x
    
    @jit(float64(int32))
    def c(x):
      return 2 / x
    
    @jit([
      (f._type.get_call_signatures()[0][0].return_type)(int32, f._type)
      for f in globals().values()
      if hasattr(f, '_type') and
         isinstance(f._type, types.Dispatcher) and
         f._type.get_call_signatures()[0][0] in
           (int32(int32), float64(int32))
    ])
    def f(x, g):
      return g(x)
    
    if __name__ == '__main__':
      print(f'Signature of function a: {a._type.get_call_signatures()[0]}')
      print(f'Signature of function b: {b._type.get_call_signatures()[0]}')
      print(f'Signature of function c: {c._type.get_call_signatures()[0]}')
      print(f'Signature of function f:\n{f._type.get_call_signatures()[0]}')
      print(f'f(1, a) = {f(1, a)}')
      print(f'f(1, b) = {f(1, b)}')
      print(f'f(3, c) = {f(3, c)}')
    
    =>
    Signature of function a: [(int32,) -> int32]
    Signature of function b: [(int32,) -> int32]
    Signature of function c: [(int32,) -> float64]
    Signature of function f:
    [(int32, type(CPUDispatcher(<function a at 0x7f4f86c82b00>))) -> int32,
     (int32, type(CPUDispatcher(<function b at 0x7f4f5e4800e0>))) -> int32,
     (int32, type(CPUDispatcher(<function c at 0x7f4f5e429050>))) -> float64]
    f(1, a) = 3
    f(1, b) = 2
    f(3, c) = 0.6666666666666666
    
[/code]


CC BY-SA 4.0
2019-12-17T06:30:41.500
61504
2019-12-17T15:37:20.463
2019-12-17T15:37:20.463
61492
answer


直接の回答ではありませんが、いくつか関連情報を見つけたので回答としてまとめておきます。

  * Numba 0.39 以降では、JIT コンパイル済みのグローバル関数は引数として渡すことができます。ただし型アノテーション無しです。

Numba ドキュメント [1.18 Frequently Asked Questions](https://numba.pydata.org/numba-
doc/dev/user/faq.html) より：

> As of Numba 0.39, you can, so long as the function argument has also been
> JIT-compiled:
[code] >     @jit(nopython=True)

>     def f(g, x):
>         return g(x) + g(-x)
>  
>     result = f(jitted_g_function, 1)
>  
[/code]

>
> (後略)

  * 関数の内側で定義された関数や lambda の扱いには制限がついています（Numba 0.47 時点）。

Numba ドキュメント [2.6.1.2. Functions](https://numba.pydata.org/numba-
doc/dev/reference/pysupported.html#functions) より：

> Numba now supports inner functions as long as they are non-recursive and
> only called locally, but not passed as argument or returned as result. The
> use of closure variables (variables defined in outer scopes) within an inner
> function is also supported.

関連 issue：[Support for higher order functions and
lambdas](https://github.com/numba/numba/issues/1730)

  * JIT コンパイル済みの関数であれば [`numba.typeof`](https://numba.pydata.org/numba-doc/dev/reference/types.html#numba.typeof) を使うと型が取得でき、これが型アノテーションにも使えるようです。ただしこの関数は stable ではなく、ドキュメントには「必要が無い場合は Numba の型推論に任せて」と書かれていました。また、`numba.typeof` を使って関数の型を得てもそれは関数型というよりかは関数の ID のようなものなので、metropolis さんの回答のように使いたいだけ列挙しないといけなくなります。


CC BY-SA 4.0
2019-12-17T09:06:13.400
61512
2019-12-17T13:52:08.087
2019-12-17T13:52:08.087
19110
19110
61492
answer