New function with partial application of the given arguments and keywords.
| 274 | |
| 275 | # Purely functional, no descriptor behaviour |
| 276 | class partial: |
| 277 | """New function with partial application of the given arguments |
| 278 | and keywords. |
| 279 | """ |
| 280 | |
| 281 | __slots__ = "func", "args", "keywords", "__dict__", "__weakref__" |
| 282 | |
| 283 | def __new__(cls, func, /, *args, **keywords): |
| 284 | if not callable(func): |
| 285 | raise TypeError("the first argument must be callable") |
| 286 | |
| 287 | if hasattr(func, "func"): |
| 288 | args = func.args + args |
| 289 | keywords = {**func.keywords, **keywords} |
| 290 | func = func.func |
| 291 | |
| 292 | self = super(partial, cls).__new__(cls) |
| 293 | |
| 294 | self.func = func |
| 295 | self.args = args |
| 296 | self.keywords = keywords |
| 297 | return self |
| 298 | |
| 299 | def __call__(self, /, *args, **keywords): |
| 300 | keywords = {**self.keywords, **keywords} |
| 301 | return self.func(*self.args, *args, **keywords) |
| 302 | |
| 303 | @recursive_repr() |
| 304 | def __repr__(self): |
| 305 | qualname = type(self).__qualname__ |
| 306 | args = [repr(self.func)] |
| 307 | args.extend(repr(x) for x in self.args) |
| 308 | args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items()) |
| 309 | if type(self).__module__ == "functools": |
| 310 | return f"functools.{qualname}({', '.join(args)})" |
| 311 | return f"{qualname}({', '.join(args)})" |
| 312 | |
| 313 | def __reduce__(self): |
| 314 | return type(self), (self.func,), (self.func, self.args, |
| 315 | self.keywords or None, self.__dict__ or None) |
| 316 | |
| 317 | def __setstate__(self, state): |
| 318 | if not isinstance(state, tuple): |
| 319 | raise TypeError("argument to __setstate__ must be a tuple") |
| 320 | if len(state) != 4: |
| 321 | raise TypeError(f"expected 4 items in state, got {len(state)}") |
| 322 | func, args, kwds, namespace = state |
| 323 | if (not callable(func) or not isinstance(args, tuple) or |
| 324 | (kwds is not None and not isinstance(kwds, dict)) or |
| 325 | (namespace is not None and not isinstance(namespace, dict))): |
| 326 | raise TypeError("invalid partial state") |
| 327 | |
| 328 | args = tuple(args) # just in case it's a subclass |
| 329 | if kwds is None: |
| 330 | kwds = {} |
| 331 | elif type(kwds) is not dict: # XXX does it need to be *exactly* dict? |
| 332 | kwds = dict(kwds) |
| 333 | if namespace is None: |
no outgoing calls