-
-
Save hltbra/0b15c459ddde0d3a4af794dc3981b320 to your computer and use it in GitHub Desktop.
Tech Deep Dive - Introduction to the Python/C API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc -o 0 0.c | |
./0 | |
*/ | |
#include <stdio.h> | |
int main(int argc, char *argv[]) | |
{ | |
printf("Hello %s!\n", argv[1]); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc -o 1 1.c -lpython $(python-config --includes) | |
./1 | |
*/ | |
#include "Python.h" | |
#include <stdio.h> | |
int main(int argc, char *argv[]) { | |
/* | |
import random | |
random.randint(1, 10) | |
*/ | |
Py_Initialize(); | |
PyObject *module; | |
module = PyImport_ImportModule("random"); | |
PyObject *result; | |
result = PyObject_CallMethod(module, "randint", "ii", 1, 10); | |
long c_result; | |
c_result = PyInt_AsLong(result); | |
printf("Result: %ld\n", c_result); | |
Py_Finalize(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc -o extract extract.c $(python-config --includes) -lpython | |
./extract | |
*/ | |
#include "Python.h" | |
int main(int argc, char *argv[]) | |
{ | |
PyObject *module, *method_result; | |
Py_Initialize(); | |
PyObject *sys_path = PySys_GetObject("path"); | |
PyList_Insert(sys_path, 0, PyString_FromString("")); | |
/* | |
>>> from extract import get_field | |
>>> get_field({'data': ['{"a": 1, "b": 2}']}, 'data[0]|fromjson.b') | |
2 | |
*/ | |
module = PyImport_ImportModule("extract"); | |
method_result = PyObject_CallMethod(module, | |
"get_field", | |
"{s:[s]}s", | |
"data", "{\"a\": 1, \"b\": 2}", | |
"data[0]|fromjson.a"); | |
long result; | |
result = PyInt_AsLong(method_result); | |
printf ("result: %ld\n", result); | |
Py_Finalize (); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# from __future__ import unicode_literals | |
import os | |
import re | |
import random | |
import logging | |
import json | |
from copy import deepcopy, copy | |
class ExtractError(Exception): | |
pass | |
class EmptyEmbeddedJsonError(Exception): | |
pass | |
def get_field_force(*args, **kwargs): | |
'''blowup if fields doesn't exists.''' | |
kwargs['force'] = True | |
return get_field(*args, **kwargs) | |
def get_field(json_, fields, type_=None, force=False): | |
''' | |
>>> data = {'data': ['{"a": 1, "b": 2}']} | |
>>> extract_value(data, 'data[0]|fromjson.b') | |
2 | |
''' | |
fields = _extract_fields(fields) | |
value = json_ | |
for field in fields: | |
try: | |
value = extract_value(value, field) | |
except ExtractError as e: | |
if force: | |
raise e | |
return None | |
if type_ is not None and value is not None: | |
value = type_(value) | |
return value | |
def extract_value(value, field): | |
match = re.search(r'\[(\d+)\]', field) | |
match_json = re.search(r'^\|fromjson$', field) | |
if match: | |
try: | |
return value[int(match.group(1))] | |
except (TypeError, KeyError, IndexError): | |
logging.warning('error in %s, for field: %s', value, field, exc_info=True) | |
raise ExtractError | |
elif match_json: | |
try: | |
return json.loads(value) | |
except (TypeError, KeyError): | |
logging.warning('error in %s, for field: %s', value, field, exc_info=True) | |
raise ExtractError | |
except ValueError: | |
raise EmptyEmbeddedJsonError | |
try: | |
return value[field] | |
except (KeyError, TypeError): | |
logging.warning('error in %s, for field: %s', value, field, exc_info=True) | |
raise ExtractError | |
def _extract_fields(text): | |
return [t for t in re.split(r'(\.|\[\d+\]|\|fromjson)', text) if t and not t in '.'] | |
def get_index(items, index=0, force=False): | |
try: | |
return items[index] | |
except IndexError: | |
if force: | |
raise ExtractError | |
else: | |
return None | |
def get_xpath(element, xpath, index=0, force=False): | |
""" | |
Given a DOM element and an XPath, return a single item. | |
Raise ExtractError if force=True and index doesn't exist. | |
""" | |
res = element.xpath(xpath) | |
if type(res) == list: | |
return get_index(res, index, force) | |
else: | |
return res | |
def get_re_match_group(pattern, string, index=0, force=False): | |
"""Return either the grouped match at index or None if no match.""" | |
match = re.search(pattern, string) | |
if match: | |
return get_index(match.groups(), index, force) | |
else: | |
return None | |
def get_re_match_groups(pattern, string, force=False): | |
""" Returns a tuple of all matches or None if no match.""" | |
match = re.search(pattern, string) | |
if match: | |
return match.groups() | |
if force: | |
raise ExtractError | |
return None | |
def get_first_non_none_item(items): | |
"""Return the first non-None item in a list.""" | |
for item in items: | |
if item is not None: | |
return item | |
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int incr(int a) { | |
return a + 1; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc -o json json.c $(python-config --includes) -lpython | |
./json | |
equivalent to the following python code: | |
import json | |
result = json.dumps({"msg": "hello world", "a": "b"}) | |
print(result) | |
*/ | |
#include "Python.h" | |
int main(int argc, char *argv[]) | |
{ | |
PyObject *module, *method_result; | |
char *result; | |
Py_Initialize(); | |
module = PyImport_ImportModule("json"); | |
method_result = PyObject_CallMethod(module, "dumps", "{s:s, s:s}", "msg", "hello world", "a", "b"); | |
result = PyString_AsString(method_result); | |
printf ("result: %s\n", result); | |
Py_Finalize (); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc -shared -o incr.so pyincr.c $(python-config --includes) -lpython | |
/usr/bin/python | |
BENCHMARK | |
--------- | |
def plusone(a): | |
return a + 1 | |
executions = 90000000 | |
setup = "from __main__ import plusone, incr" | |
import incr | |
import timeit | |
timeit.timeit("incr.incr(10)", setup=setup, number=executions) | |
timeit.timeit("plusone(10)", setup=setup, number=executions) | |
*/ | |
#include "Python.h" | |
int incr(int a) { | |
return a + 1; | |
} | |
PyObject *pyincr(PyObject *self, PyObject *a) { | |
int primitive_a = PyInt_AsLong(a); | |
int result = incr(primitive_a); | |
return PyInt_FromLong(result); | |
} | |
PyMethodDef methods[] = { | |
{"incr", (PyCFunction)pyincr, METH_O}, | |
{NULL, NULL}, | |
}; | |
void initincr() { | |
Py_InitModule("incr", methods); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
gcc -o random random.c $(python-config --includes) -lpython | |
equivalent to the following python code | |
import random | |
result = random.randint(1, 10) | |
print(result) | |
*/ | |
#include "Python.h" | |
int main(int argc, char *argv[]) | |
{ | |
Py_Initialize(); | |
PyObject *module; | |
module = PyImport_ImportModule("random"); | |
PyObject *random_value; | |
random_value = PyObject_CallMethod(module, "randint", "ii", 1, 10); | |
long result; | |
result = PyInt_AsLong(random_value); | |
printf ("result: %ld\n", result); | |
Py_Finalize (); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment