Currently repr of doesn't contain much of information besides that it is a lambda.
lambda x: x**2 <function <lambda> at 0x7f3479b74488>
All lambdas have the same repr, different only by unreadable hexadecimal address. What if include the signature and the expression of the lambda in its repr?
lambda x: x**2 <lambda x: x**2>
This would return an old feature of Python 0.9.1 (https://twitter.com/dabeaz/status/934835068043956224). Repr of function could contain just the signature. <function foo(bar, baz)> But there is a problem with default values. Their reprs can be very long, especially in the following case with mutable default value: def foo(x, _cache={}): try: return _cache[x] except KeyError: pass _cache[x] = y = expensive_calculation(x) return y Maybe the placeholder should be always used instead of default values.
On 12/17/2017 2:20 PM, Serhiy Storchaka wrote:
Currently repr of doesn't contain much of information besides that it is a lambda.
lambda x: x**2 <function <lambda> at 0x7f3479b74488>
All lambdas have the same repr, different only by unreadable hexadecimal address.
Having the same pseudo-name is what being anonymous means. Some consider that a feature ;-).
What if include the signature and the expression of the lambda in its repr?
lambda x: x**2 <lambda x: x**2>
Printing the return value requires adding a code or function attribute. The return expression(s), possibly None, would be just as useful for named functions.
This would return an old feature of Python 0.9.1 (https://twitter.com/dabeaz/status/934835068043956224).
Repr of function could contain just the signature.
<function foo(bar, baz)>
But there is a problem with default values. Their reprs can be very long, especially in the following case with mutable default value:
I would not expect the representation to change; just use the expression.
def foo(x, _cache={}): try: return _cache[x] except KeyError: pass _cache[x] = y = expensive_calculation(x) return y
Maybe the placeholder should be always used instead of default values.
Do you mean 'a placeholder'? -- Terry Jan Reedy
17.12.17 22:55, Terry Reedy пише:
What if include the signature and the expression of the lambda in its repr?
>>> lambda x: x**2 <lambda x: x**2>
Printing the return value requires adding a code or function attribute.
Yes, this requires adding an optional constant code attribute.
The return expression(s), possibly None, would be just as useful for named functions.
In case of named functions the body is not an expression and usually is multiline.
But there is a problem with default values. Their reprs can be very long, especially in the following case with mutable default value:
I would not expect the representation to change; just use the expression.
This is a solution, thanks.
Maybe the placeholder should be always used instead of default values.
Do you mean 'a placeholder'?
Yes, sorry.
On 17.12.2017 22:20, Serhiy Storchaka wrote:
Currently repr of doesn't contain much of information besides that it is a lambda.
lambda x: x**2 <function <lambda> at 0x7f3479b74488>
All lambdas have the same repr, different only by unreadable hexadecimal address.
What if include the signature and the expression of the lambda in its repr?
lambda x: x**2 <lambda x: x**2>
It's the same for named functions: In [1]: def ditto(a): return a In [2]: ditto Out[2]: <function __main__.ditto> Are you intending to do the same for them?
This would return an old feature of Python 0.9.1 (https://twitter.com/dabeaz/status/934835068043956224).
Repr of function could contain just the signature.
<function foo(bar, baz)>
But there is a problem with default values. Their reprs can be very long, especially in the following case with mutable default value:
def foo(x, _cache={}): try: return _cache[x] except KeyError: pass _cache[x] = y = expensive_calculation(x) return y
Maybe the placeholder should be always used instead of default values.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Regards, Ivan
On 18/12/2017 06:11, Ivan Pozdeev via Python-ideas wrote:
On 17.12.2017 22:20, Serhiy Storchaka wrote:
Currently repr of doesn't contain much of information besides that it is a lambda.
lambda x: x**2 <function <lambda> at 0x7f3479b74488>
All lambdas have the same repr, different only by unreadable hexadecimal address.
What if include the signature and the expression of the lambda in its repr?
lambda x: x**2 <lambda x: x**2>
It's the same for named functions:
In [1]: def ditto(a): return a
In [2]: ditto Out[2]: <function __main__.ditto>
Are you intending to do the same for them?
This would return an old feature of Python 0.9.1 (https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftwitter.com%2Fdabeaz%2Fstatus%2F934835068043956224&data=02%7C01%7C%7C44a37122957d43015aa308d545de3321%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636491742990321352&sdata=iAE6MDdsZJDHfUqlHlPjnf2XV%2BiRZ%2BrP%2FL%2BIQ8kKoKo%3D&reserved=0).
Repr of function could contain just the signature.
<function foo(bar, baz)>
But there is a problem with default values. Their reprs can be very long, especially in the following case with mutable default value:
def foo(x, _cache={}): try: return _cache[x] except KeyError: pass _cache[x] = y = expensive_calculation(x) return y
Maybe the placeholder should be always used instead of default values.
_______________________________________________
Isn't this exactly the sort of information already available via inspect.getardspec, inspect.getsourcelines & inspect.getsource? In [19]: import inspect In [20]: l = lambda x: x**2 In [21]: inspect.getargspec(l) Out[21]: ArgSpec(args=['x'], varargs=None, keywords=None, defaults=None) In [22]: inspect.getsource(l) Out[22]: u'l = lambda x: x**2\n' In [23]: ...: def foo(x, _cache={}): ...: try: ...: return _cache[x] ...: except KeyError: ...: pass ...: _cache[x] = y = expensive_calculation(x) ...: return y ...: In [24]: inspect.getargspec(foo) Out[24]: ArgSpec(args=['x', '_cache'], varargs=None, keywords=None, defaults=({},)) In [25]: inspect.getsource(foo) Out[25]: u'def foo(x, _cache={}):\n try:\n return _cache[x]\n except KeyError:\n pass\n _cache[x] = y = expensive_calculation(x)\n return y \n' In [26]: inspect.getsourcelines(foo) Out[26]: ([u'def foo(x, _cache={}):\n', u' try:\n', u' return _cache[x]\n', u' except KeyError:\n', u' pass\n', u' _cache[x] = y = expensive_calculation(x)\n', u' return y \n'], 2) -- Steve (Gadget) Barnes Any opinions in this message are my personal opinions and do not reflect those of my employer. --- This email has been checked for viruses by AVG. http://www.avg.com
On Mon, Dec 18, 2017 at 07:54:17AM +0000, Steve Barnes wrote:
Isn't this exactly the sort of information already available via inspect.getardspec, inspect.getsourcelines & inspect.getsource?
[snip ipython interactive session showing that the answer is "Yes"] You answered your own question: yes it is. What's your point? That's not a rhetorical question -- I genuinely don't understand why you raise this. Do you see the existence of inspect.* as negating the usefulness of giving functions a more useful repr? As proof that the information is available? Something else? -- Steve
On 18/12/2017 11:43, Steven D'Aprano wrote:
On Mon, Dec 18, 2017 at 07:54:17AM +0000, Steve Barnes wrote:
Isn't this exactly the sort of information already available via inspect.getardspec, inspect.getsourcelines & inspect.getsource?
[snip ipython interactive session showing that the answer is "Yes"]
You answered your own question: yes it is. What's your point? That's not a rhetorical question -- I genuinely don't understand why you raise this. Do you see the existence of inspect.* as negating the usefulness of giving functions a more useful repr? As proof that the information is available? Something else?
Hi Steve, I see it as showing that the information is already available to anybody who needs it so I question the usefulness of changing repr (for everybody) which is bound to break something somewhere. Now if you were to suggest adding a verbose flag to repr or a print format, maybe both - so that people don't have to import inspect then I would say that you have a lot less chance of breaking any code/test cases that is in the wild. Sorry I should have made my point(s) clearer. -- Steve (Gadget) Barnes Any opinions in this message are my personal opinions and do not reflect those of my employer. --- This email has been checked for viruses by AVG. http://www.avg.com
On Mon, Dec 18, 2017 at 8:31 AM, Steve Barnes <gadgetsteve@live.co.uk> wrote:
On 18/12/2017 11:43, Steven D'Aprano wrote:
On Mon, Dec 18, 2017 at 07:54:17AM +0000, Steve Barnes wrote:
Isn't this exactly the sort of information already available via inspect.getardspec, inspect.getsourcelines & inspect.getsource?
[snip ipython interactive session showing that the answer is "Yes"]
You answered your own question: yes it is. What's your point? That's not a rhetorical question -- I genuinely don't understand why you raise this. Do you see the existence of inspect.* as negating the usefulness of giving functions a more useful repr? As proof that the information is available? Something else?
Wow, that's way too aggressive for this list.
Hi Steve,
I see it as showing that the information is already available to anybody who needs it so I question the usefulness of changing repr (for everybody) which is bound to break something somewhere. Now if you were to suggest adding a verbose flag to repr or a print format, maybe both - so that people don't have to import inspect then I would say that you have a lot less chance of breaking any code/test cases that is in the wild.
Sorry I should have made my point(s) clearer.
But is it readily available? Will the people who need the information know how to get it? No. IMO, `inspect` is somewhat arcane, and you shouldn't need its full power to use lambdas. Right now, lambdas are represented just by their memory location. That's not meaningful. Lambdas are, abstractly speaking, value objects, with value defined by its definition (including parameter names). (That's not really true in Python, where lambdas are not compared by just function definition.) A lambda's location is irrelevant to its functionality; unless you poke around its dunder bits, a lambda's functionality is completely determined by its signature, its body, and the closure. In short, the address doesn't really represent the lambda. Imagine a world where ints and strs are represented by type and address. That's not an ideal world. How you use an int or str has nothing to do with its memory location, and everything to do with its value. Regarding backward compatibility, I'm unsympathetic toward anyone who was relying on lambdas being represented by their addresses. At worst, they'd check for `repr(f).startswith('<function <lambda>')`, which, if we really care, can be accounted for. I'm more concerned with future backward compatibility: if the repr is made meaningful now, it will definitely be harder to change in the future. In any case, it should be more a consideration than a reason against. Note that it's impossible in general to fulfill `eval(repr(myLambda)) == myLambda`, because of how lambdas are compared, but also because you won't necessarily have access to the same lexical scope as the original lambda, and because default arguments can hold state.
On Wed, Dec 20, 2017 at 03:55:01PM -0500, Franklin? Lee wrote:
Wow, that's way too aggressive for this list.
Hair-trigger sensitivity to "aggressiveness" is itself a form of aggression, because it leads to unfair accusations of aggressiveness and other over-reactions, and forces people to "walk on eggshells" rather than say what they are actually thinking. Remember that tone of voice doesn't communicate well across email. You should always read email and give the writer the benefit of the doubt: "if I were face to face with this person, and could see relaxed posture and a smile, or hear a friendly tone of voice, would I still think this was aggressive?" -- Steve
I'm in the middle of moving, so I'm not planning to take this any farther than this email unless someone explicitly brings up an issue by emailing Python-ideas-owner where Titus can help anyone out. On Wed, Dec 20, 2017, 16:11 Steven D'Aprano, <steve@pearwood.info> wrote:
On Wed, Dec 20, 2017 at 03:55:01PM -0500, Franklin? Lee wrote:
Wow, that's way too aggressive for this list.
I personally disagree as I didn't read anything from Steven as aggressive in his response. I think a better response would have been, "I don't think you mean for what you said to be portrayed as aggressive, but I read <blank> as if you were saying <blank>". Otherwise to me it comes off as dealing with aggression with aggression.
Hair-trigger sensitivity to "aggressiveness" is itself a form of aggression, because it leads to unfair accusations of aggressiveness and other over-reactions, and forces people to "walk on eggshells" rather than say what they are actually thinking.
I also disagree with this. 😄 Any form of aggression isn't really necessary to appropriately communicate an idea or viewpoint, so taking some time to consider how you phrase something so it doesn't come off as aggressive to people in general is a good thing. Given a choice between allowing occasional aggression so that some don't feel they have to be careful in their phrasing "just in case" compared to people having to take extra time in their response to avoid aggression, I always go with the latter. For me, any extra effort to be courteous is worth it.
Remember that tone of voice doesn't communicate well across email. You should always read email and give the writer the benefit of the doubt: "if I were face to face with this person, and could see relaxed posture and a smile, or hear a friendly tone of voice, would I still think this was aggressive?"
This I do agree with. Give people the benefit of the doubt, and if you want you can kindly inform the person how you could have interpreted what they said as aggressive and why you thought that. This gives people a chance to explain what they actually meant and for people to potentially apologize for the misunderstanding. -Brett
-- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Mon, Dec 18, 2017 at 5:31 AM, Steve Barnes <gadgetsteve@live.co.uk> wrote:
I see it as showing that the information is already available to anybody who needs it so I question the usefulness of changing repr (for everybody) @dataclass class C: a: "the a parameter" # field with no default b: "another, different parameter" = 0.0 # field with a default .
well, digging into inspect and all that is definitely an advanced process -- repr is for a quick look-see at the value of an object -- it would be great to have one that was more informative. and in theory, the "goal" is for eval(repr(obj)) to return an equivelent object -- surely that would require showing the arguments and expression, yes? But is it bound to break somethign somewhere? given how, well, useless the current lambda repr is, I can't imagine much breaking. But then I"ve been known to lack imagination :-) As for "proper" functions, I think it's pretty much off the table -- they are simply too often complicated beasts with lots of parameters, lots of code, multiple return possibilities, etc. Is there a downside other than possible breakage? Performance issue, maybe? And with regards to breakage -- anyone have code that would break (yeah, I know, small sample, but if the answer is yes, lots, then we're done) -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On 21 Dec 2017, at 06:57, Chris Barker <chris.barker@noaa.gov> wrote:
in theory, the "goal" is for eval(repr(obj)) to return an equivelent object
Is that really was the goal of repr? If true then we would not need pickle. I have always assumed that repr of simple things aims to represent them in just the way you would write them in python code. Repr of complex things represents the obj as a useful summary. Lamba seems to be in the complex end of things. In debug logs I am often very interested in object identity and use the 0x123 as one way to know. Removing the unique id would be a regression in my eyes. Maybe what you would like to have is an explain function that given any object tells you alll about it. help function does some of this I guess. Barry
Could we call it "help"? Maybe add some beef to what's already there...
help(lambda x,y,*args: x) Help on function <lambda> in module __main__:
<lambda> lambda x, y, *args On Thu, Dec 21, 2017 at 12:34 PM, Barry <barry@barrys-emacs.org> wrote:
On 21 Dec 2017, at 06:57, Chris Barker <chris.barker@noaa.gov> wrote:
in theory, the "goal" is for eval(repr(obj)) to return an equivelent object
Is that really was the goal of repr? If true then we would not need pickle.
I have always assumed that repr of simple things aims to represent them in just the way you would write them in python code. Repr of complex things represents the obj as a useful summary.
Lamba seems to be in the complex end of things.
In debug logs I am often very interested in object identity and use the 0x123 as one way to know. Removing the unique id would be a regression in my eyes.
Maybe what you would like to have is an explain function that given any object tells you alll about it. help function does some of this I guess.
Barry
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Dec 21, 2017 at 12:34 PM, Barry <barry@barrys-emacs.org> wrote:
On 21 Dec 2017, at 06:57, Chris Barker <chris.barker@noaa.gov> wrote:
in theory, the "goal" is for eval(repr(obj)) to return an equivalent object
Is that really was the goal of repr?
I think so -- see the current discussion about pprint and dict order....
If true then we would not need pickle.
well, it only a goal, and it's not going to work for complex objects... I have always assumed that repr of simple things aims to represent them
in just the way you would write them in python code. Repr of complex things represents the obj as a useful summary.
pretty much, yes.
Lamba seems to be in the complex end of things.
I think that's where the key disagreement comes in -- I think we'd al agree that regular, def-defined functions are well in the complex end of things. But lambda is limited to a single expression, so it can only get so complex -- granted you could nest a lot of parentheses and function calls and have a very complex expression, but the common use case is pretty compact. Some reprs will truncate the result if the objec is huge -- numpy arrays come to mind. In [14]: arr = np.array(range(10000)) In [15]: repr(arr) Out[15]: 'array([ 0, 1, 2, ..., 9997, 9998, 9999])' so if folks are worried that it could get too long, it could be limited. Though I note that lists don;t seem to do anything like that -- try a 10,000 element list. In debug logs I am often very interested in object identity and use the
0x123 as one way to know. Removing the unique id would be a regression in my eyes.
Every python object has an object identity, and the way to get it is with the id() function. The id is also part of the default object repr, but given that some, but only some objects have the id in their repr, it's probably better to use id() in you logs if you care. And in the case of lambda, wouldn't you rather see what the lambda actually WAS than what it's id is? Is there any downside other than backward compatibility concerns? -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On Fri, Dec 22, 2017 at 9:43 AM, Chris Barker <chris.barker@noaa.gov> wrote:
Every python object has an object identity, and the way to get it is with the id() function. The id is also part of the default object repr, but given that some, but only some objects have the id in their repr, it's probably better to use id() in you logs if you care.
And in the case of lambda, wouldn't you rather see what the lambda actually WAS than what it's id is?
Is there any downside other than backward compatibility concerns?
It's probably worth hanging onto the id, in case the same function (from the same line of code) is used in multiple contexts. But IMO having the text of the function would be very useful - as long as it can be done without costing too much time or memory. So I'm +0.75 on the idea, with the caveat that it'd have to be implemented and performance-tested to make sure it doesn't kill the common case of a lambda function being created, used, and then dropped (think of a sort key function, for instance). ChrisA
On 22 Dec. 2017 12:32 pm, "Chris Angelico" <rosuav@gmail.com> wrote: On Fri, Dec 22, 2017 at 9:43 AM, Chris Barker <chris.barker@noaa.gov> wrote:
Every python object has an object identity, and the way to get it is with the id() function. The id is also part of the default object repr, but given that some, but only some objects have the id in their repr, it's probably better to use id() in you logs if you care.
And in the case of lambda, wouldn't you rather see what the lambda actually WAS than what it's id is?
Is there any downside other than backward compatibility concerns?
It's probably worth hanging onto the id, in case the same function (from the same line of code) is used in multiple contexts. But IMO having the text of the function would be very useful - as long as it can be done without costing too much time or memory. So I'm +0.75 on the idea, with the caveat that it'd have to be implemented and performance-tested to make sure it doesn't kill the common case of a lambda function being created, used, and then dropped (think of a sort key function, for instance). Having the repr report the defining module name & line number in addition to the object ID could be a low cost way of making the definition easier to find without adding any overhead in the common case. Cheers, Nick. ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Serhiy, I like the idea, but in typeshed we have an agreement to always show a default value by an ellipsis. For example, definition like this: def fun(x, y, z=0): return x + y + z can be represented like this fun(x, y, z=...) or if one has annotations in the definition, then fun(x: int, y: int, z: int = ...) -> int So if you would make this change, I would prefer the existing "style". -- Ivan
participants (13)
-
Barry
-
Brett Cannon
-
Chris Angelico
-
Chris Barker
-
Eric Fahlgren
-
Franklin? Lee
-
Ivan Levkivskyi
-
Ivan Pozdeev
-
Nick Coghlan
-
Serhiy Storchaka
-
Steve Barnes
-
Steven D'Aprano
-
Terry Reedy