Превращение указателя функции в вызываемый
Что ж, адрес памяти скомпилированной функции получен, но как превратить его в вызываемый Python, который можно использовать как расширение. Ответ на этот вопрос - использование модуля ctypes, который может создавать вызываемый Python и переносить произвольный адрес памяти.
В приведенном ниже коде показано, как получить необработанный низкоуровневый адрес функции C и как превратить его обратно в вызываемый объект.
Code #1:
import ctypes lib = ctypes.cdll.LoadLibrary( None ) # Get the address of sin() from the C math library addr = ctypes.cast(lib.sin, ctypes.c_void_p).value print ( "addr : " , addr) |
Выход :
адрес: 140735505915760
Код # 2: превратить адрес в вызываемую функцию
functype = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double) func = functype(addr) print ( "Function : " , func) |
Выход :
Функция: <объект CFunctionType в 0x1006816d0>
Code #3 : Call the resulting function
print ( "func(2) : " , func( 2 )) print ( "func(0) : " , func( 0 )) |
Выход :
func (2): 0.9092974268256817 функция (0): 0,0
A CFUNCTYPE instance has to be created first to make a callable. The first argument to CFUNCTYPE()
is the return type. Next arguments are the types of arguments. After defining the function type, it is wrapped around an integer memory address to create a callable object. The resulting object is used like any normal function accessed through ctypes.
It is becoming increasingly common for programs and libraries to utilize advanced code generation techniques like just-in-time compilation, as found in libraries such as LLVM (LLVM itself is not an acronym; it is the full name of the project.)
В приведенном ниже коде расширение llvmpy используется для создания функции сборки, получения на нее указателя функции и превращения ее в вызываемый Python.
Code #4 :
from llvm.core import Module, Function, Type , Builder mod = Module.new( "example" ) f = Function.new(mod, Type .function( Type .double(), [ Type .double(), Type .double()], False ), "foo" ) block = f.append_basic_block( "entry" ) builder = Builder.new(block) x2 = builder.fmul(f.args[ 0 ], f.args[ 0 ]) y2 = builder.fmul(f.args[ 1 ], f.args[ 1 ]) r = builder.fadd(x2, y2) builder.ret(r) |
Выход :
<llvm.core.Instruction объект по адресу 0x10078e990>
Code #5 :
from llvm.ee import ExecutionEngine engine = ExecutionEngine.new(mod) ptr = engine.get_pointer_to_function(f) ptr |
Выход :
4325863440
Code #6 : Call the resulting function
foo = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double, ctypes.c_double)(ptr) print (foo( 2 , 3 )) print ( "
" , foo( 4 , 5 )) print ( "
" , foo( 1 , 2 )) |
Выход :
13,0 41,0 5.0
Внимание компьютерщик! Укрепите свои основы с помощью базового курса программирования Python и изучите основы.
Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS. А чтобы начать свое путешествие по машинному обучению, присоединяйтесь к курсу Машинное обучение - базовый уровень.