better_bindings icon indicating copy to clipboard operation
better_bindings copied to clipboard

Better bindings for Python

Better Bindings

Screenshot 2023-02-01 at 4 52 47 PM

This project will attempt to accomplish 2 things:

  1. Easy to implement bindings (using a standard C ABI) - ✅
  2. Fast bindings (using something like compile) - 🚧

Easy to use

Simple functions are trivial:

import better_bindings as bb

module = bb.bind('mylib.dylib', {
  'fn': ([bb.int32, bb.int32], bb.float),
  'renamed': ('orig_name', [bb.int32], bb.void)
})

out = module.fn(4, 4)
print(out)

Objects are also straightforward:

import better_bindings as bb

MyObj = bb.object('mylib.dylib', {
  '__init__': ('makeObj', [bb.int32, bb.int32], bb.ptr),
  '__del__': ('destroyObj', [bb.ptr], bb.void),
  'foo': ('foo', [bb.ptr, bb.int32], bb.int32)
})

obj = MyObj(8, 4)
out = obj.foo(3)
print(out)

Fast bindings (work in progress)

Currently, bindings are compiled on the fly with the system's C compiler

module = bb.bind('mylib.dylib', binding_map) # calls clang/gcc!

In the future, I hope to expose compile(). New code is generated and the bytecode is hotswapped (ala torchdynamo):

module = bb.bind('mylib.dylib', binding_map) 

def bar(a, b):
  c = module.foo(a, 3)
  d = module.foo(c, b)
  return d

bar = bb.compile(bar) # the two calls to `foo` are merged and compiled together

This is particularly useful for ref counting

MyObj = bb.object('mylib.dylib', binding_map) 

def bar(a, b):
  obja = MyObj(a, 4)
  objb = MyObj(b, 4)
  objc = obja + objb
  return objc

bar = bb.compile(bar) # the intermediate obja and objb are not materialized in Python, no refcounts are bumped!