Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-119127: functools.partial placeholders#119827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
rhettinger merged 78 commits intopython:mainfromdg-pb:implement-119127-again
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
78 commits
Select commitHold shift + click to select a range
ee7333c
Initial Implementation
dg-pbMay 21, 2024
8bcc462
serialization fix
dg-pbMay 21, 2024
c67c9b4
bug fix
dg-pbMay 21, 2024
680d900
Bug 2 fix
dg-pbMay 21, 2024
9591ff5
Py_TPFLAGS_IMMUTABLETYPE added
dg-pbMay 21, 2024
067e938
placeholder added to state as opposed to being used as global constant
dg-pbMay 23, 2024
8af20b3
static removed
dg-pbMay 23, 2024
607a0b1
creating sentinel via PyType_Spec
dg-pbMay 23, 2024
f55801e
more accurate variable name
dg-pbMay 23, 2024
5894145
trailing trim bug and tests
dg-pbMay 24, 2024
3722e07
Updated docs
dg-pbMay 24, 2024
a79c2af
blurb
dg-pbMay 24, 2024
12aaa72
Merge branch 'main' into implement-119127
May 24, 2024
92c767b
minor edit
dg-pbMay 24, 2024
496a9d2
doc fix
dg-pbMay 24, 2024
38d9c11
better variable names and mini corrections
dg-pbMay 31, 2024
707b957
Merge branch 'implement-119127' into implement-119127-again
dg-pbMay 31, 2024
14b38ca
review comments mostly
dg-pbJun 8, 2024
32bca19
singleton sentinel and reduce
dg-pbJun 8, 2024
8576493
python module sentinel better mimics the one of the extension
dg-pbJun 8, 2024
a3fd2d6
Emulated None behaviour, but using PyType_FromModuleAndSpec
dg-pbJun 8, 2024
0852993
review feedback
dg-pbJun 8, 2024
6fea348
included constant into tsv
dg-pbJun 8, 2024
caec6e8
documentation update
dg-pbJun 8, 2024
115b8c5
review edits
dg-pbJun 9, 2024
3f5f00b
trailing placeholder prohibition and small changes
dg-pbJun 9, 2024
202c929
change constant name in ignores
dg-pbJun 9, 2024
2c16d38
PlaceholderType Hidden
dg-pbJun 11, 2024
400ff55
support 4-arg pre-placeholder state
dg-pbJun 20, 2024
8ccc38f
better variable names
dg-pbJun 20, 2024
e7c82c7
partialmethod impl
dg-pbJun 20, 2024
c9b7ef3
fix tests
dg-pbJun 20, 2024
e59d711
adjust inspect to partial Placeholders
dg-pbJun 20, 2024
7bfc591
arg alignment
dg-pbJun 20, 2024
7957a97
small fixes
dg-pbJun 21, 2024
8aaee6a
pickle compatibility ensured
dg-pbJun 23, 2024
fe8e0ad
trailing placeholder test for __setstate__
dg-pbJun 23, 2024
00dd80e
rough implementation rolled back and example of successive applicatio…
dg-pbJun 24, 2024
d352cfa
small doc edits
dg-pbJun 24, 2024
9038ed5
example changes
dg-pbJun 24, 2024
49b8c71
serialization issues addressed
dg-pbJun 25, 2024
bc1fdbd
delete redundant references
dg-pbJun 25, 2024
3067221
simplify PyPlaceholder implementation
dg-pbJun 25, 2024
1185510
more optimal python functools.partial
dg-pbJun 25, 2024
266b4fa
placeholder arg and pre-placeholder instance conversions to positional
dg-pbJun 25, 2024
dd58a12
unittest.mock.ANY test for Placeholder
dg-pbJun 25, 2024
5971fbb
functools.partial.__get__
dg-pbJun 26, 2024
9033650
Revert "functools.partial.__get__"
dg-pbJun 26, 2024
d31e5d1
Merge branch 'main' into implement-119127-again
dg-pbJun 26, 2024
a3d39b0
review changes
dg-pbJun 26, 2024
9e4c5df
factor out repr. same to be used for partial and partialmethod
dg-pbJun 27, 2024
16f12f8
microopt & args.count(Placeholder) can not be used as it uses __eq__
dg-pbJun 27, 2024
82dd600
simplify preparation
dg-pbJun 27, 2024
f9cb653
whatsnew + minor doc edit
dg-pbJun 27, 2024
d255524
typo fixes
dg-pbJun 27, 2024
404044e
whatsnew edit
dg-pbJun 27, 2024
800217b
revert stylistic changes
dg-pbJun 27, 2024
38ee450
factor out full __new__
dg-pbJun 28, 2024
11f47db
Merge branch 'main' into implement-119127-again
serhiy-storchakaJul 3, 2024
3c872bd
Merge branch 'main' into implement-119127-again
serhiy-storchakaAug 11, 2024
fd16189
CR part 1
dg-pbAug 12, 2024
a6c6ef2
CR Part 2
dg-pbAug 12, 2024
1c8d73e
remove ignored global var
dg-pbAug 12, 2024
a8bd3ae
CR changes
dg-pbAug 12, 2024
70e47ed
small CR changes and doc updates
dg-pbAug 12, 2024
2eacf5e
push placeholder check to earlier place
dg-pbAug 12, 2024
f78d8d3
more appropriate test functions and better doc example
dg-pbAug 13, 2024
0a8640e
minor fixes; message, doc polish
dg-pbAug 13, 2024
6e3d282
better doc example and small test changes
dg-pbAug 13, 2024
66c305d
assertRaisesRegex exact match
dg-pbAug 14, 2024
14bf68c
doc nits
dg-pbAug 14, 2024
ee642d5
Add Placeholder to __all__
rhettingerSep 25, 2024
8d6c28e
Update copyright span
rhettingerSep 25, 2024
8744bcb
Minor doc edits and add doctests
rhettingerSep 25, 2024
b896470
Merge branch 'main' into implement-119127-again
rhettingerSep 25, 2024
4881ae6
Merge branch 'main' into implement-119127-again
rhettingerSep 25, 2024
c3ad7d9
Having the separate dict was necessary to eliminate duplicate keywords
rhettingerSep 26, 2024
5e5d484
Merge branch 'main' into implement-119127-again
rhettingerSep 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
review edits
  • Loading branch information
@dg-pb
dg-pb committedJun 9, 2024
commit115b8c5cb335c9cb69b9d394ae0e622913cfbc6a
13 changes: 7 additions & 6 deletionsDoc/library/functools.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -330,7 +330,7 @@ The :mod:`functools` module defines the following functions:

.. function:: partial(func, /, *args, **keywords)

Return a new :ref:`partial object<partial-objects>` which when called
Return a new :ref:`partial object<partial-objects>` which when called
will behave like *func* called with the positional arguments *args*
and keyword arguments *keywords*. If more arguments are supplied to the
call, they are appended to *args*. If additional keyword arguments are
Expand DownExpand Up@@ -380,7 +380,8 @@ The :mod:`functools` module defines the following functions:

If :data:`Placeholder` sentinels are present in *args*, they will be filled first
when :func:`partial` is called. This allows custom selection of positional arguments
to be pre-filled when constructing :ref:`partial object<partial-objects>`.
to be pre-filled when constructing a :ref:`partial object <partial-objects>`.

If :data:`Placeholder` sentinels are used, all of them must be filled at call time:

>>> from functools import partial, Placeholder
Expand All@@ -390,16 +391,16 @@ The :mod:`functools` module defines the following functions:
>>> say_to_world('Hello', 'dear')
Hello dear world!

Calling ``say_to_world('Hello')`` wouldresult in :exc:`TypeError`.
Calling ``say_to_world('Hello')`` wouldraise a :exc:`TypeError`.

.. versionchanged:: 3.14
Support for :data:`Placeholder` in *args*

.. data:: Placeholder

This is asingleton objectthat isused as a sentinelfor representing a
gap in positional arguments when calling :func:`partial`.
Ithassimilarfeaturesas :data:`None`:
Asingleton object used as a sentinelto represent a
"gap" in positional arguments when calling :func:`partial`.
This objecthas featuressimilar to ``None``:

>>> type(Placeholder)() is Placeholder
True
Expand Down
46 changes: 24 additions & 22 deletionsLib/functools.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -281,12 +281,12 @@ class PlaceholderType:
The type of the Placeholder singleton.
Used as a placeholder for partial arguments.
"""
_singleton = None
__instance = None

def __new__(cls):
if cls._singleton is None:
cls._singleton = object.__new__(cls)
return cls._singleton
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance

def __repr__(self):
return 'Placeholder'
Expand All@@ -313,13 +313,13 @@ class partial:
def __new__(cls, func, /, *args, **keywords):
if not callable(func):
raise TypeError("the first argument must be callable")
placeholder_count = 0
np = 0
nargs = len(args)
if args:
while nargs and args[nargs-1] is Placeholder:
while nargs and args[nargs -1] is Placeholder:
nargs -= 1
args = args[:nargs]
placeholder_count = args.count(Placeholder)
np = args.count(Placeholder)
if isinstance(func, partial):
pargs = func.args
pnp = func.placeholder_count
Expand All@@ -335,10 +335,10 @@ def __new__(cls, func, /, *args, **keywords):
pos += 1
if pnp < nargs:
all_args.extend(args[pnp:])
placeholder_count += pnp - end
np += pnp - end
args = tuple(all_args)
else:
placeholder_count += pnp
np += pnp
args = func.args + args
keywords = {**func.keywords, **keywords}
func = func.func
Expand All@@ -347,26 +347,28 @@ def __new__(cls, func, /, *args, **keywords):
self.func = func
self.args = args
self.keywords = keywords
self.placeholder_count =placeholder_count
self.placeholder_count =np
return self

def __call__(self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
if placeholder_count := self.placeholder_count:
if len(args) < placeholder_count:
np = self.placeholder_count
p_args = self.args
if np:
if len(args) < np:
raise TypeError(
"missing positional arguments in 'partial' call; expected "
f"at least {placeholder_count}, got {len(args)}")
f_args = list(self.args)
"missing positional arguments "
"in 'partial' call; expected "
f"at least {np}, got {len(args)}")
p_args = list(p_args)
j, pos = 0, 0
while j <placeholder_count:
pos =f_args.index(Placeholder, pos)
f_args[pos] = args[j]
while j <np:
pos =p_args.index(Placeholder, pos)
p_args[pos] = args[j]
j += 1
pos += 1
return self.func(*f_args, *args[j:], **keywords)
else:
return self.func(*self.args, *args, **keywords)
args =args[j:]
keywords = {**self.keywords, **keywords}
return self.func(*p_args, *args, **keywords)

@recursive_repr()
def __repr__(self):
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
``partial``of``functools`` module now supports placeholders for positional
arguments.
Positional argumentsof:func:`functools.partial` objects
now support placeholders via :data:`functools.Placeholder`.
19 changes: 12 additions & 7 deletionsModules/_functoolsmodule.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ typedef struct _functools_state {
/* this object is used delimit args and keywords in the cache keys */
PyObject *kwd_mark;
PyTypeObject *placeholder_type;
PyObject *placeholder;
PyTypeObject *partial_type;
PyTypeObject *keyobject_type;
PyTypeObject *lru_list_elem_type;
Expand DownExpand Up@@ -205,7 +206,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
return NULL;
}

pto->placeholder =PyObject_CallNoArgs((PyObject *)state->placeholder_type);
pto->placeholder = state->placeholder;
Py_ssize_t nnp = 0;
Py_ssize_t nnargs = PyTuple_GET_SIZE(nargs);
PyObject *item;
Expand DownExpand Up@@ -517,7 +518,7 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
PyObject *pto_args = pto->args;
PyObject *item;
Py_ssize_t j = 0; // New args index
for (Py_ssize_t i=0; i < pto_nargs; i++) {
for (Py_ssize_t i =0; i < pto_nargs; i++) {
item = PyTuple_GET_ITEM(pto_args, i);
if (Py_Is(item, pto->placeholder)) {
item = PyTuple_GET_ITEM(args, j);
Expand All@@ -537,10 +538,10 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
else {
/* Note: tupleconcat() is optimized for empty tuples */
args2 = PySequence_Concat(pto->args, args);
}
if (args2 == NULL) {
Py_XDECREF(kwargs2);
return NULL;
if (args2 == NULL) {
Py_XDECREF(kwargs2);
return NULL;
}
}

PyObject *res = PyObject_Call(pto->fn, args2, kwargs2);
Expand DownExpand Up@@ -1709,7 +1710,11 @@ _functools_exec(PyObject *module)
if (PyModule_AddType(module, state->placeholder_type) < 0) {
return -1;
}
if (PyModule_AddObject(module, "Placeholder", PyObject_CallNoArgs((PyObject *)state->placeholder_type)) < 0) {
state->placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
if (state->placeholder == NULL) {
return -1;
}
if (PyModule_AddObject(module, "Placeholder", state->placeholder) < 0) {
return -1;
}
state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp