Python vs. C

„ Програмиране с Python“, ФМИ

10.05.2011

Пайтън и C

Две думи за CPython

Защо?

Защо по * трябва да ползвам C?

Python + C > Python

Две е повече от едно

Възможностите

Как става това?

Ctypes

Ctypes позволява да викам C функции директно от Python без да ни се налага да пишем и капка C код.

Ctypes основни моменти

Зареждане на библиотеки

>>> from ctypes import *
>>> 
>>> libc = cdll.LoadLibrary('libc.so.6')
>>> libc

>>> libm = cdll.LoadLibrary('libm.so.6')
>>> libm

>>>

Calling conventions

Извикване на функции

>>> libc.time(None)
1243423125

Marshalling

Marshalling (примери)

Good morning world

libc.printf(b'good morning world, my name is %s\n', \
    b'Mityo')
good morning world, the time is 1243423807

Натурални типове

Отново извикване на функции

libc.printf(b'%d bottles of beer\n', 42)
libc.printf(b'%f bottles of beer\n', 42.5)
42 bottles of beer
Traceback (most recent call last):
  File "ctypes-basic.py", line 24, in 
    libc.printf(b'%f bottles of beer\n', 42.5)
ctypes.ArgumentError: argument 2: :
    Don't know how to convert parameter 2

Типове

ctypes type 	C type 	Python type
c_char 	char 	1-character string
c_wchar 	wchar_t 	1-character unicode string
c_byte 	char 	int
c_ubyte 	unsigned char 	int
c_short 	short 	int
c_ushort 	unsigned short 	int
c_int 	int 	int
c_uint 	unsigned int 	int
c_long 	long 	int
c_ulong 	unsigned long 	int
c_longlong 	__int64 or long long 	int
c_ulonglong 	unsigned __int64 or unsigned long long 	int
c_float 	float 	float
c_double 	double 	float
c_longdouble 	long double 	float
c_char_p 	char * (NULL terminated) 	string or None
c_wchar_p 	wchar_t * (NULL terminated) 	unicode or None
c_void_p 	void * 	int or None

Експлицитно преобразуване

libc.printf(b'%f bottles of beer\n', c_double(42.5))
42.500000 bottles of beer

c_* обектите са mutable

Имат поленце value което може да променяте.

>>> i = c_int(42)
>>> print(i, i.value)
c_long(42) 42
>>> i.value = -99
>>> print(i, i.value)
c_long(-99) -99

Структури

class POINT(Structure):
    _fields_ = [('x', c_double), ('y', c_double)]
>>> point = POINT(10, 20)
>>> print(point.x, point.y)
10.0 20.0
>>> point = POINT(y=5)
>>> print(point.x, point.y)
0.0 5.0
>>> POINT(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: too many initializers

Структури

Структурите имат метаклас различен от стандартния type:

>>> type(POINT) == type
False
>>> type(POINT)

Масиви

Масивите си имат собствен тип който включва броя елементи. Типа се указва като умножим типа на елементите по техния брой

>>> (c_int * 3)(1,2,3)[0]
1

Указатели

Указатели към c_* обекти (срещу указатели към натурални обекти)

>>> i = c_int(10)
>>> p = pointer(i)
>>> p.contents
c_long(10)
>>> j = c_int(10)
>>> p.contents = j
>>> p.contents.value
10
>>> p.contents.value = 11
>>> j.value
11
>>> p[0]
11

Указатели

>>> p[10]
159787148
>>> p[10] = 20
>>> p[10]
20

The Grim Reaper

Събирачът на боклук (The Grim Reaper) може да събере вашите обекти ако нямате референция към тях, дори и да има такива в C кода.

За и против

Ctyeps изненади

SWIG & Boost.Python

Python/C API

В началото бе Python.h …

Префикси

Примери за функции, тип

Примери за duck-typing

Marshalling към Python

Py_BuildValue("s", "spam") -> 'spam'
Py_BuildValue("i", 42) -> 42
Py_BuildValue("(sii)", 42, "hi", 8) -> (42, 'hi', 8)
Py_BuildValue("{is,is}", 1, "one", 2, "two") \
    -> {1: 'one', 2: 'two'}
Py_BuildValue("") -> None

Marshalling към C

const char* string;
int number;
PyArg_ParseTuple(args, "si:string_peek", &string, \
    &number)

Функции на C

>>> print
<built-in function print>
>>> 

Функции, връщащи PyObject*

Функции, връщащи int

Cython = Python + (C API) - (C Syntax)

Още въпроси?

Още интересни неща на

Real programmers write in FORTRAN

The Story of Mel

Истинският програмист: http://www.pbm.com/~lindahl/mel.html