Ricerca nel sito web

Ottimizza il tuo codice Python con C


Cython crea moduli C che accelerano l'esecuzione del codice Python, importante per applicazioni complesse in cui un linguaggio interpretato non è efficiente.

Cython è un compilatore per il linguaggio di programmazione Python pensato per ottimizzare le prestazioni e formare un linguaggio di programmazione Cython esteso. Come estensione di Python, Cython è anche un superset del linguaggio Python e supporta la chiamata di funzioni C e la dichiarazione di tipi C su variabili e attributi di classe. Ciò semplifica il confezionamento di librerie C esterne, l'incorporamento di C in applicazioni esistenti o la scrittura di estensioni C per Python con una sintassi semplice come quella di Python stesso.

Cython è comunemente usato per creare moduli C che accelerano l'esecuzione del codice Python. Ciò è importante in applicazioni complesse in cui un linguaggio interpretato non è efficiente.

Installa Cython

Puoi installare Cython su Linux, BSD, Windows o macOS utilizzando Python:

$ python -m pip install Cython

Una volta installato, è pronto per l'uso.

Trasforma Python in C

Un buon modo per iniziare con Cython è con una semplice applicazione "ciao mondo". Non è la migliore dimostrazione dei vantaggi di Cython, ma mostra cosa succede quando usi Cython.

Innanzitutto, crea questo semplice script Python in un file chiamato hello.pyx (l'estensione .pyx non è magica e tecnicamente potrebbe essere qualsiasi cosa, ma è l'estensione predefinita di Cython) :

print("hello world")

Successivamente, crea uno script di installazione Python. Un file setup.py è come la versione Python di un makefile e Cython può usarlo per elaborare il tuo codice Python:

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("hello.pyx")
)

Infine, usa Cython per trasformare il tuo script Python in codice C:

$ python setup.py build_ext --inplace

Puoi vedere i risultati nella directory del tuo progetto. Il modulo cythonize di Cython trasforma hello.pyx in un file hello.c e una libreria .so. Il codice C è di 2.648 righe, quindi è molto più testo della singola riga del sorgente hello.pyx. La libreria .so è inoltre oltre 2.000 volte più grande della sua sorgente (54.000 rispetto a 20 byte). Inoltre, Python è necessario per eseguire un singolo script Python, quindi c'è molto codice che sostiene quel file hello.pyx a riga singola.

Per utilizzare la versione in codice C del tuo script Python "hello world", apri un prompt Python e importa il nuovo modulo hello che hai creato:

>>> import hello
hello world

Integra il codice C in Python

Un buon test generico della potenza di calcolo è il calcolo dei numeri primi. Un numero primo è un numero positivo maggiore di 1 che produce un intero positivo solo se diviso per 1 o per se stesso. In teoria è semplice, ma man mano che i numeri aumentano, aumentano anche i requisiti di calcolo. In Python puro, può essere fatto in meno di 10 righe di codice:

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")

Questo script tace in caso di successo e restituisce un messaggio se il numero non è primo:

$ ./prime.py 3
$ ./prime.py 4
Not prime.

Convertirlo in Cython richiede un po' di lavoro, in parte per rendere il codice appropriato per l'uso come libreria e in parte per le prestazioni.

Script e librerie

Molti utenti imparano Python come linguaggio di scripting: dici a Python i passaggi che vuoi che esegua e lui fa il lavoro. Man mano che impari di più su Python (e sulla programmazione open source in generale), impari che gran parte del codice più potente disponibile si trova nelle librerie che altre applicazioni possono sfruttare. Quanto più meno specifico è il tuo codice, tanto più è probabile che possa essere riproposto da un programmatore (incluso tu) per altre applicazioni. Può richiedere un po' più di lavoro separare il calcolo dal flusso di lavoro, ma alla fine, di solito, ne vale la pena.

Nel caso di questo semplice calcolatore di numeri primi, la conversione in Cython inizia con uno script di installazione:

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("prime.py")
)

Trasforma il tuo script in C:

$ python setup.py build_ext --inplace

Finora sembra che tutto funzioni bene, ma quando tenti di importare e utilizzare il nuovo modulo, ricevi un errore:

>>> 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

Il problema è che uno script Python si aspetta di essere eseguito da un terminale, dove gli argomenti (in questo caso, un numero intero da testare come numero primo) sono comuni. È necessario modificare lo script in modo che possa essere utilizzato come libreria.

Scrivi una biblioteca

Le librerie non utilizzano argomenti di sistema e accettano invece argomenti da altro codice. Invece di usare sys.argv per inserire l'input dell'utente, rendi il tuo codice una funzione che accetta un argomento chiamato number (o num o qualsiasi altra variabile nome che preferisci):

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")

Ciò rende certamente il tuo script un po' difficile da testare perché quando esegui il codice in Python, la funzione calculate non viene mai eseguita. Tuttavia, i programmatori Python hanno escogitato una soluzione comune, se non intuitiva, per questo problema. Quando l'interprete Python esegue uno script Python, c'è una variabile speciale chiamata __name__ che viene impostata su __main__, ma quando viene importata come modulo, __name__ è impostato sul nome del modulo. Sfruttando questo, puoi scrivere una libreria che sia sia un modulo Python che uno script Python valido:

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) )

Ora puoi eseguire il codice come comando:

$ python ./prime.py 4
Not a prime

E puoi convertirlo in Cython per usarlo come modulo:

>>> import prime
>>> prime.calculate(4)
Not prime

C Pitone

La conversione del codice da Python puro a C con Cython può essere utile. Questo articolo mostra come eseguire questa parte, ma ci sono funzionalità Cython che ti aiutano a ottimizzare il codice prima della conversione, opzioni per analizzare il codice per scoprire quando Cython interagisce con C e molto altro. Se stai usando Python, ma stai cercando di migliorare il tuo codice con codice C o approfondire la tua comprensione di come le librerie forniscono una migliore estensibilità rispetto agli script, o se sei semplicemente curioso di sapere come Python e C possono lavorare insieme, allora inizia sperimentando con Cython.

Articoli correlati: