In #30 I made a point that we don't want to have Sig resolve signatures by wrapping builtins, because Sig's job is only to provide a valid signature (if any).
That said, it can be useful to have some wrapped builtins available to us. Especially if we can also have some control over particulars of these wrappers.
Following are a few examples of uses.
Providing a valid single signatures when a function is overloaded
Many builtin functions (that break inspect.signature's attempt at providing a signature) don't have a single valid signature, but several possible ones (due to function overloading).
Sometimes it's possible to invent a signature that is compatible with all of these, but sometimes it's just not.
Consider next for example.
The doc says next(iterator[, default]) which means that default is optional. But neither (iterator, default) nor (iterator, default=None) would work as the signature since the first shouldn't allow the function to be called without a default and the second would yield None if the iterator is empty (which is not what next(iterator) should be doing (it should raise a StopIteration error).
On the other hand, the following _next would work:
from i2 import mk_sentinel, Sig
NotGiven = mk_sentinel('Optional', boolean_value=False, repr_='Optional')
def _next(iterator, default=NotGiven):
if default is NotGiven:
return next(iterator)
else:
return next(iterator, default)
Making easier to curry more fully
How can I use functools.partial to make functions like is_int, is_str, is_int_or_float etc.?
Answer: I can't. At least not as "naturally" as I would if isinstance didn't have POSITION_ONLY arguments.
from functools import partial
def _isinstance(obj, class_or_tuple):
return isinstance(obj, class_or_tuple)
is_int = partial(_isinstance, class_or_tuple=int)
assert is_int(3)
assert not is_int('3')
Make some builtin choices make more sense (for a given context)
For example, the "Python functools.wraps doesn't deal with defaults correctly" python issue -- see also this pull request.
In order to be able to use wraps functionality more smoothly, I sometimes use one that adds __defaults__ and __kw_defaults)__ to the WRAPPER_ASSIGNMENTS that functools uses.
┆Issue is synchronized with this Asana task by Unito
In #30 I made a point that we don't want to have
Sigresolve signatures by wrapping builtins, becauseSig's job is only to provide a valid signature (if any).That said, it can be useful to have some wrapped builtins available to us. Especially if we can also have some control over particulars of these wrappers.
Following are a few examples of uses.
Providing a valid single signatures when a function is overloaded
Many builtin functions (that break
inspect.signature's attempt at providing a signature) don't have a single valid signature, but several possible ones (due to function overloading).Sometimes it's possible to invent a signature that is compatible with all of these, but sometimes it's just not.
Consider
nextfor example.The doc says
next(iterator[, default])which means that default is optional. But neither(iterator, default)nor(iterator, default=None)would work as the signature since the first shouldn't allow the function to be called without adefaultand the second would yieldNoneif the iterator is empty (which is not whatnext(iterator)should be doing (it should raise aStopIterationerror).On the other hand, the following
_nextwould work:Making easier to curry more fully
How can I use
functools.partialto make functions likeis_int,is_str,is_int_or_floatetc.?Answer: I can't. At least not as "naturally" as I would if
isinstancedidn't havePOSITION_ONLYarguments.Make some builtin choices make more sense (for a given context)
For example, the "Python
functools.wrapsdoesn't deal with defaults correctly" python issue -- see also this pull request.In order to be able to use
wrapsfunctionality more smoothly, I sometimes use one that adds__defaults__and__kw_defaults)__to theWRAPPER_ASSIGNMENTSthatfunctoolsuses.┆Issue is synchronized with this Asana task by Unito