第十七章 擴展Python

第十七章

Python什么都能做,真的是這樣。這門語言功能強大,但有時候速度有點慢

魚和熊掌兼得

本章討論確實需要進一步提升速度的情形。在這種情況下,最佳的解決方案可能不是完全轉向C語言(或其他中低級語言),建議你采用下面的方法(這可滿足眾多的速度至上需求)。

  1. 使用Python開發原型(有關原型開發的詳細信息,請參閱第19章)。
  2. 對程序進行性能分析以找出瓶頸(有關測試,請參閱第16章)。
  3. 使用C(或者C++、C#、Java、Fortran等)擴展重寫瓶頸部分。
    這樣得到的架構(包含一個或多個C語言組件的Python框架)將非常強大,因為它兼具這兩門語言的優點。

簡單易行的方式:Jython 和 IronPython

使用Jython(http://jython.org)或IronPython(http://ironpython.net),可輕松地使用原生模塊來擴展Python。
Jython和IronPython能夠讓你訪問底層語言中的模塊和類(對Jython來說,底層語言為Java;對IronPython來說,為C#和其他.NET語言)

一個簡單的Java類(JythonTest.java)

public class JythonTest {public void greeting() {System.out.println("Hello, world!")}
}

使用Java編譯器(如javac)來編譯這個類。javac JythonTest.java

編譯這個類后,啟動Jython(并將.class文件放到當前目錄或Java CLASSPATH包含的目錄中)
CLASSPATH=JythonTest.class jython

然后,就可直接導入這個類了。

import JythonTest
test = JythonTest()
test.greeting()#輸出結果如下:
'''
Hello, world!
'''

一個簡單的C#類(IronPythonTest.cs)

using System;
namespace FePyTest {public class IronPythonTest {public void greeting() {Console.WriteLine("Hello, world!");}}
}

選擇的編譯器來編譯這個類,對于Microsoft .NET,命令如下:csc.exe /t:library IronPythonTest.cs
要在IronPython中使用這個類,一種方法是將其編譯為動態鏈接庫(DLL),并根據需要修改相關的環境變量(如PATH),然后就應該能夠像下面這樣使用它了(這里使用的是IronPython交互式解釋器):

import clr
clr.AddReferenceToFile("IronPythonTest.dll")
import FePyTest
f = FePyTest.IronPythonTest()
f.greeting()

編寫C語言擴展

擴展Python通常意味著擴展CPython——使用編程語言C實現的Python標準版

C語言的動態性不如Java和C#,而且對Python來說,編譯后的C語言代碼也不那么容易理解。因此,使用C語言編寫Python擴展時,必須遵循嚴格的API。

其他方法
使用Cpython,有很多工具可幫助提高程序的速度,這是通過生成和使用C語言庫或提高Python代碼的速度實現的。

工具描述
Cython(http://cython.org)這其實是一個Python編譯器!它還提供了擴展的Cython語言,該語言基于Greg Ewing開發的項目Pyrex,讓你能夠使用類似于Python的語法添加類型聲明和定義C類型。因此,它的效率非常高,并且能夠很好地與C擴展模塊(包括Numpy)交互。
PyPy(http://pypy.org)這是一個雄心勃勃而有遠見的Python實現——使用的是Python。這種實現好像會慢如蝸牛,但通過極其復雜的代碼分析和編譯,其性能實際上超過了CPython。其官網指出:“有傳言說PyPy的秘密目標是在速度上超過C語言,這是無稽之談,不是嗎?”PyPy的核心是RPython——一種受限的Python方言。RPython擅長自動類型推斷等,可轉換為靜態語言、機器碼和其他動態語言(如JavaScript)。
Weave(http://scipy.org)SciPy發布版的一部分,也有單獨的安裝包。這個工具讓你能夠在Python代碼中以字符串的方式直接包含C或C++代碼,并無縫地編譯和執行這些代碼。例如,要快速計算一些數學表達式,就可使用這個工具。Weave還可提高使用數字數組的表達式的計算速度。
NumPy(http://numpy.org)NumPy讓你能夠使用數字數組,這對分析各種形式的數值數據(從股票價值到天文圖像)很有幫助。NumPy的優點之一是接口簡單,無需顯式地指定眾多低級操作。然而,NumPy的主要優點是速度快。對數字數組中的每個元素執行很多常見操作時,速度都比使用列表和for循環執行同樣的操作快得多,這是因為隱式循環是直接使用C語言實現的。數字數組能夠很好地與Cython和Weave協同工作。
ctypes(https://docs.python.org/library/ctypes.html)模塊ctypes最初是Thomas Heller開發的一個項目,但現在包含在標準庫中。它采用直截了當的方法——能夠導入既有(共享)的C語言庫。雖然存在一些限制,但這可能是訪問C語言代碼的最簡單方式之一。不需要包裝器,也不需要特殊API,只需將庫導入就可使用。
subprocess(https://docs.python.org/3/library/subprocess.html)模塊subprocess包含在標準庫中(標準庫中還有一些較老的模塊和函數提供了類似的功能)。它讓你能夠在Python中運行外部程序,并通過命令行參數以及標準輸入、輸出和錯誤流與它們通信。如果對速度要求極高的代碼可使用幾個批處理作業來完成大部分工作,啟動外部程序并與之通信所需的時間將很短。在這種情況下,將C語言代碼放在獨立的程序中并將其作為子進程運行很可能是最整潔的解決方案。
PyCXX(http://cxx.sourceforge.net)以前名為CXX或CXX/Objects,是一組幫助使用C++編寫Python擴展的工具。例如,它提供了良好的引用計數支持,可減少犯錯的機會。
SIP(http://www.riverbankcomputing.co.uk/software/sip)SIP最初是一個開發GUI包PyQt的工具,包含一個代碼生成器和一個Python模塊。它像SWIG那樣使用規范文件。
Boost.Python(http://www.boost.org/libs/python/doc)Boost.Python讓Python和C++能夠無縫地互操作,可為你解決引用計數和在C++中操作Python對象提供極大的幫助。一種使用它的主要方式是,以類似于Python的方式編寫C++代碼(Boost.Python中的宏為此提供了支持),再使用你喜歡的C++編譯器將這些代碼編譯成Python擴展。它雖然與SWIG有天壤之別,卻能很好地替代SWIG,因此很值得你研究研究。

SWIG

SWIG(http://www.swig.org)指的是簡單包裝器和接口生成器(simple wrapper and interfacegenerator),是一個適用于多種語言的工具。
一方面,它夠使用C或C++編寫擴展代碼;
另一方面,它自動包裝這些代碼,能夠在Tcl、Python、Perl、Ruby和Java等高級語言中使用它們。

SWIG使用起來很簡單,前提條件是有一些C語言代碼

1,用法
(1),為代碼編寫一個接口文件。這很像C語言頭文件(在比較簡單的情況下,可直接使用現有的頭文件)。
(2),對接口文件運行SWIG,以自動生成一些額外的C語言代碼(包裝器代碼)。
(3),將原來的C語言代碼和生成的包裝器代碼一起編譯,以生成共享庫。

2,回文
回文(palindrome;如I prefer pi)是忽略空格、標點等后正著讀和反著讀一樣的句子。

一個簡單的檢測回文的C語言函數(palindrome.c)

#include <string.h>
int is_palindrome(char *text) {int i, n=strlen(text);for (i = 0; I <= n/2; ++i) {if (text[i] != text[n-i-1]) return 0;}return 1;
}

檢測回文的Python函數

def is_palindrome(text):n = len(text)for i in range(len(text) // 2):if text[i] != text[n-i-1]:return Falsereturn True

3,接口文件
假設代碼存儲在文件palindrome.c中,現在應該在文件palindrome.i中添加接口描述。

如果定義一個頭文件(這里為palindrome.h),SWIG可能能夠從中獲取所需的信息。

在接口文件中,只是聲明要導出的函數(和變量),就像在頭文件中一樣。

在接口文件的開頭,有一個由%{和%}界定的部分,可在其中指定要包含的頭文件(這里為string.h),%module聲明,用于指定模塊名。

回文檢測庫的接口(palindrome.i)

%module palindrome%{
#include <string.h>
%}extern int is_palindrome(char *text);

4,運行SWIG
運行SWIG時,需要將接口文件(也可以是頭文件)作為參數
$ swig -python palindrome.i

這將生成兩個新文件,分別是palindrome_wrap.cpalindrome.py

5,編譯、鏈接和使用
在Linux中使用編譯器gcc

$ gcc -c palindrome.c 
$ gcc -I$PYTHON_HOME -I$PYTHON_HOME/Include -c palindrome_wrap.c 
$ gcc -shared palindrome.o palindrome_wrap.o -o _palindrome.so

將得到一個很有用的文件_palindrome.so。它就是共享庫,可直接導入到Python中(條件是它位于PYTHONPATH包含的目錄中,如當前目錄中)

import _palindrome
dir(_palindrome)#結果為:['__doc__', '__file__', '__name__', 'is_palindrome']
_palindrome.is_palindrome('ipreferpi')#結果為:1
_palindrome.is_palindrome('notlob')#結果為:0

6,穿越編譯器“魔法森林”的捷徑
通過使用Setuptools,直接支持SWIG,讓你無需手工運行SWIG:只需編寫代碼和接口文件,再運行安裝腳本。

手工編寫擴展

SWIG在幕后做了很多工作,但并非每項工作都是絕對必要的。
如果你愿意,可自己編寫包裝代碼,也可在C語言代碼中直接使用Python C API。
Python/C API參考手冊
標準庫參考手冊

1,引用計數
在Python中,內存管理是自動完成的:你只管創建對象,當你不再使用時它們就會消失。
在C語言中,必須顯式地釋放不再使用的對象(更準確地說是內存塊),否則程序占用的內存將越來越多,這稱為內存泄漏(memory leak)。
可使用Python在幕后使用的內存管理工具,其中之一就是引用計數。
一個對象只要被代碼引用(在C語言中是有指向它的指針),就不應將其釋放。

為將對象的引用計數加1和減1,可使用兩個宏,分別是Py_INCREF和Py_DECREF。

  • 對象不歸你所有,但指向它的引用歸你所有。一個對象的引用計數是指向它的引用的數量。
  • 對于歸你所有的引用,你必須負責在不再需要它時調用Py_DECREF。
  • 對于你暫時借用的引用,不應在借用完后調用Py_DECREF,因為這是引用所有者的職責。
  • 可通過調用Py_INCREF將借來的引用變成自己的。這將創建一個新引用,而借來的引用依然歸原來的所有者所有。
  • 通過參數收到對象后,要轉移所有權(如將其存儲起來)還是僅僅借用完全由你決定,但應清楚地說明。如果函數將在Python中調用,完全可以只借用,因為對象在整個函數調用期間都存在。然而,如果函數將在C語言中調用,就無法保證對象在函數調用期間都存在,因此可能應該創建自己的引用,并在使用完畢后將其釋放。

再談垃圾收集
引用計數是一種垃圾收集方式,其中的術語“垃圾”指的是程序不再使用的對象。
循環垃圾,即兩個對象相互引用對方(導致它們的引用計數不為0),但沒有其他的對象引用它們。

2,擴展框架
必須先包含頭文件Python.h,再包含其他標準頭文件。

#include <Python.h>static PyObject *somename(PyObject *self, PyObject *args) {PyObject *result;Py_INCREF(result); /* 僅當需要時才這樣做!*/return result;
}int PyArg_ParseTuple(PyObject *args, char *format, ...);

3,回文
另一個回文檢查示例(palindrome2.c)

#include <Python.h>static PyObject *is_palindrome(PyObject *self, PyObject *args) {int i, n;const char *text;int result;if (!PyArg_ParseTuple(args, "s", &text)) {return NULL;}n=strlen(text);result = 1;for (i = 0; i <= n/2; ++i) {if (text[i] != text[n-i-1]) {result = 0;break;}}return Py_BuildValue("i", result); /* "i"表示一個整數:*/}static PyMethodDef PalindromeMethods[] = {/* 方法/函數列表:*/{"is_palindrome", is_palindrome, METH_VARARGS, "Detect palindromes"},{NULL, NULL, 0, NULL}
};static struct PyModuleDef palindrome =
{PyModuleDef_HEAD_INIT,"palindrome", /* 模塊名 */"", /* 文檔字符串 */-1, /*存儲在全局變量中的信號狀態 */PalindromeMethods
};/* 初始化模塊的函數:*/ 
PyMODINIT_FUNC PyInit_palindrome(void)
{return PyModule_Create(&palindrome);
}	

小結

概念描述
擴展理念Python擴展的主要用途有兩個——利用既有(遺留)代碼和提高瓶頸部分的速度。從頭開始編寫代碼時,請嘗試使用Python建立原型,找出其中的瓶頸并在需要時使用擴展來替換它們。預先將潛在的瓶頸封裝起來大有裨益。
Jython和IronPython對這些Python實現進行擴展很容易,使用底層語言(對于Jython,為Java;對于IronPython,為C#和其他.NET語言)以庫的方式實現擴展后,就可在Python中使用它們了。
擴展方法有很多用于擴展代碼或提高其速度的工具,有的讓你更輕松地在Python程序中嵌入C語言代碼,有的可提高數字數組操作等常見運算的速度,有的可提高Python本身的速度。這樣的工具包括SWIG、Cython、Weave、NumPy、ctypes和subprocess。
SWIGSWIG是一款自動為C語言庫生成包裝代碼的工具。包裝代碼自動處理Python CAPI,使你不必自己去做這樣的工作。使用SWIG是最簡單、最流行的擴展Python的方式之一。
使用Python/C API可手工編寫可作為共享庫直接導入到Python中的C語言代碼。為此,必須遵循Python/C API:對于每個函數,你都需要負責完成引用計數、提取參數以及創建返回值等工作;另外,還需編寫將C語言庫轉換為模塊的代碼,包括列出模塊中的函數以及創建模塊初始化函數。

本章介紹的新函數

函數描述
Py_INCREF(obj)將obj的引用計數加1
Py_DECREF(obj)將obj的引用計數減1
PyArg_ParseTuple(args, fmt, …)提取位置參數
PyArg_ParseTupleAndKeywords(args, kws, fmt, kwlist)提取位置參數和關鍵字參數
PyBuildValue(fmt, value)根據C語言值創建PyObject

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/378257.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/378257.shtml
英文地址,請注明出處:http://en.pswp.cn/news/378257.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

android studio資源二進制,無法自動檢測ADB二進制文件 – Android Studio

我嘗試在Android Studio上測試我的應用程序,但我遇到了困難"waiting for AVD to come online..."我讀過Android設備監視器重置adb會做到這一點,它確實……對于1次測試,當我第二天重新啟動電腦時,我不僅僅是&#xff1a;"waiting for AVD to come online..."…

犀牛腳本:仿迅雷的增強批量下載

迅雷的批量下載滿好用。但是有兩點我不太中意。在這個腳本里會有所增強 1、不能設置保存的文件名。2、不能單獨設置這批下載的線程限制。 使用方法 // 下載從編號001到編號020的圖片&#xff0c;保存名為貓咪寫真*.jpg 使用6個線程 jdlp http://bizhi.zhuoku.com/bizhi/200804/…

為什么使用1 * 1 的卷積核

為什么使用 1* 1卷積核&#xff1f; 作用&#xff1a; 1、實現跨通道的交互和信息整合 2、 進行卷積核通道數的降維和升維 3、 在保持feature map尺度不變的&#xff08;即不損失分辨率&#xff09;的前提下大幅增加非線性特性 跨通道的交互和信息整合 使用1 * 1卷積核&a…

KingPaper初探ThinkPHP3.1.2之擴展函數庫和類庫的使用(四)

在我們做項目的時候TP的系統函數或系統類庫滿足不了我們的需要 所以有些東西需要我們自己去定義&#xff0c;在TP中我們怎么使用自己的函數庫和類庫呢&#xff1f;在TP系統中提供了三個系統函數庫 common.php是全局必須加載的基礎函數庫&#xff0c;在任何時候都可以直接調用&a…

isfinite函數_isfinite()函數以及C ++中的示例

isfinite函數C isfinite()函數 (C isfinite() function) isfinite() function is a library function of cmath header, it is used to check whether the given value is a finite value or not? It accepts a value (float, double or long double) and returns 1 if the v…

android 服務端 漏洞,安卓漏洞 CVE 2017-13287 復現詳解-

2018年4月&#xff0c;Android安全公告公布了CVE-2017-13287漏洞。與同期披露的其他漏洞一起&#xff0c;同屬于框架中Parcelable對象的寫入(序列化)與讀出(反序列化)的不一致所造成的漏洞。在剛看到谷歌對于漏洞給出的補丁時一頭霧水&#xff0c;在這里要感謝heeeeenMS509Team…

某公司面試題

一、基礎題 1&#xff0c;馮諾依曼結構的計算機硬件邏輯組成中&#xff0c;不包含以下哪個模塊&#xff1f; A&#xff0c;編譯器 B&#xff0c;控制器 C&#xff0c;輸入設備 D&#xff0c;輸出設備 解釋&#xff1a;馮諾依曼由五個模塊組成&#xff1a;輸入設備 輸出設備 存…

GAP(全局平均池化層)操作

轉載的文章鏈接&#xff1a; 為什么使用全局平均池化層&#xff1f; 關于 global average pooling https://blog.csdn.net/qq_23304241/article/details/80292859 在卷積神經網絡的初期&#xff0c;卷積層通過池化層&#xff08;一般是 最大池化&#xff09;后總是要一個或n個全…

zoj1245 Triangles(DP)

/* 動態三角形&#xff1a;每次DP時考慮的是兩個子三角形的高度即可 注意&#xff1a; 三角形可以是倒置的。 */ View Code 1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <stdio.h> 5 6 using namespace std; 7 8…

第十八章 程序打包

第十八章 程序打包 Setuptools和較舊的Distutils都是用于發布Python包的工具包&#xff0c;能夠使用Python輕松地編寫安裝腳本。這些腳本可用于生成可發布的歸檔文檔&#xff0c;供用戶用來編譯和安裝編寫庫。 Setuptools并非只能用于創建基于腳本的Python安裝程序&#xff0…

如何在Java中檢查對象是否為空?

With the help of "" operator is useful for reference comparison and it compares two objects. 借助“ ”運算符&#xff0c;對于參考比較非常有用&#xff0c;它可以比較兩個對象。 "" operator returns true if both references (objects) points to…

android編程從零開始,從零開始學習android開發

博主最近開通了Android欄目&#xff0c;現在正在從零開始學習android&#xff0c;遇到的所有值得分享的知識點以及遇到的問題將發布在這個博客的android欄目下。因為我有著深厚的java底子&#xff0c;所以學習起來得心應手&#xff0c;十分的簡單&#xff0c;當然也只能算是入門…

CNN基本步驟以及經典卷積(LeNet、AlexNet、VGGNet、InceptionNet 和 ResNet)網絡講解以及tensorflow代碼實現

課程來源&#xff1a;人工智能實踐:Tensorflow筆記2 文章目錄前言1、卷積神經網絡的基本步驟1、卷積神經網絡計算convolution2、感受野以及卷積核的選取3、全零填充Padding4、tf描述卷積層5、批標準化(BN操作)6、池化Pooling7、舍棄Dropout8、卷積神經網絡搭建以及參數分析2、經…

String.valueOf()

1. 由 基本數據型態轉換成 String String 類別中已經提供了將基本數據型態轉換成 String 的 static 方法 也就是 String.valueOf() 這個參數多載的方法 有下列幾種 String.valueOf(boolean b) : 將 boolean 變量 b 轉換成字符串 String.valueOf(char c) : 將 char 變量 c 轉換成…

emacs gdb 調試

寫下linux下用emacs調用dgb調試的方法 emacs中使用gdb 說明C等價于ctrl M等價于alt 1,編寫 .c函數 test.c 2&#xff0c;gcc一把 看看對不對 帶上-g gcc -g -o test .debug test.c 如果要用gdb調試器&#xff0c;必須使用g選項。 3&#xff0c;#ema…

第十九章 趣味編程

第十九章 趣味編程 本章將介紹一些通用的Python編程指南。 為何要有趣 Python有趣的地方之一就是讓用戶的編程效率非常高效。 極限編程是一種軟件開發方法 編程柔術 python的靈活性描述原型設計Python的優點之一是讓你能夠快速地編寫程序。要更深入地了解面臨的問題&#…

android按鈕在容器下方,使用flex布局解決安卓手機上固定在底部的按鈕,在鍵盤彈起后擋住input輸入框的問題...

移動端經常會出現&#xff0c;一個表單里面&#xff0c;確定按鈕固定在底部這樣的布局&#xff0c;一般會讓按鈕absolute或者fixed&#xff0c;這樣在ios上沒有問題&#xff0c;但是在安卓手機上&#xff0c;當表單里面的input輸入框獲得焦點的時候&#xff0c;按鈕會擋在表單上…

dbms支持哪幾種數據模型_DBMS中不同類型的數據模型

dbms支持哪幾種數據模型資料模型 (Data Model) A data model is a model that defines in which format the data are represented and accessed. Data model mainly defines some of the data elements and relationships that exist between them. 數據模型是定義數據以哪種格…

JS 數組迭代方法

var arr [3,4,5,6,7,"a"]; var isNum function(elem,index,AAA){ return !isNaN(elem);} var toUpperCase function(elem){ return String.prototype.toUpperCase.apply(elem);} var print function(elem,index){ console.log(index"."elem);} /*對數組…

php開源問答_PHP基礎知識能力問答

php開源問答This section contains Aptitude Questions and Answers on PHP Basics. 本部分包含有關PHP基礎知識的 Aptitude問題和解答。 1) There are the following statements that are given below, which of them are correct PHP? PHP stands for the Preprocessor Hom…