Как исследовать функцию, определенную в модуле расширения Cython C

Python inspect модуль, похоже, не способен проверять подписи "встроенных" функций, которые включают в себя функции определенных в C-модулях расширения, подобных тем, которые определены Cython. Есть ли способ получить подпись функции Python, которую вы определили в таком модуле, и конкретно в Cython? Я ищу, чтобы найти доступные аргументы ключевых слов.

MWE:

# mwe.pyx
def example(a, b=None):                                                                                                                                                       
    pass       

и

import pyximport; pyximport.install()                                                                                                                                         
import mwe                                                                                                                                                                    
import inspect                                                                                                                                                                

inspect.signature(mwe.example)   

дает:

Traceback (most recent call last):                                                                                                                                           
  File "mwe_py.py", line 5, in <module>                                                                                                                                      
    inspect.signature(mwe.example)                                                                                                                                           
  File "/nix/store/134l79vxb91w8mhxxkj6kb5llf7dmwpm-python3-3.4.5/lib/python3.4/inspect.py", line 2063, in signature                                                         
    return _signature_internal(obj)                                                                                                                                          
  File "/nix/store/134l79vxb91w8mhxxkj6kb5llf7dmwpm-python3-3.4.5/lib/python3.4/inspect.py", line 1965, in _signature_internal                                               
    skip_bound_arg=skip_bound_arg)                                                                                                                                           
  File "/nix/store/134l79vxb91w8mhxxkj6kb5llf7dmwpm-python3-3.4.5/lib/python3.4/inspect.py", line 1890, in _signature_from_builtin                                           
    raise ValueError("no signature found for builtin {!r}".format(func))                                                                                                     
ValueError: no signature found for builtin <built-in function example>    

В Python 3.4.5 и Cython 0.24.1

Ответ 1

Я отозвал свое дублирующее предложение (сказав, что это было невозможно...), продолжив расследование. Кажется, что он отлично работает с достаточно свежими версиями Cython (v0.23.4) и Python 3.4.4.

import cython
import inspect
scope = cython.inline("""def f(a,*args,b=False): pass """)
print(inspect.getfullargspec(scope['f']))

дает вывод

FullArgSpec(args=['a'], varargs='args', varkw=None, defaults=None, kwonlyargs=['b'], kwonlydefaults={'b': False}, annotations={})


В документации также упоминается опция компиляции " binding ", которая, по-видимому, делает эту деталь более доступной (хотя она мне и не нужна).


У меня есть ощущение, что это может зависеть от улучшений для inspect сделанных относительно недавно (возможно, это исправление), поэтому, если вы используете Python 2, вам, вероятно, не повезло.


Изменить: ваш пример работает, если вы используете опцию компиляции binding:

import cython
@cython.binding(True)
def example(a, b=None):                                                                                                                                                       
    pass

Я подозреваю, что inline добавляет его автоматически (но код для inline достаточно запутан, и я не могу найти доказательств этого в любом случае). Вы также можете установить его как параметр уровня файла.

Ответ 2

Ответ выше с использованием декоратора привязки работает для меня, когда выполняется код, который был цифонизирован. Но когда я выполнял тот же код в приложении Django 2.2, приложение запускалось с ошибкой при запуске с ошибкой, что у cython нет атрибута "привязка". Чтобы избежать этого, я добавил этот "специальный заголовок Cython" в начало моего файла, содержащего функцию Cythonized, как описано здесь, для достижения тех же результатов.

# cython: binding=True