Skip to content

Instantly share code, notes, and snippets.

@schlarpc
Created December 4, 2017 07:43
Show Gist options
  • Save schlarpc/4e15f5fbbc697bab50547a04e6eb59dd to your computer and use it in GitHub Desktop.
Save schlarpc/4e15f5fbbc697bab50547a04e6eb59dd to your computer and use it in GitHub Desktop.
Bad ideas in Python: monkey patching decorators on to builtin types
import ctypes
class PyObject(ctypes.Structure):
pass
PyObject._fields_ = [
('ob_refcnt', hasattr(ctypes.pythonapi, 'Py_InitModule4_64') and ctypes.c_int64 or ctypes.c_int),
('ob_type', ctypes.POINTER(PyObject)),
]
class SlotsPointer(PyObject):
_fields_ = [('dict', ctypes.POINTER(PyObject))]
def builtin_setattr(cls, key, value):
name = cls.__name__
pointer = SlotsPointer.from_address(id(getattr(cls, '__dict__', name)))
namespace = {}
ctypes.pythonapi.PyDict_SetItem(
ctypes.py_object(namespace),
ctypes.py_object(name),
pointer.dict,
)
namespace[name][key] = value
def ify(transform):
def ify_decorator(func):
def ify_wrapper(*args, **kwargs):
return transform(func(*args, **kwargs))
return ify_wrapper
return ify_decorator
for datatype in (list, dict, set, int):
builtin_setattr(datatype, 'ify', ify(datatype))
# turn a generator into a list!
@list.ify
def list_yields():
yield 5
yield 6
yield 7
assert list_yields() == [5, 6, 7]
# ... or pairs into a dict!
@dict.ify
def dict_yields():
yield ('a', 5)
yield ('b', 6)
yield ('a', 7)
assert dict_yields() == {'a': 7, 'b': 6}
# ... or dedupe with a set!
@set.ify
def set_yields():
yield 5
yield 6
yield 5
assert set_yields() == {5, 6}
# ... or get your integers going!
@int.ify
def string_return():
return '88'
assert string_return() == 88
# it doesn't have to be a generator!
@set.ify
def already_list():
return [5, 4, 4]
assert already_list() == {5, 4}
# and it's ok if it returns nothing!
@list.ify
def no_yield():
if False:
yield 1
assert no_yield() == []
# sigh, i guess you can use it without horrifying monkey patches if you really want
@ify(list)
def without_monkey():
yield 2
yield 8
assert without_monkey() == [2, 8]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment