1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
# -*- Mode: Python -*- Not really, but close enough
"""Cython access to Numpy arrays - simple example.
"""
# Includes from the python headers
include "Python.pxi"
# Include the Numpy C API for use via Cython extension code
include "numpy.pxi"
################################################
# Initialize numpy - this MUST be done before any other code is executed.
import_array()
# Import the Numpy module for access to its usual Python API
import numpy as np
# A 'def' function is visible in the Python-imported module
def print_array_info(ndarray arr):
"""Simple information printer about an array.
Code meant to illustrate Cython/NumPy integration only."""
cdef int i
print '-='*10
# Note: the double cast here (void * first, then Py_intptr_t) is needed in
# Cython but not in Pyrex, since the casting behavior of cython is slightly
# different (and generally safer) than that of Pyrex. In this case, we
# just want the memory address of the actual Array object, so we cast it to
# void before doing the Py_intptr_t cast:
print 'Printing array info for ndarray at 0x%0lx'% \
(<Py_intptr_t><void *>arr,)
print 'number of dimensions:',arr.nd
print 'address of strides: 0x%0lx'%(<Py_intptr_t>arr.strides,)
print 'strides:'
for i from 0<=i<arr.nd:
# print each stride
print ' stride %d:'%i,<Py_intptr_t>arr.strides[i]
print 'memory dump:'
print_elements( arr.data, arr.strides, arr.dimensions,
arr.nd, sizeof(double), arr.dtype )
print '-='*10
print
# A 'cdef' function is NOT visible to the python side, but it is accessible to
# the rest of this Cython module
cdef print_elements(char *data,
Py_intptr_t* strides,
Py_intptr_t* dimensions,
int nd,
int elsize,
object dtype):
cdef Py_intptr_t i,j
cdef void* elptr
if dtype not in [np.dtype(np.object_),
np.dtype(np.float64)]:
print ' print_elements() not (yet) implemented for dtype %s'%dtype.name
return
if nd ==0:
if dtype==np.dtype(np.object_):
elptr = (<void**>data)[0] #[0] dereferences pointer in Pyrex
print ' ',<object>elptr
elif dtype==np.dtype(np.float64):
print ' ',(<double*>data)[0]
elif nd == 1:
for i from 0<=i<dimensions[0]:
if dtype==np.dtype(np.object_):
elptr = (<void**>data)[0]
print ' ',<object>elptr
elif dtype==np.dtype(np.float64):
print ' ',(<double*>data)[0]
data = data + strides[0]
else:
for i from 0<=i<dimensions[0]:
print_elements(data, strides+1, dimensions+1, nd-1, elsize, dtype)
data = data + strides[0]
def test_methods(ndarray arr):
"""Test a few attribute accesses for an array.
This illustrates how the pyrex-visible object is in practice a strange
hybrid of the C PyArrayObject struct and the python object. Some
properties (like .nd) are visible here but not in python, while others
like flags behave very differently: in python flags appears as a separate,
object while here we see the raw int holding the bit pattern.
This makes sense when we think of how pyrex resolves arr.foo: if foo is
listed as a field in the ndarray struct description, it will be directly
accessed as a C variable without going through Python at all. This is why
for arr.flags, we see the actual int which holds all the flags as bit
fields. However, for any other attribute not listed in the struct, it
simply forwards the attribute lookup to python at runtime, just like python
would (which means that AttributeError can be raised for non-existent
attributes, for example)."""
print 'arr.any() :',arr.any()
print 'arr.nd :',arr.nd
print 'arr.flags :',arr.flags
def test():
"""this function is pure Python"""
arr1 = np.array(-1e-30,dtype=np.float64)
arr2 = np.array([1.0,2.0,3.0],dtype=np.float64)
arr3 = np.arange(9,dtype=np.float64)
arr3.shape = 3,3
four = 4
arr4 = np.array(['one','two',3,four],dtype=np.object_)
arr5 = np.array([1,2,3]) # int types not (yet) supported by print_elements
for arr in [arr1,arr2,arr3,arr4,arr5]:
print_array_info(arr)
|