<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 鍵入的內存視圖 > 原文: [http://docs.cython.org/en/latest/src/userguide/memoryviews.html](http://docs.cython.org/en/latest/src/userguide/memoryviews.html) 類型化的內存視圖允許有效訪問內存緩沖區,例如 NumPy 陣列的內存緩沖區,而不會產生任何 Python 開銷。 Memoryview 類似于當前的 NumPy 陣列緩沖支持(`np.ndarray[np.float64_t, ndim=2]`),但它們具有更多功能和更清晰的語法。 Memoryview 比舊的 NumPy 陣列緩沖支持更通用,因為它們可以處理更多種類的數據源。例如,它們可以處理 C 數組和 Cython 數組類型( [Cython 數組](#view-cython-arrays) )。 memoryview 可以在任何上下文中使用(函數參數,模塊級,cdef 類屬性等),并且幾乎可以通過 [PEP 3118](https://www.python.org/dev/peps/pep-3118/) 緩沖區接口從任何暴露可寫緩沖區的對象中獲取。 ## 快速入門 如果您習慣使用 NumPy,以下示例將使您開始使用 Cython 內存視圖。 ```py from cython.view cimport array as cvarray import numpy as np # Memoryview on a NumPy array narr = np.arange(27, dtype=np.dtype("i")).reshape((3, 3, 3)) cdef int [:, :, :] narr_view = narr # Memoryview on a C array cdef int carr[3][3][3] cdef int [:, :, :] carr_view = carr # Memoryview on a Cython array cyarr = cvarray(shape=(3, 3, 3), itemsize=sizeof(int), format="i") cdef int [:, :, :] cyarr_view = cyarr # Show the sum of all the arrays before altering it print("NumPy sum of the NumPy array before assignments: %s" % narr.sum()) # We can copy the values from one memoryview into another using a single # statement, by either indexing with ... or (NumPy-style) with a colon. carr_view[...] = narr_view cyarr_view[:] = narr_view # NumPy-style syntax for assigning a single value to all elements. narr_view[:, :, :] = 3 # Just to distinguish the arrays carr_view[0, 0, 0] = 100 cyarr_view[0, 0, 0] = 1000 # Assigning into the memoryview on the NumPy array alters the latter print("NumPy sum of NumPy array after assignments: %s" % narr.sum()) # A function using a memoryview does not usually need the GIL cpdef int sum3d(int[:, :, :] arr) nogil: cdef size_t i, j, k, I, J, K cdef int total = 0 I = arr.shape[0] J = arr.shape[1] K = arr.shape[2] for i in range(I): for j in range(J): for k in range(K): total += arr[i, j, k] return total # A function accepting a memoryview knows how to use a NumPy array, # a C array, a Cython array... print("Memoryview sum of NumPy array is %s" % sum3d(narr)) print("Memoryview sum of C array is %s" % sum3d(carr)) print("Memoryview sum of Cython array is %s" % sum3d(cyarr)) # ... and of course, a memoryview. print("Memoryview sum of C memoryview is %s" % sum3d(carr_view)) ``` 此代碼應提供以下輸出: ```py NumPy sum of the NumPy array before assignments: 351 NumPy sum of NumPy array after assignments: 81 Memoryview sum of NumPy array is 81 Memoryview sum of C array is 451 Memoryview sum of Cython array is 1351 Memoryview sum of C memoryview is 451 ``` ## 使用記憶庫視圖 ### 語法 內存視圖以與 NumPy 類似的方式使用 Python 切片語法。 要在一維 int 緩沖區上創建完整視圖: ```py cdef int[:] view1D = exporting_object ``` 完整的 3D 視圖: ```py cdef int[:,:,:] view3D = exporting_object ``` 它們也可以方便地作為函數參數: ```py def process_3d_buffer(int[:,:,:] view not None): ... ``` 參數的`not None`聲明自動拒絕 None 值作為輸入,否則將允許。默認情況下允許 None 的原因是它可以方便地用于返回參數: ```py import numpy as np def process_buffer(int[:,:] input_view not None, int[:,:] output_view=None): if output_view is None: # Creating a default view, e.g. output_view = np.empty_like(input_view) # process 'input_view' into 'output_view' return output_view ``` Cython 將自動拒絕不兼容的緩沖區,例如將三維緩沖區傳遞給需要二維緩沖區的函數會產生`ValueError`。 ### 索引 在 Cython 中,內存視圖上的索引訪問會自動轉換為內存地址。以下代碼請求 C `int`類型的項目和索引的二維內存視圖: ```py cdef int[:,:] buf = exporting_object print(buf[1,2]) ``` 負指數也起作用,從相應維度的末尾開始計算: ```py print(buf[-1,-2]) ``` 以下函數循環遍歷 2D 數組的每個維度,并為每個項目添加 1: ```py import numpy as np def add_one(int[:,:] buf): for x in range(buf.shape[0]): for y in range(buf.shape[1]): buf[x, y] += 1 # exporting_object must be a Python object # implementing the buffer interface, e.g. a numpy array. exporting_object = np.zeros((10, 20), dtype=np.intc) add_one(exporting_object) ``` 索引和切片可以在有或沒有 GIL 的情況下完成。它基本上像 NumPy 一樣工作。如果為每個維度指定了索引,您將獲得基本類型的元素(例如 &lt;cite&gt;int&lt;/cite&gt; )。否則,您將獲得一個新視圖。省略號表示您為每個未指定的維度獲取連續切片: ```py import numpy as np exporting_object = np.arange(0, 15 * 10 * 20, dtype=np.intc).reshape((15, 10, 20)) cdef int[:, :, :] my_view = exporting_object # These are all equivalent my_view[10] my_view[10, :, :] my_view[10, ...] ``` ### 復制 內存視圖可以復制到位: ```py import numpy as np cdef int[:, :, :] to_view, from_view to_view = np.empty((20, 15, 30), dtype=np.intc) from_view = np.ones((20, 15, 30), dtype=np.intc) # copy the elements in from_view to to_view to_view[...] = from_view # or to_view[:] = from_view # or to_view[:, :, :] = from_view ``` 也可以使用`copy()`和`copy_fortran()`方法復制它們;見 [C 和 Fortran 連續拷貝](#view-copy-c-fortran) 。 ### 轉置 在大多數情況下(見下文),內存視圖的轉置方式與 NumPy 切片可以轉置的方式相同: ```py import numpy as np array = np.arange(20, dtype=np.intc).reshape((2, 10)) cdef int[:, ::1] c_contig = array cdef int[::1, :] f_contig = c_contig.T ``` 這為數據提供了一個新的轉置視圖。 轉置要求存儲器視圖的所有維度都具有直接存取存儲器布局(即,沒有通過指針的間接指令)。有關詳細信息,請參閱 [指定更一般的存儲器布局](#view-general-layouts) 。 ### Newaxis 對于 NumPy,可以通過使用`None`索引數組來引入新軸 ```py cdef double[:] myslice = np.linspace(0, 10, num=50) # 2D array with shape (1, 50) myslice[None] # or myslice[None, :] # 2D array with shape (50, 1) myslice[:, None] # 3D array with shape (1, 10, 1) myslice[None, 10:-20:2, None] ``` 可以將新的軸索引與所有其他形式的索引和切片混合。另見[示例](https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html)。 ### 只讀視圖 從 Cython 0.28 開始,memoryview 項類型可以聲明為`const`以支持只讀緩沖區作為輸入: ```py import numpy as np cdef const double[:] myslice # const item type => read-only view a = np.linspace(0, 10, num=50) a.setflags(write=False) myslice = a ``` 使用帶有二進制 Python 字符串的非 const 內存視圖會產生運行時錯誤。您可以使用`const`內存視圖解決此問題: ```py cdef bint is_y_in(const unsigned char[:] string_view): cdef int i for i in range(string_view.shape[0]): if string_view[i] == b'y': return True return False print(is_y_in(b'hello world')) # False print(is_y_in(b'hello Cython')) # True ``` 注意,這不是 _ 要求 _ 輸入緩沖區是只讀的: ```py a = np.linspace(0, 10, num=50) myslice = a # read-only view of a writable buffer ``` `const`視圖仍然接受可寫緩沖區,但非 const,可寫視圖不接受只讀緩沖區: ```py cdef double[:] myslice # a normal read/write memory view a = np.linspace(0, 10, num=50) a.setflags(write=False) myslice = a # ERROR: requesting writable memory view from read-only buffer! ``` ## 與舊緩沖支持的比較 您可能更喜歡使用舊視圖的內存視圖,因為: * 語法更清晰 * Memoryview 通常不需要 GIL(參見 [Memoryviews 和 GIL](#view-needs-gil)) * 記憶視圖要快得多 例如,這是上面`sum3d`函數的舊語法等價物: ```py cpdef int old_sum3d(object[int, ndim=3, mode='strided'] arr): cdef int I, J, K, total = 0 I = arr.shape[0] J = arr.shape[1] K = arr.shape[2] for i in range(I): for j in range(J): for k in range(K): total += arr[i, j, k] return total ``` 請注意,我們不能像上面`sum3d`的 memoryview 版本那樣使用`nogil`作為函數的緩沖版本,因為緩沖區對象是 Python 對象。但是,即使我們不將`nogil`與 memoryview 一起使用,它也要快得多。這是導入兩個版本后 IPython 會話的輸出: ```py In [2]: import numpy as np In [3]: arr = np.zeros((40, 40, 40), dtype=int) In [4]: timeit -r15 old_sum3d(arr) 1000 loops, best of 15: 298 us per loop In [5]: timeit -r15 sum3d(arr) 1000 loops, best of 15: 219 us per loop ``` ## Python 緩沖支持 Cython 內存視圖幾乎支持導出 Python [新樣式緩沖區](https://docs.python.org/3/c-api/buffer.html)接口的所有對象。這是 [PEP 3118](https://www.python.org/dev/peps/pep-3118/) 中描述的緩沖接口。 NumPy 數組支持此接口, [Cython 數組](#view-cython-arrays) 也是如此。 “幾乎所有”是因為 Python 緩沖區接口允許數據數組中的 _ 元素 _ 本身成為指針; Cython 的內存視圖還不支持這一點。 ## 存儲器布局 緩沖區接口允許對象以各種方式識別底層內存。除了數據元素的指針外,Cython 內存視圖支持所有 Python 新型緩沖區布局。如果內存必須是外部例程的特定格式或代碼優化,則了解或指定內存布局可能很有用。 ### 背景 概念如下:有數據訪問和數據打包。數據訪問意味著直接(無指針)或間接(指針)。數據打包意味著您的數據在內存中可能是連續的或不連續的,并且可以使用 _ 步幅 _ 來識別連續索引需要為每個維度進行的內存跳轉。 NumPy 數組提供了一個良好的跨步直接數據訪問模型,因此我們將使用它們來更新 C 和 Fortran 連續數組的概念以及數據步幅。 ### 簡要概述 C,Fortran 和跨步存儲器布局 最簡單的數據布局可能是 C 連續數組。這是 NumPy 和 Cython 數組中的默認布局。 C 連續意味著陣列數據在存儲器中是連續的(見下文),并且陣列的第一維中的相鄰元素在存儲器中是最遠的,而最后維中的相鄰元素最接近在一起。例如,在 NumPy 中: ```py In [2]: arr = np.array([['0', '1', '2'], ['3', '4', '5']], dtype='S1') ``` 這里,`arr[0, 0]`和`arr[0, 1]`在存儲器中相隔一個字節,而`arr[0, 0]`和`arr[1, 0]`相距 3 個字節。這引出了我們 _ 步幅 _ 的想法。數組的每個軸都有一個步長,這是從該軸上的一個元素到下一個元素所需的字節數。在上面的例子中,軸 0 和 1 的步幅顯然是: ```py In [3]: arr.strides Out[4]: (3, 1) ``` 對于 3D C 連續數組: ```py In [5]: c_contig = np.arange(24, dtype=np.int8).reshape((2,3,4)) In [6] c_contig.strides Out[6]: (12, 4, 1) ``` Fortran 連續數組具有相反的內存排序,第一個軸上的元素在內存中最接近: ```py In [7]: f_contig = np.array(c_contig, order='F') In [8]: np.all(f_contig == c_contig) Out[8]: True In [9]: f_contig.strides Out[9]: (1, 2, 6) ``` 連續數組是單個連續存儲器塊包含數組元素的所有數據的數組,因此存儲器塊長度是數組中元素數量和元素大小(以字節為單位)的乘積。在上面的示例中,內存塊長度為 2 * 3 * 4 * 1 個字節,其中 1 是 int8 的長度。 數組可以是連續的而不是 C 或 Fortran 順序: ```py In [10]: c_contig.transpose((1, 0, 2)).strides Out[10]: (4, 12, 1) ``` 切片 NumPy 數組很容易使它不連續: ```py In [11]: sliced = c_contig[:,1,:] In [12]: sliced.strides Out[12]: (12, 1) In [13]: sliced.flags Out[13]: C_CONTIGUOUS : False F_CONTIGUOUS : False OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False ``` ### 內存視圖布局的默認行為 正如您在 [中看到的那樣,指定更一般的內存布局](#view-general-layouts) ,您可以為內存視圖的任何維度指定內存布局。對于未指定布局的任何維度,假定數據訪問是直接的,并假設數據打包是跨越的。例如,這將是內存視圖的假設,如: ```py int [:, :, :] my_memoryview = obj ``` ### C 和 Fortran 連續的內存視圖 您可以使用定義中的`::1`步驟語法為內存視圖指定 C 和 Fortran 連續布局。例如,如果您確定您的內存視圖將位于 3D C 連續布局之上,您可以編寫: ```py cdef int[:, :, ::1] c_contiguous = c_contig ``` 其中`c_contig`可以是 C 連續的 NumPy 數組。第 3 位的`::1`意味著該第 3 維中的元素將是存儲器中的一個元素。如果您知道將擁有 3D Fortran 連續數組: ```py cdef int[::1, :, :] f_contiguous = f_contig ``` 例如,如果傳遞非連續緩沖區 ```py # This array is C contiguous c_contig = np.arange(24).reshape((2,3,4)) cdef int[:, :, ::1] c_contiguous = c_contig # But this isn't c_contiguous = np.array(c_contig, order='F') ``` 你會在運行時得到`ValueError`: ```py /Users/mb312/dev_trees/minimal-cython/mincy.pyx in init mincy (mincy.c:17267)() 69 70 # But this isn't ---> 71 c_contiguous = np.array(c_contig, order='F') 72 73 # Show the sum of all the arrays before altering it /Users/mb312/dev_trees/minimal-cython/stringsource in View.MemoryView.memoryview_cwrapper (mincy.c:9995)() /Users/mb312/dev_trees/minimal-cython/stringsource in View.MemoryView.memoryview.__cinit__ (mincy.c:6799)() ValueError: ndarray is not C-contiguous ``` 因此,切片類型規范中的 &lt;cite&gt;:: 1&lt;/cite&gt; 指示數據在哪個維度上是連續的。它只能用于指定完整的 C 或 Fortran 連續性。 ### C 和 Fortran 連續副本 可以使用`.copy()`和`.copy_fortran()`方法使 C 或 Fortran 連續復制: ```py # This view is C contiguous cdef int[:, :, ::1] c_contiguous = myview.copy() # This view is Fortran contiguous cdef int[::1, :] f_contiguous_slice = myview.copy_fortran() ``` ### 指定更一般的內存布局 可以使用先前看到的`::1`切片語法或使用`cython.view`中的任何常量指定數據布局。如果在任何維度中都沒有給出說明符,則假定數據訪問是直接的,并假設數據打包是跨步的。如果你不知道維度是直接的還是間接的(因為你可能從某個庫得到一個帶緩沖接口的對象),那么你可以指定&lt;cite&gt;泛型&lt;/cite&gt;標志,在這種情況下它將在運行時確定。 標志如下: * 通用 - 跨步,直接或間接 * 跨步 - 跨步(直接)(這是默認值) * 間接 - 跨步和間接的 * 連續的 - 連續的和直接的 * indirect_contiguous - 指針列表是連續的 它們可以像這樣使用: ```py from cython cimport view # direct access in both dimensions, strided in the first dimension, contiguous in the last cdef int[:, ::view.contiguous] a # contiguous list of pointers to contiguous lists of ints cdef int[::view.indirect_contiguous, ::1] b # direct or indirect in the first dimension, direct in the second dimension # strided in both dimensions cdef int[::view.generic, :] c ``` 只有間接維度后面的第一個,最后一個或維度可以指定為連續的: ```py from cython cimport view # VALID cdef int[::view.indirect, ::1, :] a cdef int[::view.indirect, :, ::1] b cdef int[::view.indirect_contiguous, ::1, :] c ``` ```py # INVALID cdef int[::view.contiguous, ::view.indirect, :] d cdef int[::1, ::view.indirect, :] e ``` &lt;cite&gt;連續&lt;/cite&gt;標志和 &lt;cite&gt;:: 1&lt;/cite&gt; 說明符之間的區別在于前者僅指定一個維度的鄰接,而后者指定所有后續(Fortran)或前一個(C)的鄰接。 )尺寸: ```py cdef int[:, ::1] c_contig = ... # VALID cdef int[:, ::view.contiguous] myslice = c_contig[::2] # INVALID cdef int[:, ::1] myslice = c_contig[::2] ``` 前一種情況是有效的,因為最后一個維度仍然是連續的,但是第一個維度不再“跟隨”最后一個維度(意思是,它已經跨越了,但它不再是 C 或 Fortran 連續),因為它被切成了。 ## Memoryviews 和 GIL 正如您將從 [快速入門](#view-quickstart) 部分中看到的那樣,內存視圖通常不需要 GIL: ```py cpdef int sum3d(int[:, :, :] arr) nogil: ... ``` 特別是,您不需要 GIL 進行內存視圖索引,切片或轉置。 Memoryviews 需要 GIL 用于復制方法( [C 和 Fortran 連續拷貝](#view-copy-c-fortran) ),或者當 dtype 是對象并且讀取或寫入對象元素時。 ## Memoryview 對象和 Cython 陣列 這些類型化的內存視圖可以轉換為 Python 內存視圖對象( &lt;cite&gt;cython.view.memoryview&lt;/cite&gt; )。這些 Python 對象可以像原始內存視圖一樣進行索引,可切片和轉換。它們也可以隨時轉換回 Cython 空間的內存視圖。 它們具有以下屬性: > * `shape`:每個維度的大小,作為元組。 > * `strides`:沿每個維度跨步,以字節為單位。 > * `suboffsets` > * `ndim`:維數。 > * `size`:視圖中的項目總數(形狀的乘積)。 > * `itemsize`:視圖中項目的大小(以字節為單位)。 > * `nbytes`:等于`size`乘以`itemsize`。 > * `base` 當然還有前面提到的`T`屬性( [Transposing](#view-transposing))。這些屬性與 [NumPy](https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html#memory-layout) 具有相同的語義。例如,要檢索原始對象: ```py import numpy cimport numpy as cnp cdef cnp.int32_t[:] a = numpy.arange(10, dtype=numpy.int32) a = a[::2] print(a) print(numpy.asarray(a)) print(a.base) # this prints: # <MemoryView of 'ndarray' object> # [0 2 4 6 8] # [0 1 2 3 4 5 6 7 8 9] ``` 請注意,此示例返回從中獲取視圖的原始對象,并在此期間重新查看視圖。 ## Cython 數組 每當復制 Cython 內存視圖時(使用任何&lt;cite&gt;副本&lt;/cite&gt;或 &lt;cite&gt;copy_fortran&lt;/cite&gt; 方法),您將獲得新創建的`cython.view.array`對象的新內存視圖片段。此數組也可以手動使用,并自動分配數據塊。稍后可以將其分配給 C 或 Fortran 連續切片(或跨步切片)。它可以像: ```py from cython cimport view my_array = view.array(shape=(10, 2), itemsize=sizeof(int), format="i") cdef int[:, :] my_slice = my_array ``` 它還需要一個可選參數&lt;cite&gt;模式&lt;/cite&gt;('c'或'fortran')和一個布爾 &lt;cite&gt;allocate_buffer&lt;/cite&gt; ,它指示緩沖區是否應該在超出范圍時分配和釋放: ```py cdef view.array my_array = view.array(..., mode="fortran", allocate_buffer=False) my_array.data = <char *> my_data_pointer # define a function that can deallocate the data (if needed) my_array.callback_free_data = free ``` 您還可以將指針轉換為數組,或將 C 數組轉換為數組: ```py cdef view.array my_array = <int[:10, :2]> my_data_pointer cdef view.array my_array = <int[:, :]> my_c_array ``` 當然,您也可以立即將 cython.view.array 分配給類型化的 memoryview 切片。可以將 C 數組直接分配給 memoryview 切片: ```py cdef int[:, ::1] myslice = my_2d_c_array ``` 這些數組可以像 Python 內存對象一樣從 Python 空間進行索引和切片,并且具有與 memoryview 對象相同的屬性。 ## Python 數組模塊 `cython.view.array`的替代方案是 Python 標準庫中的`array`模塊。在 Python 3 中,`array.array`類型本身支持緩沖區接口,因此內存視圖無需額外設置即可在其上工作。 但是,從 Cython 0.17 開始,可以在 Python 2 中使用這些數組作為緩沖提供程序。這是通過顯式 cimporting `cpython.array`模塊完成的,如下所示: ```py cimport cpython.array def sum_array(int[:] view): """ >>> from array import array >>> sum_array( array('i', [1,2,3]) ) 6 """ cdef int total for i in range(view.shape[0]): total += view[i] return total ``` 請注意,cimport 還為數組類型啟用舊的緩沖區語法。因此,以下也有效: ```py from cpython cimport array def sum_array(array.array[int] arr): # using old buffer syntax ... ``` ## 強制到 NumPy Memoryview(和數組)對象可以強制轉換為 NumPy ndarray,而無需復制數據。你可以,例如做: ```py cimport numpy as np import numpy as np numpy_array = np.asarray(<np.int32_t[:10, :10]> my_pointer) ``` 當然,您不限于使用 NumPy 的類型(例如此處的`np.int32_t`),您可以使用任何可用的類型。 ## 無切片 盡管 memoryview 切片不是對象,但它們可以設置為 None,并且可以檢查它們是否為 None: ```py def func(double[:] myarray = None): print(myarray is None) ``` 如果函數需要實內存視圖作為輸入,則最好在簽名中直接拒絕 None 輸入,這在 Cython 0.17 及更高版本中受支持,如下所示: ```py def func(double[:] myarray not None): ... ``` 與擴展類的對象屬性不同,memoryview 切片不會初始化為 None。 ## 通過指針從 C 函數傳遞數據 由于在 C 中使用指針是無處不在的,這里我們給出一個快速示例,說明如何調用其參數包含指針的 C 函數。假設您想要使用 NumPy 管理數組(分配和釋放)(它也可以是 Python 數組,或者任何支持緩沖區接口的數組),但是您希望使用`C_func_file.c`中實現的外部 C 函數對此數組執行計算]: | ```py 1 2 3 4 5 6 7 8 9 ``` | ```py #include "C_func_file.h" void multiply_by_10_in_C(double arr[], unsigned int n) { unsigned int i; for (i = 0; i &lt; n; i++) { arr[i] *= 10; } } ``` | 此文件附帶一個名為`C_func_file.h`的頭文件,其中包含: | ```py 1 2 3 4 5 6 ``` | ```py #ifndef C_FUNC_FILE_H #define C_FUNC_FILE_H void multiply_by_10_in_C(double arr[], unsigned int n); #endif ``` | 其中`arr`指向數組,`n`是其大小。 您可以通過以下方式在 Cython 文件中調用該函數: | ```py 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 ``` | ```py cdef extern from "C_func_file.c": # C is include here so that it doesn't need to be compiled externally pass cdef extern from "C_func_file.h": void multiply_by_10_in_C(double *, unsigned int) import numpy as np def multiply_by_10(arr): # 'arr' is a one-dimensional numpy array if not arr.flags['C_CONTIGUOUS']: arr = np.ascontiguousarray(arr) # Makes a contiguous copy of the numpy array. cdef double[::1] arr_memview = arr multiply_by_10_in_C(&arr_memview[0], arr_memview.shape[0]) return arr a = np.ones(5, dtype=np.double) print(multiply_by_10(a)) b = np.ones(10, dtype=np.double) b = b[::2] # b is not contiguous. print(multiply_by_10(b)) # but our function still works as expected. ``` | Several things to note: * `::1`請求 C 連續視圖,如果緩沖區不是 C 連續則失敗。參見 [C 和 Fortran 連續記憶視圖](#c-and-fortran-contiguous-memoryviews) 。 * `&arr_memview[0]`可以理解為'存儲器視圖的第一個元素的地址'。對于連續數組,這相當于平坦內存緩沖區的起始地址。 * `arr_memview.shape[0]`可能被`arr_memview.size`,`arr.shape[0]`或`arr.size`取代。但`arr_memview.shape[0]`更有效,因為它不需要任何 Python 交互。 * 如果傳遞的數組是連續的,`multiply_by_10`將就地執行計算,如果`arr`不連續,它將返回一個新的 numpy 數組。 * 如果您使用的是 Python 數組而不是 numpy 數組,則無需檢查數據是否連續存儲,因為總是如此。參見 [使用 Python 數組](../tutorial/array.html#array-array) 。 這樣,您可以調用類似于普通 Python 函數的 C 函數,并將所有內存管理和清理留給 NumPy 數組和 Python 的對象處理。有關如何在 C 文件中編譯和調用函數的詳細信息,請參閱 [使用 C 庫](../tutorial/clibraries.html#using-c-libraries) 。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看