from functools import partial
writable_function_dunders = {
'__annotations__',
'__call__',
'__defaults__',
'__dict__',
'__doc__',
'__globals__',
'__kwdefaults__',
'__name__',
'__qualname__'}
def partial_plus(func, *args, **kwargs):
"""Like partial, but with the ability to add 'normal function' stuff (name, doc) to the curried function.
Note: if no writable_function_dunders is specified will just act as the builtin partial (which it calls first).
>>> def foo(a, b): return a + b
>>> f = partial_plus(foo, b=2, __name__='bar', __doc__='foo, but with b=2')
>>> f.__name__
'bar'
>>> f.__doc__
'foo, but with b=2'
"""
dunders_in_kwargs = writable_function_dunders.intersection(kwargs)
def gen():
for dunder in dunders_in_kwargs:
dunder_val = kwargs.pop(dunder)
yield dunder, dunder_val
dunders_to_write = dict(gen()) # will remove dunders from kwargs
partial_func = partial(func, *args, **kwargs)
for dunder, dunder_val in dunders_to_write.items():
setattr(partial_func, dunder, dunder_val)
return partial_func
There's a more general context here: what's the "right" way to make callables behave like full fledge functions.
For example, in the following, I needed to add a __name__ to avoid running into problems when processing expects callables to have a __name__. I can of course encapsulate the get_name need into a more careful function (e.g. if doesn't exist, use type(o).__name__ as a fallback). But that will work only when I need a name. How do I define my objects to be robust if third-party code that expects this __name__?
Note: And if the class is not a dataclass, it's even less clean: I "need" to do a self.__name__ = 'the_name' in the __init__!
Perhaps a decorator would be cleaner. But what to decorate? The following won't work on a class (or rather, won't have the effect wanted on the (callable) instance:
def add_name(obj, name=None):
if name is None:
name = type(obj).__name__
obj.__name__ = name
return obj
There's a more general context here: what's the "right" way to make callables behave like full fledge functions. For example, in the following, I needed to add a
__name__
to avoid running into problems when processing expects callables to have a__name__
. I can of course encapsulate theget_name
need into a more careful function (e.g. if doesn't exist, usetype(o).__name__
as a fallback). But that will work only when I need a name. How do I define my objects to be robust if third-party code that expects this__name__
?Note: And if the class is not a dataclass, it's even less clean: I "need" to do a
self.__name__ = 'the_name'
in the__init__
!Perhaps a decorator would be cleaner. But what to decorate? The following won't work on a class (or rather, won't have the effect wanted on the (callable) instance: