为什么说Python无所不能?它几乎可以调用所有语言的程序和代码!
Python 常被称为是胶水语言,主要原因就是其对于系统命令、各种语言的代码和程序都具有良好的调用能力。这里列举了一些在 Windows 系统中,常见的接口与调用。在 Linux 中,实现起来都非常简单直接,符合直觉。在 Windows 中,程序、代码、动态链接库的调用相对比较复杂,因此 Python 的这种能力也格外地有用。 进群:548377875 ?即可获取数十套PDF哦! 示例 这里举一个在开源软件中实际应用的例子,是 matplotlib 中 imread 函数调用 pillow 图像读取代码的实例。 试着引入一个包来读图像,不成功就返回空。 def pilread(fname): """try to load the image with PIL or return None""" try: from PIL import Image except ImportError: return None with Image.open(fname) as image: return pil_to_array(image) 参见 GitHub 源码。 邪恶的小技巧
# Get the version from the _version.py versioneer file. For a git checkout,# this is computed based on the number of commits since the last tag. from ._version import get_versions __version__ = str(get_versions()['version']) del get_versions 参见 GitHub 源码。
_python27 = (sys.version_info.major == 2 and sys.version_info.minor >= 7) _python34 = (sys.version_info.major == 3 and sys.version_info.minor >= 4) if not (_python27 or _python34): raise ImportError("Matplotlib requires Python 2.7 or 3.4 or later") 参见 GitHub 源码。 用 Python 调用 exe话说有这么一个程序 cos_exe 可以求一个角度的余弦。你想调用这个程序,怎么做? 可以使用 subprosess 包(无需安装)。 文档参见:17.5. subprocess - Subprocess management - Python 3.5.4 documentation # test_cos_exe.py import subprocess import unittest class TestCosExe(unittest.TestCase): """docstring for TestCosExe""" def test_result(self): subprocess.check_output([ '....tcc.exe',str('cos_exe.c')]) result = subprocess.check_output([ str('cos_exe.exe'),str('45')]) self.assertEqual(result,b'0.70711') if __name__ == '__main__': unittest.main() // cos_exe.c #include subprocess 可以调用一个 exe 程序,然后把标准输出和错误输出都接收回来,以字符串变量的形式存储下来。 如果程序复杂,也可以保存成文件,然后读取文件中的数据。也可以直接存成图像、声音等多媒体文件。但要注意这种使用方式会给程序带来很多额外的依赖关系,对程序的稳定性与健壮性损害较大。 示例 同样也举一个 matplotlib 中的例子。matplotlib 中对于 latex 的支持就是通过系统调用实现的。 在查看到当前目录下不存在同名 dvi 文件后,matplotlib 调用系统中的 latex 编译 tex 源文件。如果调用中出现错误,则代理输出。 if (DEBUG or not os.path.exists(dvifile) or not os.path.exists(baselinefile)): texfile = self.make_tex_preview(tex,fontsize) command = [str("latex"),"-interaction=nonstopmode",os.path.basename(texfile)] _log.debug(command) try: report = subprocess.check_output(command,cwd=self.texcache,stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: raise RuntimeError( ('LaTeX was not able to process the following ' 'string: %s 参见 GitHub 源码。 用 Python 调用 dllPython 调用简单的 C 语言编译的 DLL,怎么做? 可以简单地使用 ctypes 包(无需安装)。 import ctypes user32 = ctypes.windll.LoadLibrary('user32.dll') # load dll assert(user32.MessageBoxA(0,b'Ctypes is cool!',b'Ctypes',0)) # call message box function (示例代码来源久远,已不可考,首次使用在该文中:Some Notes on Python and PyGame) 相当简单直接。其实只需要用 dependency walker 找到 dll 文件中的函数名,就可以使用 ctypes 包直接调用。(http://dependencywalker.com/) 这里其实揭示了 dll 文件的本质,就是一组二进制代码,函数名就是代码的入口定位符号。 用 ctypes 调用 dll 需要查看 dll 本身的手册,以便了解相关函数的功能和参数。ctypes 本身只是一层接口,不提供相关功能。 示例 OpenCV 里面,使用 ctypes 调用系统调用,来获得当前进程的 exe 文件名和起始地址。 def getRunningProcessExePathByName_win32(name): from ctypes import windll,POINTER,pointer,Structure,sizeof from ctypes import c_long,c_int,c_uint,c_char,c_ubyte,c_char_p,c_void_p class PROCESSENTRY32(Structure): _fields_ = [ ( 'dwSize',c_uint ),( 'cntUsage',c_uint),( 'th32ProcessID',( 'th32DefaultHeapID',( 'th32ModuleID',( 'cntThreads',( 'th32ParentProcessID',( 'pcPriClassBase',c_long),( 'dwFlags',( 'szExeFile',c_char * 260 ),( 'th32MemoryBase',( 'th32AccessKey',c_long ) ] class MODULEENTRY32(Structure): _fields_ = [ ( 'dwSize',c_long ),( 'GlblcntUsage',( 'ProccntUsage',( 'modBaseAddr',( 'modBaseSize',( 'hModule',c_void_p ),( 'szModule',c_char * 256 ),( 'szExePath',c_char * 260 ) ] TH32CS_SNAPPROCESS = 2 TH32CS_SNAPMODULE = 0x00000008 ## CreateToolhelp32Snapshot CreateToolhelp32Snapshot= windll.kernel32.CreateToolhelp32Snapshot CreateToolhelp32Snapshot.reltype = c_long CreateToolhelp32Snapshot.argtypes = [ c_int,c_int ] ## Process32First Process32First = windll.kernel32.Process32First Process32First.argtypes = [ c_void_p,POINTER( PROCESSENTRY32 ) ] Process32First.rettype = c_int ## Process32Next Process32Next = windll.kernel32.Process32Next Process32Next.argtypes = [ c_void_p,POINTER(PROCESSENTRY32) ] Process32Next.rettype = c_int ## CloseHandle CloseHandle = windll.kernel32.CloseHandle CloseHandle.argtypes = [ c_void_p ] CloseHandle.rettype = c_int ## Module32First Module32First = windll.kernel32.Module32First Module32First.argtypes = [ c_void_p,POINTER(MODULEENTRY32) ] Module32First.rettype = c_int hProcessSnap = c_void_p(0) hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS,0 ) pe32 = PROCESSENTRY32() pe32.dwSize = sizeof( PROCESSENTRY32 ) ret = Process32First( hProcessSnap,pointer( pe32 ) ) path = None while ret : if name + ".exe" == pe32.szExeFile: hModuleSnap = c_void_p(0) me32 = MODULEENTRY32() me32.dwSize = sizeof( MODULEENTRY32 ) hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE,pe32.th32ProcessID ) ret = Module32First( hModuleSnap,pointer(me32) ) path = me32.szExePath CloseHandle( hModuleSnap ) if path: break ret = Process32Next( hProcessSnap,pointer(pe32) ) CloseHandle( hProcessSnap ) return path 参见 GitHub 源码。 用 Python 调用 C/C++ 代码推荐使用 Cython 生成并调用 pyd。 其实 Python 基本实现就是 C 写的。`#include
# distutils: language = c # distutils: sources = # distutils: include_dirs = # distutils: extra_compile_args = # distutils: extra_link_args = # distutils: libraries = cdef extern from 'math.h': double M_PI cdef extern from 'cos_exe.c': int cos_c(double alpha,double * cos_of_alpha) def cos_pyd(double alpha): cdef double cos_of_alpha cos_c(alpha,&cos_of_alpha) return cos_of_alpha pyx 是整个调用工程的组织文件,其中面向 distutils 声明了整个项目的组织参数。包含了所需的头文件与源代码文件。更是写清了对于 Python 这个 Python 包的组织。 // source.c #include 这个 source.c 是示例的一部分,简单写清了输入输出,完成一个简单的功能。也可以拓展为多输入、多输出。 # cos_build_and_app.py from distutils.core import setup from Cython.Build import cythonize setup(ext_modules=cythonize('cos_pyd.pyx'),script_args='build_ext -i -t .'.split(' ')) import cos_pyd as c if __name__ == '__main__': result = c.cos_pyd(45) print('The cos of 45 is {0:.5f}.'.format(result)) 这个 py 文件,实现了 pyd 工程的编译和调用两个步骤。 在 import 语句以前的上半部分,完成了一个 pyd 包的编译过程。编译后要保存好 pyd 文件,以后在使用的时候,需要把 pyd 放在 python 路径下。 从 import 语句开始,就是一个典型 python 包的使用方法了。通过使用 pyd 就可以直接实现各种功能。 也可以将 pyd 当作一种打包方式,打包发布供二次开发的代码。 复杂工程的调用 再复杂的工程,其实都可以用 C/C++ 封装起来,做成一个工程,然后用 Cython 编译成 pyd,都可以做成 python 包,被调用。简单的,其实可以直接用 C 打包,用 ctypes 调用。稍复杂的,再用 Cython。 用 Python 调用 Java 代码简单的,可以使用 Jpype 包。 安装:conda install -c conda-forge jpype1 考虑到网络问题,可以从这里下载 whl:Unofficial Windows Binaries for Python Extension Packages,然后使用 pip install *.whl 安装。 使用 from jpype import * startJVM("C:/Program Files/Java/jdk1.8.0_144/jre/bin/server/jvm.dll","-ea") # Java code here # Create a java.lang.String object javaPackage = JPackage("java.lang") javaClass = javaPackage.String javaObject = javaClass("Hello,Jpype") # print the object java.lang.System.out.println(javaObject) # call String.length() and Integer.toString() methods java.lang.System.out.println("This string's length: " + javaPackage.Integer.toString(javaObject.length())) shutdownJVM() (示例代码来源于:https://www.quora.com/Can-we-write-C-and-Java-in-Python,有修改) 从调用方式中可以看出,其实也是调用 jvm 的 dll。 复杂的,可以尝试使用 pyjnius。 用 Python 调用 MATLAB 代码有原生工具,但本质上就是调用 matlab engine 的 dll。 安装 cd "matlabrootexternenginespython" python setup.py install 调用 import matlab.engine eng = matlab.engine.start_matlab() tf = eng.isprime(37) print(tf) # True 具体请参考文档。 用 Python 调用 R 代码跟调用 exe 一样,只不过这个 exe 是 Rscript。 # run_max.py import subprocess # 声明要调用的命令和参数 command = 'Rscript' path2script = 'path/to your script/max.R' # 把参数(这里是数据)放在一个列表里 args = [str(11),str(3),str(9),str(42)] # 生成要执行的命令 cmd = [command,path2script] + args # check_output 执行命令,保存结果 return_str = subprocess.check_output(cmd,universal_newlines=True) print('The maximum of the numbers is:',return_str) (示例代码来源于:https://www.mango-solutions.com/blog/integrating-python-and-r-part-ii-executing-r-from-python-and-vice-versa,有修改) 总结Python 的开发,是以 C/C++ 为基础的,所以针对 C/C++ 的调用最为方便。其它程序、动态链接库、代码的调用,都可以通过 EXE、DLL、C/C++ 三种渠道之一实现。Python 还是比较适合粘合各种程序与代码的。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |