Working with Windows API which usually takes like a zillion for each function can be a little bit frustrating and if I want to only change two in the middle for each call I had to wrap everything into lambda functions which change arguments to the order that I need to use with partial.
So finally I added kinda dangerous decorator which inserts keywords into right position if detected and was about to use it but ctypes functions don't accept keyword arguments :D so just ended up with decorator :)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | from functools import partial
from inspect import getargspec, ismethod
def keywords_first(f):
def wrapper(*a, **k):
a = list(a)
#for idx, arg in enumerate(f.func_code.co_varnames[:f.func_code.co_argcount], -ismethod(f)):
for idx, arg in enumerate(getargspec(f).args, -ismethod(f)): # or [0] in 2.5
if arg in k:
if idx < len(a):
a.insert(idx, k.pop(arg))
else:
break
return f(*a, **k)
return wrapper
@keywords_first
def fun(a, b, c=3): return a, b, c
print fun(1, 3, b=2) # normally: TypeError: f() got multiple values for keyword argument 'b'
def fun2(a, b, *args, **kwargs): return a, b, args, kwargs
print partial(keywords_first(fun2), a=1, c=2, b=2)(3, 4, 5, 6, 7) # noramlly: TypeError ...
def kfpartial(fun, *args, **kwargs):
return partial(keywords_first(fun), *args, **kwargs)
print kfpartial(fun2, a=1, b=2)(3, 4, 5, 6, 7, c=3)
|
I'm not sure if it is all that useful, but makes the code shorter in some situations, especially when you have to pass handler and some default/reserved values around the code. EDIT: added ismethod to handle better methods and skip self argument
Nice. I always wanted to have a "shuffled" partial to apply to functions in
operator
module but thegetargspec
function does not work on built-in functions. :(Nice recipe nonetheless.
With build-ins works in pypy. So if you don't have any specific libraries that hasn't been ported yet, you could switch.