Skip to content

Instantly share code, notes, and snippets.

@hltbra
Created June 28, 2017 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hltbra/0b15c459ddde0d3a4af794dc3981b320 to your computer and use it in GitHub Desktop.
Save hltbra/0b15c459ddde0d3a4af794dc3981b320 to your computer and use it in GitHub Desktop.
Tech Deep Dive - Introduction to the Python/C API
/*
gcc -o 0 0.c
./0
*/
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello %s!\n", argv[1]);
return 0;
}
/*
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;
}
/*
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;
}
# -*- 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
int incr(int a) {
return a + 1;
}
/*
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;
}
/*
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);
}
/*
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