mirror of
https://github.com/AdaCore/cpython.git
synced 2026-02-12 12:57:15 -08:00
evaluate positional defaults before keyword-only defaults (closes #16967)
This commit is contained in:
@@ -493,14 +493,15 @@ case the parameter's default value is substituted. If a parameter has a default
|
||||
value, all following parameters up until the "``*``" must also have a default
|
||||
value --- this is a syntactic restriction that is not expressed by the grammar.
|
||||
|
||||
**Default parameter values are evaluated when the function definition is
|
||||
executed.** This means that the expression is evaluated once, when the function
|
||||
is defined, and that the same "pre-computed" value is used for each call. This
|
||||
is especially important to understand when a default parameter is a mutable
|
||||
object, such as a list or a dictionary: if the function modifies the object
|
||||
(e.g. by appending an item to a list), the default value is in effect modified.
|
||||
This is generally not what was intended. A way around this is to use ``None``
|
||||
as the default, and explicitly test for it in the body of the function, e.g.::
|
||||
**Default parameter values are evaluated from left to right when the function
|
||||
definition is executed.** This means that the expression is evaluated once, when
|
||||
the function is defined, and that the same "pre-computed" value is used for each
|
||||
call. This is especially important to understand when a default parameter is a
|
||||
mutable object, such as a list or a dictionary: if the function modifies the
|
||||
object (e.g. by appending an item to a list), the default value is in effect
|
||||
modified. This is generally not what was intended. A way around this is to use
|
||||
``None`` as the default, and explicitly test for it in the body of the function,
|
||||
e.g.::
|
||||
|
||||
def whats_on_the_telly(penguin=None):
|
||||
if penguin is None:
|
||||
|
||||
@@ -396,13 +396,15 @@ Known values:
|
||||
3210 (added size modulo 2**32 to the pyc header)
|
||||
Python 3.3a1 3220 (changed PEP 380 implementation)
|
||||
Python 3.3a4 3230 (revert changes to implicit __class__ closure)
|
||||
Python 3.4a1 3240 (evaluate positional default arguments before
|
||||
keyword-only defaults)
|
||||
|
||||
MAGIC must change whenever the bytecode emitted by the compiler may no
|
||||
longer be understood by older implementations of the eval loop (usually
|
||||
due to the addition of new opcodes).
|
||||
|
||||
"""
|
||||
_RAW_MAGIC_NUMBER = 3230 | ord('\r') << 16 | ord('\n') << 24
|
||||
_RAW_MAGIC_NUMBER = 3240 | ord('\r') << 16 | ord('\n') << 24
|
||||
_MAGIC_BYTES = bytes(_RAW_MAGIC_NUMBER >> n & 0xff for n in range(0, 25, 8))
|
||||
|
||||
_PYCACHE = '__pycache__'
|
||||
|
||||
@@ -176,6 +176,14 @@ class KeywordOnlyArgTestCase(unittest.TestCase):
|
||||
return __a
|
||||
self.assertEqual(X().f(), 42)
|
||||
|
||||
def test_default_evaluation_order(self):
|
||||
# See issue 16967
|
||||
a = 42
|
||||
with self.assertRaises(NameError) as err:
|
||||
def f(v=a, x=b, *, y=c, z=d):
|
||||
pass
|
||||
self.assertEqual(str(err.exception), "global name 'b' is not defined")
|
||||
|
||||
def test_main():
|
||||
run_unittest(KeywordOnlyArgTestCase)
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
|
||||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #16967: In function definition, evaluate positional defaults before
|
||||
keyword-only defaults.
|
||||
|
||||
- Issue #17173: Remove uses of locale-dependent C functions (isalpha() etc.)
|
||||
in the interpreter.
|
||||
|
||||
|
||||
@@ -2901,23 +2901,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||
}
|
||||
|
||||
/* XXX Maybe this should be a separate opcode? */
|
||||
if (posdefaults > 0) {
|
||||
PyObject *defs = PyTuple_New(posdefaults);
|
||||
if (defs == NULL) {
|
||||
Py_DECREF(func);
|
||||
goto error;
|
||||
}
|
||||
while (--posdefaults >= 0)
|
||||
PyTuple_SET_ITEM(defs, posdefaults, POP());
|
||||
if (PyFunction_SetDefaults(func, defs) != 0) {
|
||||
/* Can't happen unless
|
||||
PyFunction_SetDefaults changes. */
|
||||
Py_DECREF(defs);
|
||||
Py_DECREF(func);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(defs);
|
||||
}
|
||||
if (kwdefaults > 0) {
|
||||
PyObject *defs = PyDict_New();
|
||||
if (defs == NULL) {
|
||||
@@ -2945,6 +2928,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||
}
|
||||
Py_DECREF(defs);
|
||||
}
|
||||
if (posdefaults > 0) {
|
||||
PyObject *defs = PyTuple_New(posdefaults);
|
||||
if (defs == NULL) {
|
||||
Py_DECREF(func);
|
||||
goto error;
|
||||
}
|
||||
while (--posdefaults >= 0)
|
||||
PyTuple_SET_ITEM(defs, posdefaults, POP());
|
||||
if (PyFunction_SetDefaults(func, defs) != 0) {
|
||||
/* Can't happen unless
|
||||
PyFunction_SetDefaults changes. */
|
||||
Py_DECREF(defs);
|
||||
Py_DECREF(func);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(defs);
|
||||
}
|
||||
PUSH(func);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@@ -1565,6 +1565,8 @@ compiler_function(struct compiler *c, stmt_ty s)
|
||||
|
||||
if (!compiler_decorators(c, decos))
|
||||
return 0;
|
||||
if (args->defaults)
|
||||
VISIT_SEQ(c, expr, args->defaults);
|
||||
if (args->kwonlyargs) {
|
||||
int res = compiler_visit_kwonlydefaults(c, args->kwonlyargs,
|
||||
args->kw_defaults);
|
||||
@@ -1572,8 +1574,6 @@ compiler_function(struct compiler *c, stmt_ty s)
|
||||
return 0;
|
||||
kw_default_count = res;
|
||||
}
|
||||
if (args->defaults)
|
||||
VISIT_SEQ(c, expr, args->defaults);
|
||||
num_annotations = compiler_visit_annotations(c, args, returns);
|
||||
if (num_annotations < 0)
|
||||
return 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user