Update and rename sources/tech/20210421 Optimize your Python code with C.md to translated/tech/20210421 Optimize your Python code with C.md

This commit is contained in:
RiaXu 2021-04-25 21:32:12 +08:00 committed by GitHub
parent f0e48af4e5
commit 920ce8ed57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 207 additions and 208 deletions

View File

@ -1,208 +0,0 @@
[#]: subject: (Optimize your Python code with C)
[#]: via: (https://opensource.com/article/21/4/cython)
[#]: author: (Alan Smithee https://opensource.com/users/alansmithee)
[#]: collector: (lujun9972)
[#]: translator: (ShuyRoy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
Optimize your Python code with C
======
Cython creates C modules that speed up Python code execution, important
for complex applications where an interpreted language isn't efficient.
![Hands on a keyboard with a Python book ][1]
Cython is a compiler for the Python programming language meant to optimize performance and form an extended Cython programming language. As an extension of Python, [Cython][2] is also a superset of the Python language, and it supports calling C functions and declaring C types on variables and class attributes. This makes it easy to wrap external C libraries, embed C into existing applications, or write C extensions for Python in syntax as easy as Python itself.
Cython is commonly used to create C modules that speed up Python code execution. This is important in complex applications where an interpreted language isn't efficient.
### Install Cython
You can install Cython on Linux, BSD, Windows, or macOS using Python:
```
`$ python -m pip install Cython`
```
Once installed, it's ready to use.
### Transform Python into C
A good way to start with Cython is with a simple "hello world" application. It's not the best demonstration of Cython's advantages, but it shows what happens when you're using Cython.
First, create this simple Python script in a file called `hello.pyx` (the `.pyx` extension isn't magical and it could technically be anything, but it's Cython's default extension):
```
`print("hello world")`
```
Next, create a Python setup script. A `setup.py` file is like Python's version of a makefile, and Cython can use it to process your Python code:
```
from setuptools import setup
from Cython.Build import cythonize
setup(
    ext_modules = cythonize("hello.pyx")
)
```
Finally, use Cython to transform your Python script into C code:
```
`$ python setup.py build_ext --inplace`
```
You can see the results in your project directory. Cython's `cythonize` module transforms `hello.pyx` into a `hello.c` file and a `.so` library. The C code is 2,648 lines, so it's quite a lot more text than the single line of `hello.pyx` source. The `.so` library is also over 2,000 times larger than its source (54,000 compared to 20 bytes). Then again, Python is required to run a single Python script, so there's a lot of code propping up that single-line `hello.pyx` file.
To use the C code version of your Python "hello world" script, open a Python prompt and import the new `hello` module you created:
```
>>> import hello
hello world
```
### Integrate C code into Python
A good generic test of computational power is calculating prime numbers. A prime number is a positive number greater than 1 that produces a positive integer only when divided by 1 or itself. It's simple in theory, but as numbers get larger, the calculation requirements also increase. In pure Python, it can be done in under 10 lines of code:
```
import sys
number = int(sys.argv[1])
if not number <= 1:
    for i in range(2, number):
        if (number % i) == 0:
            print("Not prime")
            break
else:
    print("Integer must be greater than 1")
```
This script is silent upon success and returns a message if the number is not prime:
```
$ ./prime.py 3
$ ./prime.py 4
Not prime.
```
Converting this to Cython requires a little work, partly to make the code appropriate for use as a library and partly for performance.
#### Scripts and libraries
Many users learn Python as a scripting language: you tell Python the steps you want it to perform, and it does the work. As you learn more about Python (and open source programming in general), you learn that much of the most powerful code out there is in the libraries that other applications can harness. The _less_ specific your code is, the more likely it can be repurposed by a programmer (you included) for other applications. It can be a little more work to decouple computation from workflow, but in the end, it's usually worth the effort.
In the case of this simple prime number calculator, converting it to Cython begins with a setup script:
```
from setuptools import setup
from Cython.Build import cythonize
setup(
    ext_modules = cythonize("prime.py")
)
```
Transform your script into C:
```
`$ python setup.py build_ext --inplace`
```
Everything appears to be working well so far, but when you attempt to import and use your new module, you get an error:
```
>>> import prime
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "prime.py", line 2, in init prime
    number = sys.argv[1]
IndexError: list index out of range
```
The problem is that a Python script expects to be run from a terminal, where arguments (in this case, an integer to test as a prime number) are common. You need to modify your script so that it can be used as a library instead.
#### Write a library
Libraries don't use system arguments and instead accept arguments from other code. Instead of using `sys.argv` to bring in user input, make your code a function that accepts an argument called `number` (or `num` or whatever variable name you prefer):
```
def calculate(number):
    if not number <= 1:
        for i in range(2, number):
            if (number % i) == 0:
                print("Not prime")
                break
    else:
        print("Integer must be greater than 1")
```
This admittedly makes your script somewhat difficult to test because when you run the code in Python, the `calculate` function is never executed. However, Python programmers have devised a common, if not intuitive, workaround for this problem. When the Python interpreter executes a Python script, there's a special variable called `__name__` that gets set to `__main__`, but when it's imported as a module, `__name__` is set to the module's name. By leveraging this, you can write a library that is both a Python module and a valid Python script:
```
import sys
def calculate(number):
    if not number <= 1:
        for i in range(2, number):
            if (number % i) == 0:
                print("Not prime")
                break
    else:
        print("Integer must be greater than 1")
if __name__ == "__main__":
    number = sys.argv[1]    
    calculate( int(number) )
```
Now you can run the code as a command:
```
$ python ./prime.py 4
Not a prime
```
And you can convert it to Cython for use as a module:
```
>>> import prime
>>> prime.calculate(4)
Not prime
```
### C Python
Converting code from pure Python to C with Cython can be useful. This article demonstrates how to do that part, yet there are Cython features to help you optimize your code before conversion, options to analyze your code to find when Cython interacts with C, and much more. If you're using Python, but you're looking to enhance your code with C code or further your understanding of how libraries provide better extensibility than scripts, or if you're just curious about how Python and C can work together, then start experimenting with Cython.
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/4/cython
作者:[Alan Smithee][a]
选题:[lujun9972][b]
译者:[ShuyRoy](https://github.com/ShuyRoy)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alansmithee
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python-programming-code-keyboard.png?itok=fxiSpmnd (Hands on a keyboard with a Python book )
[2]: https://cython.org/

View File

@ -0,0 +1,207 @@
[#]: subject: (Optimize your Python code with C)
[#]: via: (https://opensource.com/article/21/4/cython)
[#]: author: (Alan Smithee https://opensource.com/users/alansmithee)
[#]: collector: (lujun9972)
[#]: translator: (ShuyRoy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
使用C优化你的Python代码
======
Cython创建了C模块来加速Python代码的执行这对使用效率不高的解释型语言编写的复杂的应用是很重要的。
![Hands on a keyboard with a Python book ][1]
Cython是Python编程语言的编译器旨在优化性能并形成一个扩展的Cython编程语言。作为Python的扩展[Cython][2]也是Python语言的超集它支持调用C函数和在变量和类属性上声明C类型。这使得包装外部C库、将C嵌入现有应用程序或者为Python编写C扩展语法像Python本身一样简单变得容易。
Cython一般用于创建C模块来加速Python代码的执行。这在使用解释型语言编写的效率不高的复杂应用中非常重要。
### 安装Cython
你可以在LinuxBSDWindows或macOS上安装Cython来使用Python
```
`$ python -m pip install Cython`
```
安装好后,就可以使用它了。
### 将Python转换成C
使用Cython的一个好的方式是从一个简单的“hello world”开始。这虽然不是Cython优点的最好的展现方式但是它展示了使用Cython时发生的情况。
首先创建一个简单的Python脚本文件命名为`hello.pyx` `.pyx`扩展名并不神奇从技术上它可以是任何东西但它是Cython的默认扩展名
```
`print("hello world")`
```
接下来创建一个Python设置脚本。一个像Python的生成文件一样的`setup.py`Cython可以使用它来处理你的Python代码
```
from setuptools import setup
from Cython.Build import cythonize
setup(
    ext_modules = cythonize("hello.pyx")
)
```
最后使用Cython将你的Python脚本转换为C代码
```
`$ python setup.py build_ext --inplace`
```
你可以在你的工程目录中看到结果。Cython的`cythonize`模块将`hello.pyx`转换成一个`hello.c`文件和一个`.so`库。该C代码有2648行所以它比一个一行的`hello.pyx`源码的文本要多很多。`.so`库也比它的源码大2000倍即54000字节和20字节相比。然后Python需要运行单个Python脚本所以有很多代码支持这个只有一行的`hello.pyx`文件。
要使用Python的“hello world”脚本的C代码版本请打开一个Python提示符并导入您创建的新`hello`模块:
```
>>> import hello
hello world
```
### 将C代码集成到Python中
测试计算能力的一个很好的通用测试是计算质数。一个质数是一个比1大的正数且它只有被1或它自己除后才会产生正整数。虽然理论很简单但是随着数的变大计算需求也会增加。在纯Python中可以用10行以内的代码完成质数的计算。
```
import sys
number = int(sys.argv[1])
if not number <= 1:
    for i in range(2, number):
        if (number % i) == 0:
            print("Not prime")
            break
else:
    print("Integer must be greater than 1")
```
这个脚本在成功的时候是不会提醒的,如果这个数不是质数,则返回一条信息:
```
$ ./prime.py 3
$ ./prime.py 4
Not prime.
```
将这些转换为Cython需要一些工作一部分是为了使代码适合用作库另一部分是为了提高性能。
#### 脚本和库
许多用户将Python当作一种脚本语言来学习你告诉Python你想让它执行的步骤然后它来做。随着你对Python以及一般的开源编程的了解越多你可以了解到许多强大的代码都存在于其他应用程序可以利用的库中。你的代码越_不具有针对性_程序员包括你就越可能将其重用于其他的应用程序。将计算和工作流解耦可能需要更多的工作但最终这通常是值得的。
在这个简单的质数计算的例子中将Python转换成Cython从一个设置脚本开始
```
from setuptools import setup
from Cython.Build import cythonize
setup(
    ext_modules = cythonize("prime.py")
)
```
将你的脚本转换成C
```
`$ python setup.py build_ext --inplace`
```
到目前为止,一切似乎都工作的很好,但是当你试图导入并使用新模块时,你会看到一个错误:
```
>>> import prime
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "prime.py", line 2, in init prime
    number = sys.argv[1]
IndexError: list index out of range
```
这个问题是Python脚本希望从一个终端运行其中参数在这个例子中是要测试是否为质数的整数是一样的。你需要修改你的脚本这样它就可以作为一个库来使用了。
#### 写一个库
库不使用系统参数,而是接受其他代码的参数。对于用户输入,不是使用`sys.argv`,而是将你的代码封装成一个函数来接收一个叫`number`(或者`num`,或者任何你喜欢的变量名)的参数:
```
def calculate(number):
    if not number <= 1:
        for i in range(2, number):
            if (number % i) == 0:
                print("Not prime")
                break
    else:
        print("Integer must be greater than 1")
```
这确实使你的脚本有些难测试因为当你在Python中运行代码时`calculate`函数永远不会被执行。但是Python编程人员已经为这个问题设计了一个通用但不是很直观的解决方案。当Python解释器执行一个Python脚本时有一个叫`__name__`的特殊变量,这个变量被设置为`__main__`,但是当它被作为模块导入的时候,`__name__` 被设置为模块的名字。利用这点你可以写一个既是Python模块又是有效Python脚本的库
```
import sys
def calculate(number):
    if not number <= 1:
        for i in range(2, number):
            if (number % i) == 0:
                print("Not prime")
                break
    else:
        print("Integer must be greater than 1")
if __name__ == "__main__":
    number = sys.argv[1]    
    calculate( int(number) )
```
现在你可以用一个命令来运行代码了:
```
$ python ./prime.py 4
Not a prime
```
你可以将它转换为Cython来用作一个模块
```
>>> import prime
>>> prime.calculate(4)
Not prime
```
### C Python
用Cython将纯Python的代码转换为C是有用的。这篇文章描述了如何做但是Cython的特性可以帮助你在转换之前优化你的代码分析你的代码来找到Cython什么时候与C进行交互以及更多。如果你正在用Python但是你希望用C代码改进你的代码或者进一步理解库是如何提供比脚本更好的扩展性的或者你只是好奇Python和C是如何协作的那么就开始使用Cython吧。
--------------------------------------------------------------------------------
via: https://opensource.com/article/21/4/cython
作者:[Alan Smithee][a]
选题:[lujun9972][b]
译者:[ShuyRoy](https://github.com/ShuyRoy)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alansmithee
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python-programming-code-keyboard.png?itok=fxiSpmnd (Hands on a keyboard with a Python book )
[2]: https://cython.org/