Nim connects to Python

Source: Internet
Author: User
Tags python list


Original: https://akehrer.github.io/nim/2015/01/24/connecting-nim-to-python.html



At the end of the previous article, I asked about the code for the Nim connection to the Python interface, and I was able to do some work after some experimentation. So, let's take a look.


Compiling a library


The first thing we want to talk about is the Nim compiler. In most cases you Compile the Nim code into an executable file to run this command.

Nim C Projectfile.nim

But to write the code in a library, we'll need to look at the compiler's documentation. There are many options here, but --app is of interest to us, and in our case we will use the -app command to create a shared library. ( .dll in Windows, in .so Linux, and in .dylib OSX).

Nim C--app:lib Projectfile.nim

Run the above command to create a projectfile.dll or libprojectfile.so file in the directory under the . Nim file . It was fantastic, but it didn't give us what we wanted. This library has been created, but there are no functional functions that we have exposed. is not very useful.


The exportc& dynlibPragmas


Nim has a special way of accessing pragmas, which gets additional information from the compiler when it parses a particular block of code. We have seen their use in previous articles, remember that the following code loads the isNaN function from MATH.H.

Import Mathproc Cisnan (x:float): int {. IMPORTC: "isNaN", Header: "<math.h>".}  # # returns Non-zero if X is not a number

In the above code {. and.} between include IMPORTC statement, which is to tell the compiler to Nim in the Cisnan the process needs to be used math.h in the isNaN function.


So, if Nim has a way to import C Code, then there should be a way to export the code to C ; it's EXPORTC . . With EXPORTC can tell the compiler to show our function to the outside. Add the dynlib statement to ensure that we can access our process from the Access library.

Let's start with a few simple examples:

Proc summer* (x, y:float): float {. EXPORTC, dynlib.} =  result = x + y

Save it as Test1.nim, Run the command under Windows Nim C--app:lib Test1.nim will get a test1.dll file. Now let's see if we can use it. ( libtest1.so files are generated under Linux )


Python ctypes

In order to use the compiled library, we will use the cTYPES module in Python , which is already part of the standard library since the 2.5 version. It allows us to use C -based code that is compiled in the library to convert between the Python type and the C type. The code here can access our summer function.



From cTYPES import *def main ():    test_lib = Cdll (' test1 ')        # Function parameter Types    test_ Lib.summer.argtypes = [C_float, c_float]        # Function return types    test_lib.summer.restype = c_float        sum_res = Test_lib.summer (1.0, 3.0)    print (' The sum of 1.0 and 3.0 is:%f '%sum_res) if __name__ = = ' __main__ '    : Main ()

We can see that after the library is loaded, the return type of the parameter and function is set, and then two arguments are passed to call the function. Let's see what's going on.

C:\workspaces\nim-tests>python test1.pythe Sum of 1.0 and 3.0 is:32.000008

Well, that's not true. It seems that we may not be using the correct parameters and return types. Let's compareNimof thefloatType andPython ctypesof thec_floattype. According toNimManuals,floatType is set to the fastest floating-point of the processor. Python ctypesmanual saysc_floatis withCin thefloatThe same type. is because I use +-bit version ofNimrun this code and2.7version ofPythonin the -bitWindowsMachine isNimthe compiler makes itsfloatto beDouble?


From cTYPES import *def main ():    test_lib = Cdll (' test1 ')        # Function parameter Types    test_ Lib.summer.argtypes = [C_double, c_double]        # Function return types    test_lib.summer.restype = c_double        Sum_res = Test_lib.summer (1.0, 3.0)    print (' The sum of 1.0 and 3.0 is:%f '%sum_res) if __name__ = = ' __main__ ':    mai N ()

C:\workspaces\nim-tests>python test1.pythe Sum of 1.0 and 3.0 is:4.000000

It seems to have been solved. When we know that we will use EXPORTC or create a shared library,Nim has a type that lets us add more constraints, reducing these types of confusion (e.g. cfloat,cint) .


openArrayArguments & the header file


Now let's try something more complicated, using the median function in the statistics module written in the previous two articles .

Nim Code:

Proc median* (X:openarray[float]): float {. EXPORTC, dynlib.} = # computes the median of the elements in   ' x '.   # # If ' x ' is empty and NaN is returned.  If X.len = = 0:    return NAN    var sx = @x # Convert to a sequence since sort () won ' t take an openarray  sx.sort (sys Tem.cmp[float])    if Sx.len mod 2 = = 0:    var n1 = sx[(sx.len-1) Div 2]    var n2 = Sx[sx.len Div 2]    result = ( N1 + N2)/2.0  Else:    result = sx[(sx.len-1) Div 2]

Python Code:

1 from ctypes Import * 2  3 def Main (): 4     test_lib = Cdll (' test1 ') 5      6     # Function parameter types 7     tes T_lib.summer.argtypes = [C_double, c_double] 8     test_lib.median.argtypes = [POINTER (c_double), C_int] 9     # Function return types11     test_lib.summer.restype = c_double12     test_lib.median.restype = c_double13     14     # Calc Some numbers15     nums = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]16     Nums_arr = (c_double * len (nums)) ( )     i,v in Enumerate (nums):         nums_arr[i] = c_double (v)     sum_res = Test_lib.summer (1.0, 3.0)     print (' The sum of 1.0 and 3.0 is:%f '%sum_res)     med_res = Test_lib.median (Nums_arr, C_int (Len (nums_a RR)),     print (' The median of%s is:%f '% (Nums, med_res)) "If __name__ = = ' __main__ ':     Main ()

         There are some interesting things happening here that allow us to invoke   MEDIAN&NBSP; process. In this nim In the code you can see that it just needs a parameter, a float openarray OPENARRAYS&NBSP; makes it possible to transfer arrays of different sizes to the process. But how to convert it into c What about the library? (You may be from PYTHON&NBSP; nim additional parameters of the compiler.

Nim C--app:lib--header Test1.nim

This --header option will generate a C header file in the folder Nimcache that the module is compiled in . If we see the header file will look like this:

1/* Generated by Nim Compiler v0.10.2 *   /2/* (c) Andreas Rumpf */3 */The Generated code is subject to the Ori Ginal License. */4 */Compiled for:windows, i386, GCC */5/Command for C compiler:6    gcc.exe-c-  w  -ic:\nim\lib-o C:\wo RKSPACES\NIM-TESTS\NIMCACHE\TEST1.O C:\workspaces\nim-tests\nimcache\test1.h */7 #ifndef __test1__ 8 #define __test1_ _ 9 #define Nim_intbits 3210 #include "nimbase.h" one N_noconv (void, signalhandler) (int sig), N_nimcall (NI, Getrefcount) ( void* p); N_lib_import n_cdecl (NF, median) (nf* x, NI xLen0), N_lib_import n_cdecl (NF, Summer) (NF X, NF y), N_lib_imp ORT n_cdecl (void, nimmain) (void); #endif/* __test1__ */

It is important that the first -and the -OK, the process of our two outputs is aroused. Can seeSummerIt's about two .NFtype of parameters, we can assume that theNimin thefloattype. on the otherMedianIt's not like we 'reNima parameter defined in the procedure, but two, one is a pointer to theNFpointer, and the other isNimthe integral type inNI. There is a hint about an integral type that is the length of a value. So thisOpenarrayparameters have been converted to theCin the standard way of passing an array, a pointer to the array and the length of an array.

In python code you can see that we set the correct parameters ([POINTER (c_double), c_int) and return type (c_double) and we map a python list to a double array of C in rows 15 through 18. Then when we call this function on line 23, make sure the length of the list is converted to a c_int. Let's check the results.

C:\workspaces\nim-tests>python test1.pythe Sum of 1.0 and 3.0 is:4.000000the median of [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] is:4.500000

This looks good, it's enough for this article. In future articles we will see more types of interfaces, like strings, tuples, and custom objects.





Reference

Nim Compiler User Guide
Nim Manual
Python cTYPES
Python ctypes Tutorial

(Thanks to DOM96 for corrections.)



Nim connects to Python

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.