diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst index c7a3e0c596b9d0..d70f5f774d0376 100644 --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -425,7 +425,7 @@ The :mod:`bdb` module also defines two classes: ``(frame, lineno)`` tuple. The return string contains: * The canonical filename which contains the frame. - * The function name or ``""``. + * The function name. * The input arguments. * The return value. * The line of code (if it exists). diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index 3a9b66ec7e7088..2709ba0146faa1 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -1256,8 +1256,7 @@ The following option is accepted: .. [#] Don't confuse this with the :mod:`marshal` module -.. [#] This is why :keyword:`lambda` functions cannot be pickled: all - :keyword:`!lambda` functions share the same name: ````. +.. [#] This is why :keyword:`lambda` functions cannot be pickled. .. [#] The exception raised will likely be an :exc:`ImportError` or an :exc:`AttributeError` but it could be something else. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 91f90a0726aa93..08fdad632e5673 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2684,7 +2684,7 @@ we try to call it incorrectly:: >>> req = request.Request() Traceback (most recent call last): ... - TypeError: () takes at least 2 arguments (1 given) + TypeError: missing a required argument: 'url' The spec also applies to instantiated classes (i.e. the return value of specced mocks):: diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 5379ac3abba227..7252edda50cdbb 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -307,6 +307,17 @@ Other language changes not only integers or floats, although this does not improve precision. (Contributed by Serhiy Storchaka in :gh:`67795`.) +* The repr and the name of :keyword:`lambda` functions will now contain + the signature and body expression. For example:: + + >>> f = lambda x, y=1: x+y + >>> f + + >>> f.__name__ + '' + + (Contributed by Serhiy Storchaka in :issue:`32489`.) + New modules =========== diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 9c2364491fe08d..b32140e55991d0 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -587,6 +587,7 @@ def test_compile_ast(self): ['', """if True:\n pass\n"""], ['', """for n in [1, 2, 3]:\n print(n)\n"""], ['', """def foo():\n pass\nfoo()\n"""], + ['', """f = lambda x: x+1"""], [fname, fcontents], ] diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py index 2ad422079b7f23..fd97080dac16c3 100644 --- a/Lib/test/test_docxmlrpc.py +++ b/Lib/test/test_docxmlrpc.py @@ -127,8 +127,8 @@ def test_lambda(self): self.client.request("GET", "/") response = self.client.getresponse() - self.assertIn((b'
' - b'<lambda>(x, y)
'), + self.assertIn((b'
' + b'<lambda x, y: x - y>(x, y)
'), response.read()) @make_request_and_skipIf(sys.flags.optimize >= 2, diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 375f456dfde834..a525d50f340ece 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -205,7 +205,7 @@ def test___qualname__(self): self.assertEqual(FuncAttrsTest.setUp.__qualname__, 'FuncAttrsTest.setUp') self.assertEqual(global_function.__qualname__, 'global_function') self.assertEqual(global_function().__qualname__, - 'global_function..') + 'global_function..') self.assertEqual(global_function()().__qualname__, 'global_function..inner_function') self.assertEqual(global_function()()().__qualname__, diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index 22a55b57c076eb..0b36fca840ee22 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -202,8 +202,8 @@ def test_instance(self): self.assertIn(s.find("..."), [12, 13]) def test_lambda(self): - r = repr(lambda x: x) - self.assertStartsWith(r, ".$', + self.failureException, '^Exception not raised by $', self.assertRaisesRegex, Exception, re.compile('x'), lambda: None) self.assertRaisesRegex( - self.failureException, '^Exception not raised by $', + self.failureException, '^Exception not raised by $', self.assertRaisesRegex, Exception, 'x', lambda: None) # Custom message diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index c54530740395f7..6d653f9fb0b1ae 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1700,15 +1700,18 @@ def _register(self, func, subst=None, needcleanup=1): be executed. An optional function SUBST can be given which will be executed before FUNC.""" f = CallWrapper(func, subst, self).__call__ - name = repr(id(f)) try: func = func.__func__ except AttributeError: pass try: - name = name + func.__name__ + name = func.__name__ except AttributeError: - pass + name = '' + else: + if not re.fullmatch('[a-zA-Z0-9_]+', name): + name = '' + name = repr(id(f)) + name self.tk.createcommand(name, f) if needcleanup: if self._tclCommands is None: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2018-09-30-21-15-54.bpo-34856.uQBZD7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2018-09-30-21-15-54.bpo-34856.uQBZD7.rst new file mode 100644 index 00000000000000..2293e27a882b9b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2018-09-30-21-15-54.bpo-34856.uQBZD7.rst @@ -0,0 +1 @@ +Add signature and body expression to the repr of lambda. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 43198aaf8a7048..105b6f55d61de1 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1165,6 +1165,18 @@ static PyObject* func_repr(PyObject *self) { PyFunctionObject *op = _PyFunction_CAST(self); + PyObject *name = op->func_name; + Py_ssize_t len = PyUnicode_GET_LENGTH(name); + if (len > 2 + && PyUnicode_READ_CHAR(name, 0) == '<' + && PyUnicode_READ_CHAR(name, len-1) == '>') + { + PyObject *repr = PyUnicode_Substring(name, 0, len-1); + if (repr) { + Py_SETREF(repr, PyUnicode_FromFormat("%U at %p>", repr, op)); + } + return repr; + } return PyUnicode_FromFormat("", op->func_qualname, op); } diff --git a/Python/codegen.c b/Python/codegen.c index c4109fcaa48dbe..60db909f6ad8cf 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -2022,10 +2022,20 @@ codegen_lambda(compiler *c, expr_ty e) .u_posonlyargcount = asdl_seq_LEN(args->posonlyargs), .u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs), }; - _Py_DECLARE_STR(anon_lambda, ""); - RETURN_IF_ERROR( - codegen_enter_scope(c, &_Py_STR(anon_lambda), COMPILE_SCOPE_LAMBDA, - (void *)e, e->lineno, NULL, &umd)); + + PyObject *exprstr = _PyAST_ExprAsUnicode(e); + if (!exprstr) { + return ERROR; + } + PyObject *name = PyUnicode_FromFormat("<%U>", exprstr); + Py_DECREF(exprstr); + if (!name) { + return ERROR; + } + int rc = codegen_enter_scope(c, name, COMPILE_SCOPE_LAMBDA, + (void *)e, e->lineno, NULL, &umd); + Py_DECREF(name); + RETURN_IF_ERROR(rc); assert(!SYMTABLE_ENTRY(c)->ste_has_docstring);