New function with partial application of the given arguments and keywords.
| 367 | |
| 368 | # Purely functional, no descriptor behaviour |
| 369 | class partial: |
| 370 | """New function with partial application of the given arguments |
| 371 | and keywords. |
| 372 | """ |
| 373 | |
| 374 | __slots__ = ("func", "args", "keywords", "_phcount", "_merger", |
| 375 | "__dict__", "__weakref__") |
| 376 | |
| 377 | __new__ = _partial_new |
| 378 | __repr__ = recursive_repr()(_partial_repr) |
| 379 | |
| 380 | def __call__(self, /, *args, **keywords): |
| 381 | phcount = self._phcount |
| 382 | if phcount: |
| 383 | try: |
| 384 | pto_args = self._merger(self.args + args) |
| 385 | args = args[phcount:] |
| 386 | except IndexError: |
| 387 | raise TypeError("missing positional arguments " |
| 388 | "in 'partial' call; expected " |
| 389 | f"at least {phcount}, got {len(args)}") |
| 390 | else: |
| 391 | pto_args = self.args |
| 392 | keywords = {**self.keywords, **keywords} |
| 393 | return self.func(*pto_args, *args, **keywords) |
| 394 | |
| 395 | def __get__(self, obj, objtype=None): |
| 396 | if obj is None: |
| 397 | return self |
| 398 | return MethodType(self, obj) |
| 399 | |
| 400 | def __reduce__(self): |
| 401 | return type(self), (self.func,), (self.func, self.args, |
| 402 | self.keywords or None, self.__dict__ or None) |
| 403 | |
| 404 | def __setstate__(self, state): |
| 405 | if not isinstance(state, tuple): |
| 406 | raise TypeError("argument to __setstate__ must be a tuple") |
| 407 | if len(state) != 4: |
| 408 | raise TypeError(f"expected 4 items in state, got {len(state)}") |
| 409 | func, args, kwds, namespace = state |
| 410 | if (not callable(func) or not isinstance(args, tuple) or |
| 411 | (kwds is not None and not isinstance(kwds, dict)) or |
| 412 | (namespace is not None and not isinstance(namespace, dict))): |
| 413 | raise TypeError("invalid partial state") |
| 414 | |
| 415 | if args and args[-1] is Placeholder: |
| 416 | raise TypeError("trailing Placeholders are not allowed") |
| 417 | phcount, merger = _partial_prepare_merger(args) |
| 418 | |
| 419 | args = tuple(args) # just in case it's a subclass |
| 420 | if kwds is None: |
| 421 | kwds = {} |
| 422 | elif type(kwds) is not dict: # XXX does it need to be *exactly* dict? |
| 423 | kwds = dict(kwds) |
| 424 | if namespace is None: |
| 425 | namespace = {} |
| 426 |
searching dependent graphs…