From jfine2358 at gmail.com Wed Aug 1 03:29:41 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 08:29:41 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Hi All I have two further questions. I'm keen to clarify what is the behaviour specified by PEP 505. I'm not, at this time, interested in why and how PEP 505 specifies behaviour. I just wish, through explicit examples, to clarify the behaviour that is specified. Here 'a' is an identifier. Consider the following 12 expressions (I use the word loosely). 1) a . b . c 2) (a . b) . c 3) a . (b . c) 4) a ?. b . c 5) (a ?. b) . c 6) a ?. (b . c) 7) a . b ?. c 8) (a . b) ?. c 9) a . (b ?. c) 10) a ?. b ?. c 11) (a .? b) ?. c 12) a ?. (b ?. c) Question A: Which of the expressions are NOT valid (Python + PEP 505) syntax? Question B: Which of the valid (Python + PEP 505) expressions are equivalent, for all possible values of 'a'. The answer depends, of course, on the exact text of PEP 505. I've not read PEP 505 that closely. My expectations, based on my Python experience, are that PEP 505 would be written so that: Answer A: Expressions 3, 6, 9 and 12 are invalid. The others are valid. Answer B: 1 and 2 are equivalent. Similarly 4 and 5. Similarly 7 and 8. Similarly 10 and 11. There are no other equivalences (for all values of 'a'). I would like to know if my answers to my questions are correct, and if not please may I be given correct answers. Thank you in advance. -- Jonathan From rosuav at gmail.com Wed Aug 1 03:34:18 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 1 Aug 2018 17:34:18 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: On Wed, Aug 1, 2018 at 5:29 PM, Jonathan Fine wrote: > Hi All > > I have two further questions. I'm keen to clarify what is the > behaviour specified by PEP 505. I'm not, at this time, interested in > why and how PEP 505 specifies behaviour. I just wish, through explicit > examples, to clarify the behaviour that is specified. > > Here 'a' is an identifier. Consider the following 12 expressions (I > use the word loosely). > > 1) a . b . c > 2) (a . b) . c > 3) a . (b . c) > > 4) a ?. b . c > 5) (a ?. b) . c > 6) a ?. (b . c) > > 7) a . b ?. c > 8) (a . b) ?. c > 9) a . (b ?. c) > > 10) a ?. b ?. c > 11) (a .? b) ?. c > 12) a ?. (b ?. c) > > Question A: Which of the expressions are NOT valid (Python + PEP 505) syntax? > Question B: Which of the valid (Python + PEP 505) expressions are > equivalent, for all possible values of 'a'. > > The answer depends, of course, on the exact text of PEP 505. I've not > read PEP 505 that closely. My expectations, based on my Python > experience, are that PEP 505 would be written so that: > > Answer A: Expressions 3, 6, 9 and 12 are invalid. The others are valid. Correct. After a dot (whether ?. or plain . ), you need a NAME, not any form of expression (test, expr, etc). > Answer B: 1 and 2 are equivalent. Similarly 4 and 5. Similarly 7 and > 8. Similarly 10 and 11. There are no other equivalences (for all > values of 'a'). Incorrect. The short-circuiting behaviour ends at any sort of grouping. It's like how "a < b < c" is not equivalent to "(a < b) < c", nor to "a < (b < c)". ChrisA From jfine2358 at gmail.com Wed Aug 1 03:40:20 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 08:40:20 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Hi Chris Thank you for your prompt reply. You wrote > Incorrect. The short-circuiting behaviour ends at any sort of > grouping. It's like how "a < b < c" is not equivalent to "(a < b) < > c", nor to "a < (b < c)". You've told me that my answer B is wrong. But you've not provided your correct answer. I'd be most grateful if you could tell me what are the equivalences between the 12 expressions I provided. -- Jonathan From rosuav at gmail.com Wed Aug 1 03:43:21 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 1 Aug 2018 17:43:21 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: On Wed, Aug 1, 2018 at 5:40 PM, Jonathan Fine wrote: > Hi Chris > > Thank you for your prompt reply. You wrote > >> Incorrect. The short-circuiting behaviour ends at any sort of >> grouping. It's like how "a < b < c" is not equivalent to "(a < b) < >> c", nor to "a < (b < c)". > > You've told me that my answer B is wrong. But you've not provided your > correct answer. I'd be most grateful if you could tell me what are the > equivalences between the 12 expressions I provided. Oh. The equivalent ones are #1 and #2, and #7 and #8, where this proposal doesn't change anything. Otherwise, they're not equivalent. (And you can test #1 and #2 with dis.dis().) ChrisA From jfine2358 at gmail.com Wed Aug 1 04:00:25 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 09:00:25 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Hi Chris You wrote: > Oh. The equivalent ones are #1 and #2, and #7 and #8, where this > proposal doesn't change anything. Otherwise, they're not equivalent. Are you sure. I'd also expect #10 and #11 to be equivalent. By the way, there's a typo in my examples: 11) (a .? b) ?. c -- Jonathan From rosuav at gmail.com Wed Aug 1 04:04:57 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 1 Aug 2018 18:04:57 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: On Wed, Aug 1, 2018 at 6:00 PM, Jonathan Fine wrote: > Hi Chris > > You wrote: > >> Oh. The equivalent ones are #1 and #2, and #7 and #8, where this >> proposal doesn't change anything. Otherwise, they're not equivalent. > > Are you sure. I'd also expect #10 and #11 to be equivalent. > > By the way, there's a typo in my examples: 11) (a .? b) ?. c Hmm. > 10) a ?. b ?. c > 11) (a ?. b) ?. c I would parse those differently, but you may be right that they'll always have the same final result. Technically they should result in different code, though. ChrisA From jfine2358 at gmail.com Wed Aug 1 04:45:37 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 09:45:37 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Hi Chris Thank you for your reply. I think we're making good progress. You wrote >> 10) a ?. b ?. c >> 11) (a ?. b) ?. c > > I would parse those differently, but you may be right that they'll > always have the same final result. I'd like to get some certainty on this. I'm not aware of any value of 'a' for which #10 and #11 give different values. Can you (or anyone else) think of any such value? > Technically they should result in different code, though. Maybe. We need to think. Should can be a difficult word. Elsewhere you have, as I recall, pointed out that if None: do_something() generates no code. Perhaps the compiler should collapse #11 to #10, if they are equivalent. But this is a side issue. So, are there any values of 'a' for which #10 and #11 don't give the same result? -- Jonathan From rosuav at gmail.com Wed Aug 1 04:49:30 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 1 Aug 2018 18:49:30 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: On Wed, Aug 1, 2018 at 6:45 PM, Jonathan Fine wrote: > Hi Chris > > Thank you for your reply. I think we're making good progress. > > You wrote > >>> 10) a ?. b ?. c >>> 11) (a ?. b) ?. c >> >> I would parse those differently, but you may be right that they'll >> always have the same final result. > > I'd like to get some certainty on this. I'm not aware of any value of > 'a' for which #10 and #11 give different values. Can you (or anyone > else) think of any such value? > >> Technically they should result in different code, though. > > Maybe. We need to think. Should can be a difficult word. Elsewhere you > have, as I recall, pointed out that > if None: > do_something() > generates no code. > > Perhaps the compiler should collapse #11 to #10, if they are > equivalent. But this is a side issue. > > So, are there any values of 'a' for which #10 and #11 don't give the > same result? I'm not prepared to put my neck out and say "They are absolutely identical" and have people jump on me with some technicality. What is your point here? ChrisA From jfine2358 at gmail.com Wed Aug 1 05:09:49 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 10:09:49 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Hi Chris We're discussing. > 10) a ?. b ?. c > 11) (a ?. b) ?. c I asked > So, are there any values of 'a' for which #10 and #11 don't give the > same result? You replied > I'm not prepared to put my neck out and say "They are absolutely > identical" and have people jump on me with some technicality. What is > your point here? I am willing to put my neck out and say a.b.c and (a.b).c are equivalent. And my understanding for PEP 505 is that #10 and #11 is that they are equivalent. You're right to be cautious. My understanding of PEP 505 is that #13. a ?. b ?. __str__ #14. (a ?. b) ?. __str__ are not equivalent. The first is None, and the other is None.__str__. That looks like a gotcha. (By the way, it was not my intention to catch you out. I'm simply looking for clarity. I wasn't aware of the gotcha until I started answering myself the question I had asked you.) However, the None object is somewhat special, in that all it's methods and double-under (dunder) methods. And one of them is __bool__. And we can't add or change the attributes of None. Chris, you don't have to reply to this. But I would be pleased if an expert could either tell me that my neck is safe, or produce a value of 'a' that cuts it off (so to speak). -- Jonathan From stephanh42 at gmail.com Wed Aug 1 05:26:38 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Wed, 1 Aug 2018 11:26:38 +0200 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Op wo 1 aug. 2018 10:50 schreef Chris Angelico : > On Wed, Aug 1, 2018 at 6:45 PM, Jonathan Fine wrote: > > Hi Chris > > > > Thank you for your reply. I think we're making good progress. > > > > You wrote > > > >>> 10) a ?. b ?. c > >>> 11) (a ?. b) ?. c > >> > >> I would parse those differently, but you may be right that they'll > >> always have the same final result. > > > > I'd like to get some certainty on this. I'm not aware of any value of > > 'a' for which #10 and #11 give different values. Can you (or anyone > > else) think of any such value? > > > >> Technically they should result in different code, though. > > > > Maybe. We need to think. Should can be a difficult word. Elsewhere you > > have, as I recall, pointed out that > > if None: > > do_something() > > generates no code. > > > > Perhaps the compiler should collapse #11 to #10, if they are > > equivalent. But this is a side issue. > > > > So, are there any values of 'a' for which #10 and #11 don't give the > > same result? > > I'm not prepared to put my neck out and say "They are absolutely > identical" and have people jump on me with some technicality. Let me stand up and claim that if a chain consists *only* of None-coalescing operations, then breaking up the chain by adding parentheses does not matter, ever. So a?.b?.c is equivalent to (a?.b)?.c What is > your point here? > It is useful to establish rules under which a chain can be factored. Stephan > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephanh42 at gmail.com Wed Aug 1 05:32:54 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Wed, 1 Aug 2018 11:32:54 +0200 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Op wo 1 aug. 2018 11:10 schreef Jonathan Fine : > > > You're right to be cautious. My understanding of PEP 505 is that > #13. a ?. b ?. __str__ > #14. (a ?. b) ?. __str__ > are not equivalent. The first is None, and the other is None.__str__. > That looks like a gotcha. > No. None.?__str__ produces None, even though None has a __str__ attribute. I am pretty sure a?.b?.c == (a?.b)?.c and more generically chain_A ?. chain_B == (chain_A) ?. chain_B Stephan > (By the way, it was not my intention to catch you out. I'm simply > looking for clarity. I wasn't aware of the gotcha until I started > answering myself the question I had asked you.) > > However, the None object is somewhat special, in that all it's methods > and double-under (dunder) methods. And one of them is __bool__. And > we can't add or change the attributes of None. > > Chris, you don't have to reply to this. But I would be pleased if an > expert could either tell me that my neck is safe, or produce a value > of 'a' that cuts it off (so to speak). > > -- > Jonathan > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 1 05:57:57 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 1 Aug 2018 19:57:57 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: On Wed, Aug 1, 2018 at 7:09 PM, Jonathan Fine wrote: > Hi Chris > > We're discussing. >> 10) a ?. b ?. c >> 11) (a ?. b) ?. c > > I asked >> So, are there any values of 'a' for which #10 and #11 don't give the >> same result? > > You replied >> I'm not prepared to put my neck out and say "They are absolutely >> identical" and have people jump on me with some technicality. What is >> your point here? > > I am willing to put my neck out and say a.b.c and (a.b).c are > equivalent. And my understanding for PEP 505 is that #10 and #11 is > that they are equivalent. The first pair are easily proven, since we can just probe existing code. >>> import dis >>> dis.dis(lambda a: a.b.c) 1 0 LOAD_FAST 0 (a) 2 LOAD_ATTR 0 (b) 4 LOAD_ATTR 1 (c) 6 RETURN_VALUE >>> dis.dis(lambda a: (a.b).c) 1 0 LOAD_FAST 0 (a) 2 LOAD_ATTR 0 (b) 4 LOAD_ATTR 1 (c) 6 RETURN_VALUE >>> Same byte code? Same result. Unless there's a bug in the peephole optimizer or something, which I doubt. ChrisA From jfine2358 at gmail.com Wed Aug 1 06:03:05 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 11:03:05 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180729055442.GH22554@ando.pearwood.info> <20180731174646.GE22431@ando.pearwood.info> <22124c7c-e0c6-5857-b2c7-4b162e908da2@mrabarnett.plus.com> Message-ID: Hi Stephan You wrote > Let me stand up and claim that if a chain consists *only* of None-coalescing > operations, then breaking up the chain by adding parentheses does not > matter, ever. You missed a post I made, 17 minutes before yours. I then believed that PEP 505 specified. #1. (None ?. dne) is None #2. (None ?. dne ?. __str__) is None #3. (None.__str__) is not None #4. ((None ?. dne) ?. __str__) is (None.__str__) After my last post, you wrote > None.?__str__ > produces None, even though None has a __str__ attribute. This surprises me. But I think it follows from the rules in https://www.python.org/dev/peps/pep-0505/#the-maybe-dot-and-maybe-subscript-operators My initial reading of >>> a ?. b was that if 'a' didn't have a 'b' attribute, then the result was None, whatever the string 'b'. In other words, the same as >> getattr(a, name, None) But you and I agree, I think, that PEP 505 specifies (in the cited page fragment) >>> a ?. anything is always None, whenever 'a' is None, and for any non-keyword identifier instead of 'anything'. Thank you for contributing this clarification. The abstract to PEP 505 writes === The "None-aware attribute access" operator ?. ("maybe dot") evaluates the complete expression if the left hand side evaluates to a value that is not None === This is, of course, informal prose. I'm now reading it carefully. Here's a specific example. >>> (42).__str__ >>> (42).str Traceback (most recent call last): AttributeError: 'int' object has no attribute 'str' >>> (42) ?. str I don't see how to apply the prose in the abstract to this last example. The left hand side is not None, so we "evaluate the complete expression". On one reading, this is a recursion. I'd very much appreciate some help here. -- Jonathan From steve at pearwood.info Wed Aug 1 09:12:35 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 1 Aug 2018 23:12:35 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: Message-ID: <20180801131235.GG22431@ando.pearwood.info> On Wed, Aug 01, 2018 at 11:03:05AM +0100, Jonathan Fine wrote: [...] > After my last post, you wrote > > None.?__str__ > > produces None, even though None has a __str__ attribute. > > This surprises me. But I think it follows from the rules in > https://www.python.org/dev/peps/pep-0505/#the-maybe-dot-and-maybe-subscript-operators Correct. None?.__str__ is equivalent to: _v = None if _v is not None: _v = _v.__str__ return _v (except no actual _v variable is created, and it is not literally a return statement). > My initial reading of > >>> a ?. b > was that if 'a' didn't have a 'b' attribute, then the result was None, > whatever the string 'b'. > > In other words, the same as > >> getattr(a, name, None) No. PEP 505 is for None-aware operators. It spends considerable time explaining that it treats None as special. It does not catch AttributeError from missing attributes. (45)?.upper() will fail with AttributeError, same as (45).upper() does. > The abstract to PEP 505 writes > === > The "None-aware attribute access" operator ?. ("maybe dot") evaluates > the complete expression if the left hand side evaluates to a value > that is not None > === > > This is, of course, informal prose. I'm now reading it carefully. > Here's a specific example. > > >>> (42).__str__ > > >>> (42).str > Traceback (most recent call last): > AttributeError: 'int' object has no attribute 'str' > >>> (42) ?. str > > I don't see how to apply the prose in the abstract to this last > example. The left hand side is not None, so we "evaluate the complete > expression". On one reading, this is a recursion. The phrasing could be clearer. Since 42 is not None, it evaluates (42).str which of course will fail with AttributeError. To be specific, it is equivalent to something like this pseudo-code: _v = 42 if _v is not None: _v = _v.str return _v (The same disclaimer about _v and return apply as earlier.) -- Steve From jfine2358 at gmail.com Wed Aug 1 10:04:40 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 15:04:40 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: <20180801131235.GG22431@ando.pearwood.info> References: <20180801131235.GG22431@ando.pearwood.info> Message-ID: Hi Steve Thank you for your reply. We're discussing the abstract to PEP 505, which writes === The "None-aware attribute access" operator ?. ("maybe dot") evaluates the complete expression if the left hand side evaluates to a value that is not None === I gave (42).str as an example. I wrote > I don't see how to apply the prose in the abstract to this last > example. The left hand side is not None, so we "evaluate the complete > expression". On one reading, this is a recursion. You wrote > The phrasing could be clearer. I think the phrasing could be considerably improved (see below). > Since 42 is not None, it evaluates (42).str > [...] Based on this hint, here's what I think is a better statement. === Let `lhs` be the value of the left hand side, and RHS the code fragment on the right hand side. If `lhs` is None, then the whole expression is `None`. Otherwise, `lhs . RHS` gives the value of the whole expression. === Please would the experts tell me: Is it true? And if true, is it better? And can it be improved? -- Jonathan From rosuav at gmail.com Wed Aug 1 10:08:30 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 2 Aug 2018 00:08:30 +1000 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180801131235.GG22431@ando.pearwood.info> Message-ID: On Thu, Aug 2, 2018 at 12:04 AM, Jonathan Fine wrote: > Hi Steve > > Thank you for your reply. > > We're discussing the abstract to PEP 505, which writes > === > The "None-aware attribute access" operator ?. ("maybe dot") evaluates > the complete expression if the left hand side evaluates to a value > that is not None > === > > I gave (42).str as an example. I wrote > >> I don't see how to apply the prose in the abstract to this last >> example. The left hand side is not None, so we "evaluate the complete >> expression". On one reading, this is a recursion. > > You wrote >> The phrasing could be clearer. > > I think the phrasing could be considerably improved (see below). > >> Since 42 is not None, it evaluates (42).str >> [...] > > Based on this hint, here's what I think is a better statement. > === > Let `lhs` be the value of the left hand side, and RHS the code > fragment on the right hand side. If `lhs` is None, then the whole > expression is `None`. Otherwise, `lhs . RHS` gives the value of the > whole expression. > === > > Please would the experts tell me: Is it true? And if true, is it > better? And can it be improved? It may be true, but it isn't better IMO - especially not for the abstract. It's unnecessarily pedantic. The current wording isn't ambiguous, because infinite recursion makes no sense. MAYBE change it to "evaluate the rest of the expression", but I don't see a problem with the current wording. ChrisA From jfine2358 at gmail.com Wed Aug 1 11:34:47 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 1 Aug 2018 16:34:47 +0100 Subject: [Python-ideas] PEP 505: None-aware operators In-Reply-To: References: <20180801131235.GG22431@ando.pearwood.info> Message-ID: Chris Angelico wrote: > It may be true, but it isn't better IMO - especially not for the > abstract. It's unnecessarily pedantic. The current wording isn't > ambiguous, because infinite recursion makes no sense. Thank you for this. Please take a look and compare https://www.python.org/dev/peps/pep-0505/#abstract https://www.python.org/dev/peps/pep-0572/#abstract I'd like to get an abstract for PEP 572 that is as concise and clear as that for PEP 505. My previous comment focused just on 'the sharp edge that cut me'. But the more I look at PEP 572, the more I see sharp edges (in the expression of the ideas in the PEP). Having said that, I hope now to return to lurking, until we have cover for the BDFL vacation. -- Jonathan From kenlhilton at gmail.com Thu Aug 2 05:35:11 2018 From: kenlhilton at gmail.com (Ken Hilton) Date: Thu, 2 Aug 2018 11:35:11 +0200 Subject: [Python-ideas] With expressions Message-ID: Hi, I don't know if someone has already suggested this before, but here goes: With expressions allow using the enter/exit semantics of the with statement inside an expression context. Examples: contents = f.read() with open('file') as f #the most obvious one multiplecontents = [f.read() with open(name) as f for name in names] #reading multiple files I don't know if it's worth making the "as NAME" part of the with mandatory in an expression - is this a valid use case? data = database.selectrows() with threadlock Where this would benefit: I think the major use case is `f.read() with open('file') as f`. Previous documentation has suggested `open('file').read()` and rely on garbage collection; as the disadvantages of that became obvious, it transitioned to a method that couldn't be done in an expression: with open('file') as f: contents = f.read() Therefore `f.read() with open('file') as f`, I think, would be much welcomed as the best way to read a file in an expression. For those wondering about the scope semantics of the "as NAME", I think they would be identical to the scope semantics of the "for" expression - i.e. these are legal: contents = f.read() with open('file') as f grid = [[i] * 4 for i in range(4)] But these are not: contents = f.read() with open('file') as f f.seek(0) grid = [[i] * 4 for i in range(4)] grid[i][i] = 4 Is this a good idea? Are there some subtleties I've failed to explain? Please let me know. Sharing, Ken Hilton -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Thu Aug 2 05:53:22 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 2 Aug 2018 10:53:22 +0100 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: On Thu, 2 Aug 2018 at 10:39, Ken Hilton wrote: > With expressions allow using the enter/exit semantics of the with statement inside an expression context. Examples: > > contents = f.read() with open('file') as f #the most obvious one > multiplecontents = [f.read() with open(name) as f for name in names] #reading multiple files > > I don't know if it's worth making the "as NAME" part of the with mandatory in an expression - is this a valid use case? > > data = database.selectrows() with threadlock > > Where this would benefit: I think the major use case is `f.read() with open('file') as f`. Previous documentation has suggested `open('file').read()` and rely on garbage collection; as the disadvantages of that became obvious, it transitioned to a method that couldn't be done in an expression: That use case is satisfied by pathlib: Path('file').read_text() see https://docs.python.org/3.7/library/pathlib.html#pathlib.Path.read_text Are there any other use cases? I don't see any real advantage here other than the non-advantage of being able to write one-liners. Paul From ml+python-ideas at thomasnyberg.com Thu Aug 2 06:23:50 2018 From: ml+python-ideas at thomasnyberg.com (Thomas Nyberg) Date: Thu, 2 Aug 2018 12:23:50 +0200 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: Is it true that Path('file').read_text() closes the file after the read? I think that is the sort of functionality that Ken is asking for. It's not clear to me by your linked documentation that it does. If it does, maybe that should be made more clear in that linked documentation? (Of course, maybe it's written there somewhere and I'm just blind...) Cheers, Thomas On 08/02/2018 11:53 AM, Paul Moore wrote: > On Thu, 2 Aug 2018 at 10:39, Ken Hilton wrote: > >> With expressions allow using the enter/exit semantics of the with statement inside an expression context. Examples: >> >> contents = f.read() with open('file') as f #the most obvious one >> multiplecontents = [f.read() with open(name) as f for name in names] #reading multiple files >> >> I don't know if it's worth making the "as NAME" part of the with mandatory in an expression - is this a valid use case? >> >> data = database.selectrows() with threadlock >> >> Where this would benefit: I think the major use case is `f.read() with open('file') as f`. Previous documentation has suggested `open('file').read()` and rely on garbage collection; as the disadvantages of that became obvious, it transitioned to a method that couldn't be done in an expression: > > That use case is satisfied by pathlib: > > Path('file').read_text() > > see https://docs.python.org/3.7/library/pathlib.html#pathlib.Path.read_text > > Are there any other use cases? I don't see any real advantage here > other than the non-advantage of being able to write one-liners. > Paul > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > From andre.roberge at gmail.com Thu Aug 2 06:35:43 2018 From: andre.roberge at gmail.com (Andre Roberge) Date: Thu, 2 Aug 2018 07:35:43 -0300 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: On Thu, Aug 2, 2018 at 7:24 AM Thomas Nyberg via Python-ideas < python-ideas at python.org> wrote: > Is it true that Path('file').read_text() cl > oses the file after the read? > I think that is the sort of functionality that Ken is asking for. > It's not clear to me by your linked documentation that it does. If it > does, maybe that should be made more clear in that linked documentation? > Agreed. Then again, the documentation includes a link to the source at the top and we find ( https://github.com/python/cpython/blob/3.7/Lib/pathlib.py#L1174) docstring: Open the file in text mode, read it, and close the file. Or ... >>> import pathlib >>> help(pathlib.Path.read_text) Help on function read_text in module pathlib: read_text(self, encoding=None, errors=None) Open the file in text mode, read it, and close the file. The documentation would be improved if it used the text from the docstring instead of its own one-line description. Andr? Roberge > (Of course, maybe it's written there somewhere and I'm just blind...) > > Cheers, > Thomas > > On 08/02/2018 11:53 AM, Paul Moore wrote: > > On Thu, 2 Aug 2018 at 10:39, Ken Hilton wrote: > > > >> With expressions allow using the enter/exit semantics of the with > statement inside an expression context. Examples: > >> > >> contents = f.read() with open('file') as f #the most obvious one > >> multiplecontents = [f.read() with open(name) as f for name in > names] #reading multiple files > >> > >> I don't know if it's worth making the "as NAME" part of the with > mandatory in an expression - is this a valid use case? > >> > >> data = database.selectrows() with threadlock > >> > >> Where this would benefit: I think the major use case is `f.read() with > open('file') as f`. Previous documentation has suggested > `open('file').read()` and rely on garbage collection; as the disadvantages > of that became obvious, it transitioned to a method that couldn't be done > in an expression: > > > > That use case is satisfied by pathlib: > > > > Path('file').read_text() > > > > see > https://docs.python.org/3.7/library/pathlib.html#pathlib.Path.read_text > > > > Are there any other use cases? I don't see any real advantage here > > other than the non-advantage of being able to write one-liners. > > Paul > > _______________________________________________ > > Python-ideas mailing list > > Python-ideas at python.org > > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Thu Aug 2 06:43:46 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 2 Aug 2018 11:43:46 +0100 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: On Thu, 2 Aug 2018 at 11:25, Thomas Nyberg via Python-ideas wrote: > > Is it true that Path('file').read_text() closes the file after the read? > I think that is the sort of functionality that Ken is asking for. > It's not clear to me by your linked documentation that it does. If it > does, maybe that should be made more clear in that linked documentation? > (Of course, maybe it's written there somewhere and I'm just blind...) I'm not sure I see why you think it wouldn't - opening and closing the file is a purely internal detail of the function. In any case, you don't get given a file object, so how could anything *other* than the read_text() close the file? So you're basically asking "does Path.read_text() have a bug that causes it to leak a filehandle?" to which my answer would be "I assume not, until someone demonstrates such a bug". But if someone wanted to raise a doc bug suggesting that we mention this, I'm not going to bother objecting... Paul From ml+python-ideas at thomasnyberg.com Thu Aug 2 07:41:18 2018 From: ml+python-ideas at thomasnyberg.com (Thomas Nyberg) Date: Thu, 2 Aug 2018 13:41:18 +0200 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <0ba9ca17-e168-a742-1595-8c9ead0b2244@thomasnyberg.com> On 08/02/2018 12:43 PM, Paul Moore wrote: > I'm not sure I see why you think it wouldn't - opening and closing the > file is a purely internal detail of the function. In any case, you > don't get given a file object, so how could anything *other* than the > read_text() close the file? So you're basically asking "does > Path.read_text() have a bug that causes it to leak a filehandle?" to > which my answer would be "I assume not, until someone demonstrates > such a bug". To me the following look the same: Path('file').read_text() open('file').read() The first presumably creates a Path object while the second creates a file object. Why should I assume that the Path object closes the underlying file object after the method is called? I mean maybe my assumption is bad, but I doubt I'd be the only one making it given how open() works and that it looks similar superficially. Cheers, Thomas From ml+python-ideas at thomasnyberg.com Thu Aug 2 07:53:51 2018 From: ml+python-ideas at thomasnyberg.com (Thomas Nyberg) Date: Thu, 2 Aug 2018 13:53:51 +0200 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <2e31b56b-1f3a-beb4-fd05-24e00b516f1b@thomasnyberg.com> On 08/02/2018 12:43 PM, Paul Moore wrote: > But if someone wanted to raise a doc bug suggesting that we mention > this, I'm not going to bother objecting... > Paul > I opened a bug here: https://bugs.python.org/issue34319 We can see what others think. Cheers, Thomas From steve at pearwood.info Thu Aug 2 07:56:13 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 2 Aug 2018 21:56:13 +1000 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <20180802115613.GJ22431@ando.pearwood.info> On Thu, Aug 02, 2018 at 11:35:11AM +0200, Ken Hilton wrote: > Where this would benefit: I think the major use case is `f.read() with > open('file') as f`. [...] > Therefore `f.read() with open('file') as f`, I think, would be much > welcomed as the best way to read a file in an expression. Perhaps so, but do we want to encourage that to the point of adding syntax to make it easier? f.read() is a (mild) code-smell. Unless your file is guaranteed to be smaller than the amount of free memory, it risks starting your OS thrashing. IMO that makes this an idiom only suitable for quick and dirty scripts where the the user knows the limitations of the script and can abide by them. (In these days of computers with multiple gigabytes of RAM, reading in an entire file is not as risky as it used to be. But on the other hand, in these days of terrabyte and even petabyte storage devices, there are more *really large* files too.) Don't get me wrong -- f.read() is not necessarily bad. I often write scripts that slurp in an entire file at once, but they're typically throw-away scripts, and I'm also the user of the script and I know not to call it on files above a certain size. (As Miss Piggy once said, "Never eat more in one sitting than you can lift.") But I'm not sure if this sort of thing is something we want to *encourage* rather than merely *allow*. Best practice for reading files is, after all, a with statement for a reason: we expect to read text files line by line, often wrapped in a try...except to handle exceptions. For your use-case, I suspect the best thing is a utility function: def read(name, size=-1, **kwargs): with open(name, **kwargs) as f: return f.read(size) Not every three-line function needs to be a built-in, let alone given syntax :-) > For those wondering about the scope semantics of the "as NAME", I think > they would be identical to the scope semantics of the "for" expression Its not really a "for expression" -- its a *comprehension*, which is much more than merely a for expression: # this isn't legal result = for x in seq One important difference is that unlike this proposed "with" expression, comprehensions have an obvious pair of delimiters which enclose the expression and give it a natural beginning and end. There's no need to memorise arcane operator precedences and parsing rules to work out where the "with...as" variable will be legal. Another important difference is that while there are good reasons for putting comprehension loop variables in their own sub-local scope, I don't see any such benefit to doing the same for this proposed with expression. I don't think we should encourage the proliferation of more and more layers of extra scopes. We already have six: sublocal (comprehensions) local nonlocal (enclosing functions) class global (module) builtins Let's be cautious about adding more varieties of sublocal scope. -- Steve From cody.piersall at gmail.com Thu Aug 2 09:10:56 2018 From: cody.piersall at gmail.com (Cody Piersall) Date: Thu, 2 Aug 2018 08:10:56 -0500 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: On Thu, Aug 2, 2018 at 5:24 AM Thomas Nyberg via Python-ideas wrote: > > Is it true that Path('file').read_text() closes the file after the read? A quick look at the source confirms that the file is closed: https://github.com/python/cpython/blob/master/Lib/pathlib.py#L1174 The docstring is better than the official documentation, in my opinion. Cody From robertve92 at gmail.com Thu Aug 2 09:13:25 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Thu, 2 Aug 2018 15:13:25 +0200 Subject: [Python-ideas] With expressions In-Reply-To: <20180802115613.GJ22431@ando.pearwood.info> References: <20180802115613.GJ22431@ando.pearwood.info> Message-ID: This brings the discussion of variable assignement in Expression. Functional programming community seems to be more interested in python. lines = (f.readlines() with open('hello') as f) digit = (int('hello') except ValueError: 5) value = (x+y**2 where x,y = (2,4)) values = [x+y**2 for x in range(5) for y in range(7)] values = [x+y**2 for x,y in product (range(5), range(7))] y = 5 if condition else 2 y = (lambda x: x+2)(x=5) vs with open('hello') as f: lines = f.readlines() del f # f is leaked ! x,y = 2,4 value = x+y**2 del x, y # x,y are leaked ! try: digit = (int('hello') except ValueError: digit = 5 if condition: y = 5 else: y = 2 def f(x): return x+2 y = f(x=2) del f # we want an anonymous function ! Those "oneliners" is not only the will to be quicker in interactive mode, it's the way functional programming Thinks. If we add one, it's Logical to add the others to be consistent. Of course, one can always write functions like read_text but the ide of those construction is like the lambda, we want anonymous. Le jeu. 2 ao?t 2018 ? 13:56, Steven D'Aprano a ?crit : > On Thu, Aug 02, 2018 at 11:35:11AM +0200, Ken Hilton wrote: > > > Where this would benefit: I think the major use case is `f.read() with > > open('file') as f`. > [...] > > Therefore `f.read() with open('file') as f`, I think, would be much > > welcomed as the best way to read a file in an expression. > > Perhaps so, but do we want to encourage that to the point of adding > syntax to make it easier? > > f.read() is a (mild) code-smell. Unless your file is guaranteed to be > smaller than the amount of free memory, it risks starting your OS > thrashing. IMO that makes this an idiom only suitable for quick and > dirty scripts where the the user knows the limitations of the script and > can abide by them. > > (In these days of computers with multiple gigabytes of RAM, reading in > an entire file is not as risky as it used to be. But on the other hand, > in these days of terrabyte and even petabyte storage devices, there are > more *really large* files too.) > > Don't get me wrong -- f.read() is not necessarily bad. I often write > scripts that slurp in an entire file at once, but they're typically > throw-away scripts, and I'm also the user of the script and I know not > to call it on files above a certain size. (As Miss Piggy once said, > "Never eat more in one sitting than you can lift.") > > But I'm not sure if this sort of thing is something we want to > *encourage* rather than merely *allow*. Best practice for reading files > is, after all, a with statement for a reason: we expect to read text > files line by line, often wrapped in a try...except to handle > exceptions. > > For your use-case, I suspect the best thing is a utility function: > > def read(name, size=-1, **kwargs): > with open(name, **kwargs) as f: > return f.read(size) > > Not every three-line function needs to be a built-in, let alone > given syntax :-) > > > > For those wondering about the scope semantics of the "as NAME", I think > > they would be identical to the scope semantics of the "for" expression > > Its not really a "for expression" -- its a *comprehension*, which is > much more than merely a for expression: > > # this isn't legal > result = for x in seq > > One important difference is that unlike this proposed "with" expression, > comprehensions have an obvious pair of delimiters which enclose the > expression and give it a natural beginning and end. There's no need to > memorise arcane operator precedences and parsing rules to work out where > the "with...as" variable will be legal. > > Another important difference is that while there are good reasons for > putting comprehension loop variables in their own sub-local scope, I > don't see any such benefit to doing the same for this proposed with > expression. I don't think we should encourage the proliferation of more > and more layers of extra scopes. We already have six: > > sublocal (comprehensions) > local > nonlocal (enclosing functions) > class > global (module) > builtins > > > Let's be cautious about adding more varieties of sublocal scope. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From storchaka at gmail.com Thu Aug 2 09:13:53 2018 From: storchaka at gmail.com (Serhiy Storchaka) Date: Thu, 2 Aug 2018 16:13:53 +0300 Subject: [Python-ideas] Change repr of collections.OrderedDict to be more dict-like In-Reply-To: References: <378a7b7d-eb60-0a90-1f35-802913b6b501@redhat.com> <20180727052246.GA22554@ando.pearwood.info> <20180727055840.GC22554@ando.pearwood.info> Message-ID: 27.07.18 16:29, Chris Angelico ????: > Ah, fair point. Interestingly, the same problem hits repr(dict(od)), > which I would have thought a reliable solution here. The simplest way > that I've found is: > >>>> dict(od.items()) > {'b': 2, 'a': 1} > > That seems very odd. Iterating over the OD produces its keys in the > correct order (b, a), but constructing a dict from it ignores > iteration order and just goes "oh hey, this is a dict, we can snag > that". Is that correct? This looks like a bug to me. Opened https://bugs.python.org/issue34320 . From davidfstr at gmail.com Thu Aug 2 10:37:49 2018 From: davidfstr at gmail.com (David Foster) Date: Thu, 2 Aug 2018 07:37:49 -0700 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: Message-ID: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> RE none-aware operators in general: +1 overall for the latest version of PEP 505 and the utility of ?? in particular. There are several places in my code that could be simplified with ??. find-pep505.py on my current Django-oriented codebase gives: Total None-coalescing `if` blocks: 43 Total [possible] None-coalescing `or`: 4 Total None-coalescing ternaries: 8 Total Safe navigation `and`: 0 Total Safe navigation `if` blocks: 6 Total Safe navigation ternaries: 17 RE OR and ||: * -1 for "OR" as an operator. Insufficiently distinct from "or". Reads the same out loud despite being a different operator. * -1 for "||" with none-aware semantics. This differs from the semantics in every C-derived language I can think of, which will be confusing to several other developers. David Foster | Seattle, WA, USA On 7/19/18 5:30 AM, Jonathan Fine wrote: > Hi > >> There is a formatted version of this PEP at >> https://www.python.org/dev/peps/pep-0505/ > > I've taken a look at this, and have some comments on the first two > examples drawn from standard library code. (And a very grateful +10 > for writing a script to find such examples.) > > I've started a subthread, just to discuss the ?= and ?? operators. And > something newish, that I call OR. > > FIRST EXAMPLE > The first example is > --- > From bisect.py: > def insort_right(a, x, lo=0, hi=None): > # ... > if hi is None: > hi = len(a) > --- > > Here, None is a sentinel value. The simpler code > --- > hi = hi or len(a) > --- > fails when hi is zero (or any other value that is False in the boolean context). > > This can be fixed by introducing a new operator OR which is similar to > 'or' but has the semantics this example requires. Thus, given OR we > can write > --- > hi = hi OR len(a) > --- > where (A OR B) returns A if A is not None, otherwise it returns B. > > (Recall that (A or B) returns A if bool(A), otherwise it returns B.) > > SECOND EXAMPLE > The second example is > --- > From calendar.py: > encoding = options.encoding > if encoding is None: > encoding = sys.getdefaultencoding() > optdict = dict(encoding=encoding, css=options.css) > --- > > Once we have OR we would write this as > --- > encoding = encoding OR sys.getdefaultencoding() > optdict = dict(encoding=encoding, css=options.css) > --- > > And from here we can condense into a single (longish) line: > --- > optdict = dict(encoding=encoding OR sys.getdefaultencoding(), css=options.css) > -- > > SUMMARY > Here, for reference, are the suggestions using ?= and ?? in PEP 505. > --- > hi ??= len(a) > --- > optdict = dict(encoding=encoding ?? sys.getdefaultencoding(), css=options.css) > --- > > Comments ?? suggestions. For example, would a None-aware AND operator be useful? > From paal.drange at gmail.com Thu Aug 2 12:50:47 2018 From: paal.drange at gmail.com (=?UTF-8?B?UMOlbCBHcsO4bsOlcyBEcmFuZ2U=?=) Date: Thu, 2 Aug 2018 18:50:47 +0200 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> Message-ID: > Reads the same out loud despite being a different operator. How are `??`, `.?`, and the others pronounced? dhuh, dothuh? Or just read the expressions as if it were a question? -1 on 505, +1 on waiting a while with introducing new syntax P?l -------------- next part -------------- An HTML attachment was scrubbed... URL: From ericfahlgren at gmail.com Thu Aug 2 15:03:34 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Thu, 2 Aug 2018 12:03:34 -0700 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> Message-ID: >From the PEP: > >From email/generator.py (and importantly note that there is no way to substitute or for ?? in this situation): > mangle_from_ = True if policy is None else policy.mangle_from_ > After updating: > mangle_from_ = policy?.mangle_from_ ?? True I cannot see how these are equivalent, and cannot understand what the cryptic comment means. >>> policy.mangle_from_ = None >>> True if policy is None else policy.mangle_from_ None >>> policy?.mangle_from_ ?? True True (??? since lhs is None?) -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 2 15:20:47 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 2 Aug 2018 20:20:47 +0100 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> Message-ID: Hi Eric [Steve Dower: Eric seems to have found a bug in the PEP. Where to report?] You quoted, from PEP 505, Before > mangle_from_ = True if policy is None else policy.mangle_from_ After > mangle_from_ = policy?.mangle_from_ ?? True You then remarked > I cannot see how these are equivalent I don't see the equivalence either. If `policy.mangle_from_ is None` then surely Before gives None, while After gives True. Here's the process for filing bugs in a PEP https://www.python.org/dev/peps/pep-0001/#reporting-pep-bugs-or-submitting-pep-updates As we seem to be in early draft stage, perhaps communicate first with PEP author (Steve Dower, copied). -- Jonathan From tjreedy at udel.edu Thu Aug 2 16:13:26 2018 From: tjreedy at udel.edu (Terry Reedy) Date: Thu, 2 Aug 2018 16:13:26 -0400 Subject: [Python-ideas] With expressions In-Reply-To: <2e31b56b-1f3a-beb4-fd05-24e00b516f1b@thomasnyberg.com> References: <2e31b56b-1f3a-beb4-fd05-24e00b516f1b@thomasnyberg.com> Message-ID: On 8/2/2018 7:53 AM, Thomas Nyberg via Python-ideas wrote: > On 08/02/2018 12:43 PM, Paul Moore wrote: >> But if someone wanted to raise a doc bug suggesting that we mention >> this, I'm not going to bother objecting... >> Paul >> > > I opened a bug here: > > ????https://bugs.python.org/issue34319 > > We can see what others think. I suggested on the issue that we add "The file is opened and then closed." before "The optional parameters have the same meaning as in open()." Another option would be to add "The file is closed after reading." after the latter sentence. -- Terry Jan Reedy From python at mrabarnett.plus.com Thu Aug 2 16:19:10 2018 From: python at mrabarnett.plus.com (MRAB) Date: Thu, 2 Aug 2018 21:19:10 +0100 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> Message-ID: <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> On 2018-08-02 20:03, Eric Fahlgren wrote: > From the PEP: > > > From email/generator.py (and importantly note that there is no way to > substitute or for ?? in this situation): > > > mangle_from_ = True if policy is None else policy.mangle_from_ > > After updating: > > > mangle_from_ = > policy?.mangle_from_ ?? True > > I cannot see how these are equivalent, and cannot understand what the > cryptic comment means. > If there's a policy, use policy.mangle_from_. If there's no policy, default to True. The comment is a reminder that you can't use 'or' instead of '??' because 'policy.mangle_from_' could be False and you don't want it to default to True in that case. > >>> policy.mangle_from_ = None > >>> > True if policy is None else policy.mangle_from_ > None > > >>> > policy?.mangle_from_ ?? True > True (??? since lhs is None?) > No, it's not 'policy.mangle_from_' that could be None, it's 'policy' that could be None (i.e. there's no policy). From ericfahlgren at gmail.com Thu Aug 2 17:49:24 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Thu, 2 Aug 2018 14:49:24 -0700 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> Message-ID: On Thu, Aug 2, 2018 at 1:22 PM MRAB wrote: > > policy?.mangle_from_ ?? True > > True (??? since lhs is None?) > > > No, it's not 'policy.mangle_from_' that could be None, it's 'policy' > that could be None (i.e. there's no policy). > In my example, there is a policy, and the value of policy.mangle_from_ is set to None. Thus the above should be equivalent to this >>> None ?? True True Unless, of course, I completely misunderstand the way the ?? operator works. This is not the same as the original code, they are not equivalent. -------------- next part -------------- An HTML attachment was scrubbed... URL: From python at mrabarnett.plus.com Thu Aug 2 18:38:29 2018 From: python at mrabarnett.plus.com (MRAB) Date: Thu, 2 Aug 2018 23:38:29 +0100 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> Message-ID: <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> On 2018-08-02 22:49, Eric Fahlgren wrote: > > On Thu, Aug 2, 2018 at 1:22 PM MRAB > wrote: > > > policy?.mangle_from_ ?? True > > True (??? since lhs is None?) > > > No, it's not 'policy.mangle_from_' that could be None, it's 'policy' > that could be None (i.e. there's no policy). > > > In my example, there is a policy, and the value of policy.mangle_from_ > is set to None.? Thus the above should be equivalent to this > > >>> None ?? True > True > > Unless, of course, I completely misunderstand the way the ?? operator > works.? This is not the same as the original code, they are not > equivalent. In the relevant code, is policy.mangle_from_ ever None? From ericfahlgren at gmail.com Thu Aug 2 19:01:04 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Thu, 2 Aug 2018 16:01:04 -0700 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> Message-ID: On Thu, Aug 2, 2018 at 3:39 PM MRAB wrote: > In the relevant code, is policy.mangle_from_ ever None? > That's impossible to know, since the initializer where this code originally appears puts no constraints on the value of 'policy', it's just assumed to have a 'mangle_from_' member... I would be paranoid and assume, yes, it can take on a value of None as there's nothing to indicate that it can't. class Generator: ... def __init__(self, outfp, mangle_from_=None, maxheaderlen=None, *, policy=None): ... if mangle_from_ is None: mangle_from_ = True if policy is None else policy.mangle_from_ self._fp = outfp self._mangle_from_ = mangle_from_ -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Thu Aug 2 19:35:19 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 3 Aug 2018 09:35:19 +1000 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> Message-ID: <20180802233518.GK22431@ando.pearwood.info> On Thu, Aug 02, 2018 at 06:50:47PM +0200, P?l Gr?n?s Drange wrote: > > Reads the same out loud despite being a different operator. > > How are `??`, `.?`, and the others pronounced? Did you read the PEP? It answers that question. https://www.python.org/dev/peps/pep-0505/#reading-expressions I'm happy to read them as: spam ?? eggs spam maybe eggs spam or eggs if None spam?.eggs spam maybe-dot eggs spam dot eggs if not None etc depending on context. But I expect that some clever person will think up a nickname for it, like the Elvis operator: https://en.wikipedia.org/wiki/Elvis_operator -- Steve From steve at pearwood.info Thu Aug 2 20:53:06 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 3 Aug 2018 10:53:06 +1000 Subject: [Python-ideas] With expressions In-Reply-To: References: <20180802115613.GJ22431@ando.pearwood.info> Message-ID: <20180803005305.GM22431@ando.pearwood.info> On Thu, Aug 02, 2018 at 03:13:25PM +0200, Robert Vanden Eynde wrote: > This brings the discussion of variable assignement in Expression. Functional > programming community seems to be more interested in python. I'm not sure what you mean there. Your English grammar is just slightly off, enough to make your meaning unclear, sorry. > lines = (f.readlines() with open('hello') as f) readlines has the same problems as read, as I described earlier, and the same trivial three-line solution. > digit = (int('hello') except ValueError: 5) try...except exceptions have been proposed before and rejected. > value = (x+y**2 where x,y = (2,4)) A "where" *statement* is interesting, but this is not a good example of it. The above is better written in the normal syntax: value = 2 + 4**2 no need to introduce temporary variables that exist only to obfuscate the code. > values = [x+y**2 for x in range(5) for y in range(7)] > values = [x+y**2 for x,y in product (range(5), range(7))] > y = 5 if condition else 2 These already exist, because they are useful. > y = (lambda x: x+2)(x=5) This is not a good example of the use of a lambda. Better: y = 5 + 2 Why bother writing a function with such a simple body if you are going to immediately call it on the spot? Unless the body is more complex, or you are going to call it elsewhere, or call it repeatedly, the lambda adds nothing. Nobody denies that *some* statements are well-suited and useful as expressions. The question is whether "with" is one of those. > with open('hello') as f: > lines = f.readlines() > del f # f is leaked ! 99% of the time, I would think that "del f" was a waste of time. If that code is in function, then f will be closed when the "with" block is exited, and garbage collected when the function returns. If you are worried about the memory efficiency of one tiny closed file object, then Python is the wrong language for you. If that code is in the top-level of a script, who cares about f? You surely don't delete all your variables when you are done with them: name = input("what is your name?") print("Hello,", name) del name play_game() The only time I would explicitly delete f like you do above was if I was writing a library which specifically and explicitly supported the "from module import *" syntax, AND there were too many exportable names to list them all in __all__ by hand. Only in that very rare case would I care about tidying up the global namespace by using del. > x,y = 2,4 > value = x+y**2 > del x, y # x,y are leaked ! If you are writing code like this, you are just obscuring the code. Much better to just use the values where you need them, not to invent unnecessary temporary variables that you don't need! value = 2 + 4**2 [...] > If we add one, it's Logical to add the others to be consistent. My car has round wheels. Since we use one shape (circle) for wheels, it must be "logical" to make wheels in all other shapes, to be consistent: - triangular wheels - square wheels etc. Consistency just for the sake of consistency is *not* a virtue. Unless those expression forms justify *themselves* on their own merits, it is just a waste of time and effort to let them sneak into the language "for consistency". > Of course, one can always write functions like read_text but the ide of > those construction is like the lambda, we want anonymous. We can say: text = read('filename') text = f.read() with open('filename') as f and both are equally unanonymous (both use a named variable), or we can say: process(spam, eggs, read('filename'), foo, bar) process(spam, eggs, f.read with open('filename') as f, foo, bar) and both are equally anonymous. If Python had a built-in function "read", surely you wouldn't refuse to use it because it was a named function? We don't complain that map() and filter() are named functions and demand "anonymous" ways to do the same thing. A read function should be no different. The only point of difference is that it is not built-in, you have to write it yourself. But not every trivial three-line function must be built-in. -- Steve From abrault at mapgears.com Fri Aug 3 00:58:08 2018 From: abrault at mapgears.com (Alexandre Brault) Date: Fri, 3 Aug 2018 00:58:08 -0400 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> Message-ID: <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> On 2018-08-02 7:01 PM, Eric Fahlgren wrote: > On Thu, Aug 2, 2018 at 3:39 PM MRAB > wrote: > > In the relevant code, is policy.mangle_from_ ever None? > > > That's impossible to know, since the initializer where this code > originally appears puts no constraints on the value of 'policy', it's > just assumed to have a 'mangle_from_' member...? I would be paranoid > and assume, yes, it can take on a value of None as there's nothing to > indicate that it can't. > I would make the opposite argument and claim that since when policy is None mangle_from_ is initialised to True and not None, None is likely not a potential value for policy.mangle_from_. Looking at Lib/email/_policybase.py where the abstract policy class in question is defined, policies default their mangle_from_ to False, which gives additional credence to the notion that policy.mangle_from_ is not meant to be None. So yes, *strictly speaking* the two chunks of code are not exactly the same. In practice, they'll act the same way given sensible inputs. Alex -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Fri Aug 3 04:16:13 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Fri, 3 Aug 2018 09:16:13 +0100 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> Message-ID: Hi Alexandre Thank you for your post. In PEP 505 the context for the example being discussed is: > Some of these are shown below as examples before and after converting to use the new operators. You wrote: > So yes, *strictly speaking* the two chunks of code are not exactly the same. I see nothing in the context that indicates that given suitable (Python) context, the before and after expressions give different values. I assumed the before and after values were intended to be the same. By the way, I think that even without your *strictly speaking*, the two chunks of code are not exactly the same (in that they can give different values from identical inputs). > In practice, they'll act the same way given sensible inputs. For me, the truth or falsity of this statement requires more than the peep-hole view of the code supplied by the PEP. Your argument for its truth certainly looked beyond the PEP. I think lack of clarity can mislead, and prevents the PEP performing properly one of its key functions === https://www.python.org/dev/peps/pep-0001/#what-is-a-pep The PEP should provide a concise technical specification of the feature and a rationale for the feature [being proposed]. === and so is a bug in the PEP. Fixing it will help the progress of the PEP. Where to report the bug? Either to Steve Dower, or raise an issue on github. https://www.python.org/dev/peps/pep-0001/#reporting-pep-bugs-or-submitting-pep-updates Steve's already been emailed on this. We're waiting to hear back from him. -- Jonathan From robertve92 at gmail.com Fri Aug 3 06:49:24 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Fri, 3 Aug 2018 12:49:24 +0200 Subject: [Python-ideas] With expressions In-Reply-To: <20180803005305.GM22431@ando.pearwood.info> References: <20180802115613.GJ22431@ando.pearwood.info> <20180803005305.GM22431@ando.pearwood.info> Message-ID: Thanks for answering each line. If someone wants "too long didn't read", just check my code at the paragraph "readlines is a toy example, but maybe the code would be more creative". Le ven. 3 ao?t 2018 ? 03:07, Steven D'Aprano a ?crit : > On Thu, Aug 02, 2018 at 03:13:25PM +0200, Robert Vanden Eynde wrote: > > > This brings the discussion of variable assignement in Expression. > Functional > > programming community seems to be more interested in python. > > I'm not sure what you mean there. Your English grammar is just slightly > off, enough to make your meaning unclear, sorry. > When I say "functional programming", I speak about the paradigm used in language like Haskell. In language like those, all constructs are "expression-based". I consider the code "result = 5 if condition else 2" more "functional style" than "if condition: result = 5; else: result = 2". Functional style focus on the result, uses expressions. Imperative focus on the process, "we must do a condition, then we set the variable, else, we set a variable to something else". > > > lines = (f.readlines() with open('hello') as f) > > readlines has the same problems as read, as I described earlier, and the > same trivial three-line solution. > > > > digit = (int('hello') except ValueError: 5) > > try...except exceptions have been proposed before and rejected. > I'm wondering why, that must have been the same reasons of not accepting "with". if condition: something = x else: something = y Can be refactored something = x if condition else y Or something = (x if condition else y) But, try: something = x except: something = y Can't? The use cases seems similar. One can use the first form, using more of a imperative programming, or the second line, which is more "functional programming", more expressions oriented. > > > value = (x+y**2 where x,y = (2,4)) > > A "where" *statement* is interesting, but this is not a good example of > it. The above is better written in the normal syntax: > > value = 2 + 4**2 That's the discussion we had on the list called "variable assignement in expressions". What you did here is inlining the variables, technically it's not possible if you're calling a function and using the variable more than once. So we're really comparing it to : x,y = (2,4) value = x+y**2 Or x = 2 y = 4 value = x+y**2 Where the idea is to separate the steps of a computation, introducing temporary variables with a meaningful name is useful (And as mentioned, if a function is called and the variable reused, it's called once, but that's not the main point). In Haskell there is "value = (x = 2 in y = 4 in x+y**2)" or similar. position = initial + speed * time position_inch = distance / 2.54 Vs position_inch = (initial + speed * time) / 2.54 The programmer chooses what's more clear given the context and the audience. Or maybe he wants to emphasize that the code creates a position_inch variable usable in the code after ? Or both, he wants to explain how he computes position_inch using a temporary variable but doesn't want the rest of the code depend o "position" ?). Yes the del is generally useless, more about leaking below. > no need to introduce temporary variables that exist only to obfuscate > the code. > > > > values = [x+y**2 for x in range(5) for y in range(7)] > > values = [x+y**2 for x,y in product (range(5), range(7))] > > y = 5 if condition else 2 > > These already exist, because they are useful. > I see those as a refactoring of imperative programming style as well (values = []; for ...: values.append(...)) > > > y = (lambda x: x+2)(x=5) > > This is not a good example of the use of a lambda. Better: > > y = 5 + 2 > Same thing as in the where syntax. However, some constructs are easier to refactor as def meaningfulname(x): return x+2 y = meaningfulname(5) > Why bother writing a function with such a simple body if you are going > to immediately call it on the spot? Unless the body is more complex, or > you are going to call it elsewhere, or call it repeatedly, the lambda > adds nothing. > Indeed, in complex expressions. Or if I want to separate the steps of a computation. position = initial + speed * time position_inch = distance / 2.54 > Nobody denies that *some* statements are well-suited and useful as > expressions. The question is whether "with" is one of those. > I'm just pointing out those constructs are very similar, it kind of makes sense to compare them. Of course I don't know about real world examples that would simplify a code. But often as I'm a "expression first" guy I write: result = ... # code using result and that doesn't care about the temporary variable it uses. Then I figure how to compute result, without polluting the namespace. Again adding temporary variables before "result = ..." Is totally fine and that's the way to go in imperative programming. > > > with open('hello') as f: > > lines = f.readlines() > > del f # f is leaked ! > > 99% of the time, I would think that "del f" was a waste of time. If that > code is in function, then f will be closed when the "with" block is > exited, and garbage collected when the function returns. > Yes of course, but what if "f" was defined before? We lose its value, even if "f" was created only as a temporary variable to have the variables lines. Maybe it came from: lines = ... # code using lines Yes naming it "f" where one has a 'f' in the same block is confusing, yes it could be named "_". But maybe we are in a script and we have a lots of variables? That kind of questions arise, when we wanted a temporary variable. readlines is a toy example, but maybe the code would be more creative, something like : if condition: filename = "session-{}-{}.txt".format(x, y*10) else: filename = "data_{}_{}.txt".format(w, z) with open('hello') as f: lines = [l.strip('\n') for l in f if len(l) > 0 if not l.stri().startswith('#')] parsed_data = [ ... # list expression mapping lines ] The extra indent seems a bit weird, opening a file is just a secondary effect of wanting to compute "lines = ..." filename = ("session-{}-{}.txt".format(x, y*10) if condition else "data_{}_{}.txt".format(w,z)) lines = ... # Implement that later parsed_data = [ ... # list expression mapping lines ] To: filename = ("session-{}-{}.txt".format(x, y*10) if ... else "data_{}_{}.txt".format(x, y)) lines = ([l.strip('\n') for l in f if len(l) > 0 if not l.stri().startswith('#')] with open (filename) as f) parsed_data = [ ... # list expression mapping lines ] The creator chose to keep exactly the three variables because they have a meaning, f is just an implementation detail. The creator wanted to emphasize that the code is simply: filename = ... lines = ... parsed_data = ... But the "..." being not so useful to have their own function. #Very verbose def compute_filename(x,y,w,z): ... def compute_lines(..., filename): ... def compute_parsed_data(..., lines, filename): ... filename = compute_filename(...) lines = compute_lines(...) parsed_data = compute_parsed_data(...) The functions there should be anonymous, but lambda invoked directly are not very readable. > If you are worried about the memory efficiency of one tiny closed file > object, then Python is the wrong language for you. > Yes I don't talk about the "free" of C or "delete" of C++. > > If that code is in the top-level of a script, who cares about f? You > surely don't delete all your variables when you are done with them: > > name = input("what is your name?") > print("Hello,", name) > del name > play_game() > > > The only time I would explicitly delete f like you do above was if I was > writing a library which specifically and explicitly supported the "from > module import *" syntax, AND there were too many exportable names to > list them all in __all__ by hand. Only in that very rare case would I > care about tidying up the global namespace by using del. > Yes that's a good example of me not wanting to "pollute the namespace, not wanting to create simple functions, not wanting to indent sometimes, but wanting to have tempory variables". If someone reads the module to see its content, they look for all the lines at zero indent begining with 'something = ...' or 'def ...' > > > x,y = 2,4 > > value = x+y**2 > > del x, y # x,y are leaked ! > > If you are writing code like this, you are just obscuring the code. Much > better to just use the values where you need them, not to invent > unnecessary temporary variables that you don't need! > > value = 2 + 4**2 > Temporary variable has always been a choice to the programmer, they explain more the intermediary steps, but focus less on the final result. > > [...] > > If we add one, it's Logical to add the others to be consistent. > > My car has round wheels. Since we use one shape (circle) for wheels, it > must be "logical" to make wheels in all other shapes, to be consistent: > > - triangular wheels > - square wheels > > etc. Consistency just for the sake of consistency is *not* a virtue. > Unless those expression forms justify *themselves* on their own merits, > it is just a waste of time and effort to let them sneak into the > language "for consistency". > I agree, that's why I said earlier "I didn't think so much about the use cases". But trust me, when I write code, I'm really often in "something = ..." Case. And sometimes the ... must depending on a try except, sometimes on a with, sometimes on other variables that are temporary. > > > Of course, one can always write functions like read_text but the ide of > > those construction is like the lambda, we want anonymous. > > We can say: > > text = read('filename') > > text = f.read() with open('filename') as f > > and both are equally unanonymous (both use a named variable), or we can > say: > > process(spam, eggs, read('filename'), foo, bar) > > process(spam, eggs, f.read with open('filename') as f, foo, bar) > > and both are equally anonymous. > > If Python had a built-in function "read", surely you wouldn't refuse to > use it because it was a named function? We don't complain that map() and > filter() are named functions and demand "anonymous" ways to do the same > thing. A read function should be no different. > > The only point of difference is that it is not built-in, you have to > write it yourself. But not every trivial three-line function must be > built-in. > Of course naming stuff is important (that's one of the reasons to build temporary variables). One difficultly of finding use cases, it that it's about changing the paradigm, probably all cases have a really readable implementation in current python / imperative style. But when I see: try: a_variable = int(input("...")) except ValueError: try: a_variable = fetch_db() except DbError: a_variable = default I really think "why can't I put it one one line like I do with if". a_variable = (int(input("...")) except ValueError: fetch_db() except DbError: default) For "with", I'm just wondering "why do I have to indent, it will lose the focus of the reader on the result itself". > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ericfahlgren at gmail.com Fri Aug 3 09:30:25 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Fri, 3 Aug 2018 06:30:25 -0700 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> Message-ID: On Thu, Aug 2, 2018 at 10:06 PM Alexandre Brault wrote: > I would make the opposite argument and claim that since when policy is > None mangle_from_ is initialised to True and not None, None is likely not a > potential value for policy.mangle_from_. Looking at > Lib/email/_policybase.py where the abstract policy class in question is > defined, policies default their mangle_from_ to False, which gives > additional credence to the notion that policy.mangle_from_ is not meant to > be None. > After looking at the code a bit more, I agree, we've uncovered a bug in the stdlib and the null coalescing version actually fixes it. So yes, *strictly speaking* the two chunks of code are not exactly the > same. In practice, they'll act the same way given sensible inputs. > But! We are not here to talk about bugs in the email package, this discussion is about PEP 505, which means to me that the example is a bug in the PEP. In my view, the before and after examples should have identical results, unless there is some very clear and thorough discussion accompanying the example as to why they are different and more importantly, why the "after" version is better or worse. In this light, the example certainly needs a lot of work. -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 3 12:54:26 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Fri, 3 Aug 2018 09:54:26 -0700 Subject: [Python-ideas] With expressions In-Reply-To: References: <20180802115613.GJ22431@ando.pearwood.info> <20180803005305.GM22431@ando.pearwood.info> Message-ID: On Fri, Aug 3, 2018 at 3:49 AM, Robert Vanden Eynde wrote: > > When I say "functional programming", I speak about the paradigm used in > language like Haskell. In language like those, all constructs are > "expression-based". > sure -- but Python is explicitly NOT a functional language in that sense. It does support some functional paradigms, but features are not added to conform to the functional paradigm per-se, but because they are considered useful features. So one needs to defend a new proposal with arguments about how it makes python programming better (by SOME definition of better) on its own merits. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From toddrjen at gmail.com Fri Aug 3 13:46:39 2018 From: toddrjen at gmail.com (Todd) Date: Fri, 3 Aug 2018 13:46:39 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators Message-ID: Coming back to the previous discussion about a new set of overloadable boolean operators [1], I have an idea for overloadable boolean operators that I think might work. The idea would be to define four new operators that take two inputs and return a boolean result based on them. This behavior can be overridden in appropriate dunder methods. These operators would have similar precedence to existing logical operators. The operators would be: bNOT - boolean "not" bAND - boolean "and" bOR - boolean "or" bXOR - boolean "xor" With corresponding dunder methods: __bNOT__ and _rbNOT__ (or __r_bNOT__) __bAND__ and _rbAND__ (or __r_bAND__) __bOR__ and _rbOR__ (or __r_bOR__) __bXOR__ and _rbXOR__ (or __r_bXOR__) The basic idea is that the "b" is short for "boolean", and we change the rest of the operator to upercase to avoid confusions with the existing operators. I think these operators would be preferably to the proposals so far (see [1] again) for a few reasons: 1. They are not easy to mistake with existing operators. They are clearly not similar to the existing bitwise operators like & or |, and although they are clearly related to the "not", "and", and "or" I think they are distinct enough that it should not be easy to confuse the two or accidentally use one in place of the other. 2. They are related to the operations they carry out, which is also an advantage over the existing bitwise operators. 3. The corresponding dunder methods (such as __bAND__ and _rbAND__) are obvious and not easily confused with anything else. 4. The unusual capitalization means they are not likely to be used much in existing Python code. It doesn't fall under any standard capitalization scheme I am aware of. 5. At least for english the capitalization means they are not easy to confuse with existing words. For example Band is a word, but it is not likely to be capitalized as bAND. As to why this is useful, the overall problem is that the current logical operators, like and, or, and not, cannot be overloaded, which means projects like numpy and SQLAlchemy instead have to (ab)use bitwise operators to define their own boolean operations (for example elementwise "and" in numpy arrays). This has a variety of problems, such not having appropriate precedence leading to precedence errors being common, and the simple fact that this precludes them from using the bitwise operators for bitwise operations. There was a proposal to allow overloading boolean operators in Pep-335 [2], but that PEP was rejected for a variety of very good reasons. I think none of those reasons (besides the conversation fizzling out) apply to my proposal. So the alternative proposal that has been floating around is to instead define new operators specifically for this. Although there seemed to be some support for this in principle, the actually operators so far have not met with much enthusiasm. So far the main operators proposed so far seem to be: 1. Double bitwise operators, such as && and ||. These have the disadvantage of looking like they should be a type of bitwise operator. 2. the existing operators, with some non-letter character at the front and back, like ".and.". These have the advantage that they are currently not valid syntax in most cases, but I think are too similar to existing logical operators, to easy to confuse, and it is not immediately obvious in what way they should differ from existing operators. They also mean different things in other languages. So I think my proposal addresses the main issues raised with existing proposals, but has the downside that it requires new keywords. Thoughts? [1] https://mail.python.org/pipermail/python-ideas/2015-November/037207.html [2] https://www.python.org/dev/peps/pep-0335/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From toddrjen at gmail.com Fri Aug 3 13:56:41 2018 From: toddrjen at gmail.com (Todd) Date: Fri, 3 Aug 2018 13:56:41 -0400 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: On Thu, Aug 2, 2018 at 5:35 AM, Ken Hilton wrote: > Hi, I don't know if someone has already suggested this before, but here > goes: > > With expressions allow using the enter/exit semantics of the with > statement inside an expression context. Examples: > > contents = f.read() with open('file') as f #the most obvious one > multiplecontents = [f.read() with open(name) as f for name in names] > #reading multiple files > > I don't know if it's worth making the "as NAME" part of the with mandatory > in an expression - is this a valid use case? > > data = database.selectrows() with threadlock > > Where this would benefit: I think the major use case is `f.read() with > open('file') as f`. Previous documentation has suggested > `open('file').read()` and rely on garbage collection; as the disadvantages > of that became obvious, it transitioned to a method that couldn't be done > in an expression: > > with open('file') as f: > contents = f.read() > > Therefore `f.read() with open('file') as f`, I think, would be much > welcomed as the best way to read a file in an expression. > > For those wondering about the scope semantics of the "as NAME", I think > they would be identical to the scope semantics of the "for" expression - > i.e. these are legal: > > contents = f.read() with open('file') as f > grid = [[i] * 4 for i in range(4)] > > But these are not: > > contents = f.read() with open('file') as f > f.seek(0) > grid = [[i] * 4 for i in range(4)] > grid[i][i] = 4 > > Is this a good idea? Are there some subtleties I've failed to explain? > Please let me know. > > Sharing, > Ken Hilton > > If this is a common enough operation for you, it would be trivially easy to just write a function that does this. There is already a module on pypi that has this function: read_and_close. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Fri Aug 3 14:26:49 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Fri, 3 Aug 2018 19:26:49 +0100 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: Hi Todd Thank you for your contribution! I've got a couple of comments. The experts, I hope, will have more to say. You wrote: > As to why this is useful, the overall problem is that the current logical > operators, like and, or, and not, cannot be overloaded, which means projects > like numpy and SQLAlchemy instead have to (ab)use bitwise operator > There was a proposal to allow overloading boolean operators in Pep-335 [2], > but that PEP was rejected for a variety of very good reasons. The key thing is, I think, the wish for a domain specific language. I find this to be a wholesome wish. But I'd rather create a broad solution, than something that works just for special cases. And if at all possible, implement domain specific languages without extending the syntax and semantics of the language. This would benefit many existing users and projects now, without having to wait for the introduction of a new version of Python, and their project adopting that version. It may help to build on PEP 465 -- A dedicated infix operator for matrix multiplication https://www.python.org/dev/peps/pep-0465/ This addition allows you (from the PEP) to write >>> S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r) You my want to extend the syntax and semantics so that >>> S = (H @beta - r).T @ inv(H @ V @ H.T) @ (H @beta - r) invokes double-under methods, whose name might be something like __at_beta__ I'm impressed by > https://en.wikipedia.org/wiki/Fluent_interface > https://martinfowler.com/bliki/FluentInterface.html and encourage work on tools for creating such in Python. There is the problem of short-circuiting evaluation, as in the 'and' and 'or' operators (and elsewhere in Python). This has to be a syntax and semantics feature. It can't be controlled by the objects. However, as Steve Dower pointed out last month, we can use lamda for this purpose. I think it's easy to define a function OR such that the following > EXP_1 or EXP_2 >> OR(lambda: EXP_1, lambda:EXP_2) do pretty the same thing (except refactoring the expressions into the lambdas). In fact, I think OR has to be >>> def OR(fn_1, fn_2): ... return fn_1() or fn_2() I hope this help you solve the underlying problems, and have a better time with Python. -- Jonathan From toddrjen at gmail.com Fri Aug 3 15:17:42 2018 From: toddrjen at gmail.com (Todd) Date: Fri, 3 Aug 2018 15:17:42 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: On Fri, Aug 3, 2018 at 2:26 PM, Jonathan Fine wrote: > Hi Todd > > Thank you for your contribution! I've got a couple of comments. The > experts, I hope, will have more to say. > > Thanks for your reply, Jonathan. > You wrote: > > > As to why this is useful, the overall problem is that the current logical > > operators, like and, or, and not, cannot be overloaded, which means > projects > > like numpy and SQLAlchemy instead have to (ab)use bitwise operator > > > There was a proposal to allow overloading boolean operators in Pep-335 > [2], > > but that PEP was rejected for a variety of very good reasons. > > The key thing is, I think, the wish for a domain specific language. I > find this to be a wholesome wish. But I'd rather create a broad > solution, than something that works just for special cases. And if at > all possible, implement domain specific languages without extending > the syntax and semantics of the language. > This proposal isn't domain-specific. I think the fact that it would benefit projects as diverse as numpy and SQLAlchemy (as well as others such as sympy) demonstrates that. Boolean operators like the sort I am discussing have been a standard part of programming languages since forever. In fact, they are the basic operations on which modern microprocessors are built. The fact that Python, strictly speaking, doesn't have them is extremely unusual for a programming language. In many cases they aren't necessary in Python since Python's logical operators do the job well enough, but there are a set of highly diverse and highly prominent cases where those logical operators won't work. There are workarounds, but they are less than optimal for the reasons I describe, and the previous discussion I linked to goes into much more detail why these new operators are important. There is the problem of short-circuiting evaluation, as in the 'and' > and 'or' operators (and elsewhere in Python). This has to be a syntax > and semantics feature. It can't be controlled by the objects. > Yes, sorry, I left that out. The consensus from the previous discussion is that this wouldn't be short-circuiting. I can imagine ways to support short-circuiting as well (such as a second set of dunder methods with one set overriding the other), but it isn't really relevant to my proposal. This proposal is assuming the semantics from the previous discussion. All I am trying to address here is how the operators would be spelled. -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicholas.chammas at gmail.com Fri Aug 3 16:02:48 2018 From: nicholas.chammas at gmail.com (Nicholas Chammas) Date: Fri, 3 Aug 2018 16:02:48 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: On Fri, Aug 3, 2018 at 1:47 PM Todd toddrjen at gmail.com wrote: The operators would be: > > bNOT - boolean "not" > bAND - boolean "and" > bOR - boolean "or" > bXOR - boolean "xor" > These look pretty ugly to me. But that could just be a matter of familiarity. For what it?s worth, the Apache Spark project offers a popular DataFrame API for querying tabular data, similar to Pandas. The project overloaded the bitwise operators &, |, and ~ since they could not override the boolean operators and, or, and not. For example: non_python_rhode_islanders = ( person .where(~person['is_python_programmer']) .where(person['state'] == 'RI' & person['age'] > 18) .select('first_name', 'last_name') ) non_python_rhode_islanders.show(20) This did lead to confusion among users since people (myself included) would initially try the boolean operators and wonder why they weren?t working. So the Spark devs added a warning to catch when users were making this mistake. But now it seems quite OK to me to use &, |, and ~ in the context of Spark DataFrames, even though their use doesn?t match their designed meaning. It?s unfortunate, but I think the Spark devs made a practical choice that works well enough for their users. PEP 335 would have addressed this issue by letting developers overload the common boolean operators directly, but from what I gather of Guido?s rejection , the biggest problem was that it would have had an undue performance impact on non-users of boolean operator overloading. (Not sure if I interpreted his email correctly.) ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 3 17:36:47 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 3 Aug 2018 16:36:47 -0500 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: I like this idea in theory, but I'm not sold yet. I think there's a lot of draw to the concept of "expressionizing" statements because many statements require an unnatural ordering in-which the most important code, the logic, comes after some necessary but ultimately noisy (from the readers perspective) preamble. So I expect people to keep asking for expressionized statements and slowly, but, surely, they'll make their way into the language. They just need to be very carefully thought out. Expressionization may break the "one and only on obvious way" guideline, but it can offer concise, readable code in a lot of instances where a statement-based version would be clumsy and noisy, and there's already some precedent for it: function declaration => lambda for-loops => generator expressions and comprehensions if-else => ternary statements With the exception of lambda, expressionized statements usually allow one to put the "meat before the vegitables" so to speak. That is; the highest value part of the expression comes first and all the book-keeping follows. To illustrate this, I'll write a part of an expression and gradually reveal the complete expression, you can see how progressively easier it is to predict the next reveal: def initials(people): return {"".join(name[0] ... # The identifier "name" isn't in scope so it must be assigned in the for clause of a comprehension. def initials(people): return {"".join(name[0] for name in ... # This is a nested comprehension so it's not much of a surprise that the iterator might be related to another # yet-to-be assigned identifier. def initials(people): return {"".join(name[0] for name in person.names ... # Blindly accessing the first element of an empty sequence could cause problems def initials(people): return {"".join(name[0] for name in person.names if name) ... # The inner generator is closed but we still need a binding for "person" def initials(people): return {"".join(name[0] for name in person.names if name) for person in ... # There's not much left to iterate over and decent variable names point to one obvious choice def initials(people): return {"".join(name[0] for name in person.names if name) for person in people} The same could be said for lambdas if they were defined logic-first because they're usually used in a context where the call signature is obvious: hand = sorted(cards, key=(card.suit if card is not wild else max_value <== card))[-5:] Of course, no such thing exists so the '<==' syntax is made up (in-fact a possibly better alternative is, "with"), but it doesn't really matter because a reverse lambda isn't going to happen. You can see, however; that the function's signature is pretty obvious from context, so it's more for the computer's sake than the reader's sake and would be better placed out of the way. I like the current proposal because it follows that design idea, however; I haven't taken the time to think about all the edge cases yet. For instance, what would the following do? initial = person.name[0] with suppress(AttributeError) # Hangover from PEP 505 discussion... Now that I think of it, this seems to inherently make assignment part of the expression: data = file.read() with open(...) as file is supposed to be equivalent to: with open(...) as file: data = file.read() Right? So maybe it only makes sense to use expression assignment (PEP 572): data = (d := file.read() with open(...) as file) To which I say, "Eww..." Also: initial = (i := person.name[0] with suppress(AttributeError)) Is still ambiguous (and still eww). One tactic that other expressionizations have taken is to limit the scope. For instance, the ternary operation only covers expressionization of "if-else" not "just if" or "if-elif-..." or "if-elif-...-else", and generator expressions don't allow the 'else' clause of normal for-loops. So maybe you can obviate some of the edge cases by requiring an as clause or something. I don't know how that would help with the suppress(AttributeError) case thought... On Fri, Aug 3, 2018 at 12:56 PM, Todd wrote: > On Thu, Aug 2, 2018 at 5:35 AM, Ken Hilton wrote: > >> Hi, I don't know if someone has already suggested this before, but here >> goes: >> >> With expressions allow using the enter/exit semantics of the with >> statement inside an expression context. Examples: >> >> contents = f.read() with open('file') as f #the most obvious one >> multiplecontents = [f.read() with open(name) as f for name in names] >> #reading multiple files >> >> I don't know if it's worth making the "as NAME" part of the with >> mandatory in an expression - is this a valid use case? >> >> data = database.selectrows() with threadlock >> >> Where this would benefit: I think the major use case is `f.read() with >> open('file') as f`. Previous documentation has suggested >> `open('file').read()` and rely on garbage collection; as the disadvantages >> of that became obvious, it transitioned to a method that couldn't be done >> in an expression: >> >> with open('file') as f: >> contents = f.read() >> >> Therefore `f.read() with open('file') as f`, I think, would be much >> welcomed as the best way to read a file in an expression. >> >> For those wondering about the scope semantics of the "as NAME", I think >> they would be identical to the scope semantics of the "for" expression - >> i.e. these are legal: >> >> contents = f.read() with open('file') as f >> grid = [[i] * 4 for i in range(4)] >> >> But these are not: >> >> contents = f.read() with open('file') as f >> f.seek(0) >> grid = [[i] * 4 for i in range(4)] >> grid[i][i] = 4 >> >> Is this a good idea? Are there some subtleties I've failed to explain? >> Please let me know. >> >> Sharing, >> Ken Hilton >> >> > If this is a common enough operation for you, it would be trivially easy > to just write a function that does this. There is already a module on pypi > that has this function: read_and_close. > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 3 17:38:59 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Fri, 3 Aug 2018 14:38:59 -0700 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: On Fri, Aug 3, 2018 at 1:02 PM, Nicholas Chammas wrote: > The project overloaded the bitwise operators &, |, and ~ since they > could not > override the boolean operators and, or, and not. > > I actually think that is a good solution to this problem -- the fact is that for most data types bitwise operators are useless -- and for even more not-very-useful. numpy did not do this, because, as it happens, bitwise operators can be useful for numpy arrays of integers (though as I write this, bitwise operations really aren't that common -- maybe requiring a function call for them would be a good way to go -- too late now). Also, in a common use-case, bitwise-and behaves the same as logical_and, e.g. if (arr > x) & (arr2 == y) This "works" because both arrays being bitwise-anded are boolean arrays. So you really don't need to call: np.logical_and and friends very often. so -1 on yet another set of operartors. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From 1benediktwerner at gmail.com Fri Aug 3 18:05:46 2018 From: 1benediktwerner at gmail.com (Benedikt Werner) Date: Sat, 4 Aug 2018 00:05:46 +0200 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: <80f1bb07-157a-ab9a-dcf0-7947f234752f@gmail.com> > There was a proposal to allow overloading boolean operators in Pep-335 > [2], but that PEP was rejected for a variety of very good reasons.? I > think none of those reasons (besides the conversation fizzling out) > apply to my proposal. Maybe I am missing something, but I don't really see how this idea solves the problems that lead to PEP 335 getting rejected. As far as I understand it the main reason for the rejection was that this would decrease performance for all boolean operations which are extremely common where as the need for overriding these operators is rather rare. (See the rejection email here: https://mail.python.org/pipermail/python-dev/2012-March/117510.html) As I see it this proposal only proposes a different syntax and doesn't solve this problem. The only real solution for this would be a new set of operators but I agree with Chris that overriding the bitwise operators is good enough for most cases and a new set of operators really is a bit over the top just for this. I especially dislike using || and && as they are prominently used in other programming languages and this would be extremely confusing for newcomers from those languages. Also if the syntax isn't clear and consice I feel it doesn't really add any value as the main point of operator overloading is to make code easy to read and understand. This really only would be the case if we could overload the boolean operators. Otherweise I think using a function or overloading the bitwise ops is the best solution. From robertve92 at gmail.com Fri Aug 3 18:28:40 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 4 Aug 2018 00:28:40 +0200 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: > > Expressionization may break the "one and only on obvious way" guideline, > but it can offer concise, readable code in a lot of instances where a > statement-based version would be clumsy and noisy, and there's already some > precedent for it: > > function declaration => lambda > for-loops => generator expressions and comprehensions > if-else => ternary statements > Totally agree. That's the problem when being multi paradigm, but we already have that "problem" and that's alright. > With the exception of lambda, expressionized statements usually allow one > to put the "meat before the vegetables" so to speak. That is; the highest > value part of the expression comes first and all the book-keeping follows > As the code I showed, being just that: filename = ... lines = ... parsed_data = ... With implementation details? The highest value is there, the alg is clear., one fetches the filename, one preprocess the lines, then parse the data. > One tactic that other expressionizations have taken is to limit the scope. > For instance, the ternary operation only covers expressionization of > "if-else" not "just if" or "if-elif-..." or "if-elif-...-else", and > generator expressions don't allow the 'else' clause > of normal > for-loops. So maybe you can obviate some of the edge cases by requiring an > as clause or something. I don't know how that would help with the > suppress(AttributeError) case thought... > About if elif elif else, ternary if does have that: y = (x+1 if x < 0 else x-1 if x > 0 else 0) Limiting the scope is interesting, for "with" the only limitation in that the body must have exactly one assignment, like in the ternary if case? a = ([l.strip() for l in f.readlines()] with open ('name') as f) By cutting the edge cases, "with something():" is not possible, only "with ... as" being possible? But the "scope limitation" for try except in expression concept would be not to have "else" or "finally"? The else and finally clauses do not make sense in Expression style assignment anyway. a = (int('stuff') except ValueError: 5) > On Fri, Aug 3, 2018 at 12:56 PM, Todd wrote: > >> On Thu, Aug 2, 2018 at 5:35 AM, Ken Hilton wrote: >> >>> Hi, I don't know if someone has already suggested this before, but here >>> goes: >>> >>> With expressions allow using the enter/exit semantics of the with >>> statement inside an expression context. Examples: >>> >>> contents = f.read() with open('file') as f #the most obvious one >>> multiplecontents = [f.read() with open(name) as f for name in names] >>> #reading multiple files >>> >>> I don't know if it's worth making the "as NAME" part of the with >>> mandatory in an expression - is this a valid use case? >>> >>> data = database.selectrows() with threadlock >>> >>> Where this would benefit: I think the major use case is `f.read() with >>> open('file') as f`. Previous documentation has suggested >>> `open('file').read()` and rely on garbage collection; as the disadvantages >>> of that became obvious, it transitioned to a method that couldn't be done >>> in an expression: >>> >>> with open('file') as f: >>> contents = f.read() >>> >>> Therefore `f.read() with open('file') as f`, I think, would be much >>> welcomed as the best way to read a file in an expression. >>> >>> For those wondering about the scope semantics of the "as NAME", I think >>> they would be identical to the scope semantics of the "for" expression - >>> i.e. these are legal: >>> >>> contents = f.read() with open('file') as f >>> grid = [[i] * 4 for i in range(4)] >>> >>> But these are not: >>> >>> contents = f.read() with open('file') as f >>> f.seek(0) >>> grid = [[i] * 4 for i in range(4)] >>> grid[i][i] = 4 >>> >>> Is this a good idea? Are there some subtleties I've failed to explain? >>> Please let me know. >>> >>> Sharing, >>> Ken Hilton >>> >>> >> If this is a common enough operation for you, it would be trivially easy >> to just write a function that does this. There is already a module on pypi >> that has this function: read_and_close. >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From 1benediktwerner at gmail.com Fri Aug 3 18:40:13 2018 From: 1benediktwerner at gmail.com (Benedikt Werner) Date: Sat, 4 Aug 2018 00:40:13 +0200 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: > For instance, what would the following do? > > initial = person.name [0] with > suppress(AttributeError)? # Hangover from PEP 505 discussion... As the with-expression mimics the with-statement I would say this is similar to: with supress(AttributeError): tmp = person.name[0] initial = tmp # Error on assignment wouldn't get suppressed. Not relevant for this case but still. I don't understand where this is ambigous? > So maybe it only makes sense to use expression assignment (PEP 572): > > data = (d := file.read() with open(...) as file) > > To which I say, "Eww..." I definitely agree that this looks a bit bad but I don't get why you would consider using an expression assignment there. data = file.read with open(...) as file works perfectly fine so why would you want to additonaly assign it to another variable "d"? Overall I like the idea of the with-expression as it allows you to make some common use cases like the open/read example more readable. It's clear at first sight that what is actually done is reading the file. While it's true that it's usually easy to write a simple function to do the job that still isn't as simple to understand and in most cases when reading the code you then have to look at the function to see if anything else is done there. Also what if you then do readlines somewhere? Then you need another function. -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 3 19:57:40 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 3 Aug 2018 18:57:40 -0500 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: [Benedikt Werner] > As the with-expression mimics the with-statement I would say this is > similar to: > with supress(AttributeError): > tmp = person.name[0] > initial = tmp # Error on assignment wouldn't get suppressed. Not relevant > for this case but still. Ah, yes. That makes much more sense now. I would say the error on assignment IS relevant for that case and it's not clear to me how you would present that error to the user without causing a lot of confusion. If it were implemented as: tmp = None with suppress(AttributeError): tmp = person.name[0] initial = tmp Then it would solve many of the common use cases for the None-aware operators proposed in PEP 505, especially if we made it easy to filter out None-specific errors: class NoneError(BaseException): pass class NoneAttributeError(AttributeError, NoneError): pass ... code to make erroneous attribute access on NoneType objects throw NoneAttributeErrors ... ... shouldn't break much code other than maybe some doc-string tests ... initial = person.name[0] with suppress(NoneError) [Robert Vanden Eynde] > With implementation details? The highest value is there, the alg is > clear., one fetches the filename, one preprocess the lines, then parse the > data. Yes. Sorry for using confusing language. I was trying to say that I like your proposed syntax (for both with and except) because it follows the same principal. At the same time, I was trying to demonstrate part of the value of expression-ized statements to everyone else. Since Python is strictly evaluated statement by statement, there is no notion of looking ahead and re-ordering code. You can't use a variable in one statement then define that variable later on (like you do in comprehensions). Expressions, on the other hand; are parsed in a more complex way, so you can do things like put the relevant logic up front and move all the book-keeping to the end. [Robert Vanden Eynde] > About if elif elif else, ternary if does have that: > y = (x+1 if x < 0 else > x-1 if x > 0 else > 0) True, and your except syntax could chain in a similar manner. In-fact it might be possible to make a separate "finally" operator that executes the left side then executes the right side no matter what: y = ((x[0] except InxexError: x.default) except AttributeError: None) finally print("hello!") [Robert Vanden Eynde] > Limiting the scope is interesting, for "with" the only limitation in that > the body must have exactly one assignment, like in the ternary if case? > a = ([l.strip() for l in f.readlines()] with open ('name') as f) > By cutting the edge cases, "with something():" is not possible, only "with > ... as" being possible? I think it's better to forget what I said about limiting the scope of the operator. It was a half-baked thought. As for assignment expressions, they're already on their way thanks to PEP 572. I like the "where" version you proposed because it places the logic first, but unfortunately PEP 572 (4th alternate spelling ) states that they had considered that version and rejected it because "where" is a pretty common variable name. From the PEP: SQLAlchemy and numpy have where methods, as does tkinter.dnd.Icon in the > standard library So adding a new "where" keyword would break backwards compatibility in a major way. On Fri, Aug 3, 2018 at 5:40 PM, Benedikt Werner <1benediktwerner at gmail.com> wrote: > For instance, what would the following do? > > initial = person.name[0] with suppress(AttributeError) # Hangover from > PEP 505 discussion... > > As the with-expression mimics the with-statement I would say this is > similar to: > > with supress(AttributeError): > tmp = person.name[0] > initial = tmp # Error on assignment wouldn't get suppressed. Not relevant for this case but still. > > I don't understand where this is ambigous? > > So maybe it only makes sense to use expression assignment (PEP 572): > > data = (d := file.read() with open(...) as file) > > To which I say, "Eww..." > > I definitely agree that this looks a bit bad but I don't get why you would > consider using an expression assignment there. > > data = file.read with open(...) as file > > works perfectly fine so why would you want to additonaly assign it to > another variable "d"? > > > Overall I like the idea of the with-expression as it allows you to make > some common use cases like the open/read example more readable. It's clear > at first sight that what is actually done is reading the file. While it's > true that it's usually easy to write a simple function to do the job that > still isn't as simple to understand and in most cases when reading the code > you then have to look at the function to see if anything else is done > there. Also what if you then do readlines somewhere? Then you need another > function. > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 3 20:26:04 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 3 Aug 2018 19:26:04 -0500 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: One last thing: Since expressions tend to have pretty limited space, it might be worth it to consider more concise options like maybe instead of: except (Exception[-list])[ as e]): it could be: (Exception[-list])[ as e])! So: y = x[0] IndexError! default instead of y = x[0] except IndexError: default or: y = spam.ham[0] (AttributeError, IndexError) as e! foo(e) instead of y = spam.ham[0] except (AttributeError, IndexError) as e: foo(e) Or something to that effect. (thought I think it might be best to err on the side of 'except' because it's more clear what it does and it only adds 7 characters). On Fri, Aug 3, 2018 at 6:57 PM, Abe Dillon wrote: > [Benedikt Werner] > >> As the with-expression mimics the with-statement I would say this is >> similar to: >> with supress(AttributeError): >> tmp = person.name[0] >> initial = tmp # Error on assignment wouldn't get suppressed. Not relevant >> for this case but still. > > > Ah, yes. That makes much more sense now. I would say the error on > assignment IS relevant for that case and it's not clear to me how you would > present that error to the user without causing a lot of confusion. > > If it were implemented as: > > tmp = None > with suppress(AttributeError): > tmp = person.name[0] > initial = tmp > > Then it would solve many of the common use cases for the None-aware > operators proposed in PEP 505, especially if we made it easy to filter out > None-specific errors: > > class NoneError(BaseException): > pass > > class NoneAttributeError(AttributeError, NoneError): > pass > > ... code to make erroneous attribute access on NoneType objects throw > NoneAttributeErrors ... > ... shouldn't break much code other than maybe some doc-string tests ... > > initial = person.name[0] with suppress(NoneError) > > [Robert Vanden Eynde] > >> With implementation details? The highest value is there, the alg is >> clear., one fetches the filename, one preprocess the lines, then parse the >> data. > > > Yes. Sorry for using confusing language. I was trying to say that I like > your proposed syntax (for both with and except) because it follows the same > principal. At the same time, I was trying to demonstrate part of the value > of expression-ized statements to everyone else. Since Python is strictly > evaluated statement by statement, there is no notion of looking ahead and > re-ordering code. You can't use a variable in one statement then define > that variable later on (like you do in comprehensions). Expressions, on the > other hand; are parsed in a more complex way, so you can do things like put > the relevant logic up front and move all the book-keeping to the end. > > [Robert Vanden Eynde] > >> About if elif elif else, ternary if does have that: >> y = (x+1 if x < 0 else >> x-1 if x > 0 else >> 0) > > > True, and your except syntax could chain in a similar manner. In-fact it > might be possible to make a separate "finally" operator that executes the > left side then executes the right side no matter what: > > y = ((x[0] except InxexError: x.default) except AttributeError: None) > finally print("hello!") > > [Robert Vanden Eynde] > >> Limiting the scope is interesting, for "with" the only limitation in that >> the body must have exactly one assignment, like in the ternary if case? >> a = ([l.strip() for l in f.readlines()] with open ('name') as f) >> By cutting the edge cases, "with something():" is not possible, only >> "with ... as" being possible? > > > I think it's better to forget what I said about limiting the scope of the > operator. It was a half-baked thought. > > As for assignment expressions, they're already on their way thanks to PEP > 572. I like the "where" version you proposed because it places the logic > first, but unfortunately PEP 572 (4th alternate spelling > ) states > that they had considered that version and rejected it because "where" is a > pretty common variable name. From the PEP: > > SQLAlchemy and numpy have where methods, as does tkinter.dnd.Icon in the >> standard library > > > So adding a new "where" keyword would break backwards compatibility in a > major way. > > On Fri, Aug 3, 2018 at 5:40 PM, Benedikt Werner <1benediktwerner at gmail.com > > wrote: > >> For instance, what would the following do? >> >> initial = person.name[0] with suppress(AttributeError) # Hangover from >> PEP 505 discussion... >> >> As the with-expression mimics the with-statement I would say this is >> similar to: >> >> with supress(AttributeError): >> tmp = person.name[0] >> initial = tmp # Error on assignment wouldn't get suppressed. Not relevant for this case but still. >> >> I don't understand where this is ambigous? >> >> So maybe it only makes sense to use expression assignment (PEP 572): >> >> data = (d := file.read() with open(...) as file) >> >> To which I say, "Eww..." >> >> I definitely agree that this looks a bit bad but I don't get why you >> would consider using an expression assignment there. >> >> data = file.read with open(...) as file >> >> works perfectly fine so why would you want to additonaly assign it to >> another variable "d"? >> >> >> Overall I like the idea of the with-expression as it allows you to make >> some common use cases like the open/read example more readable. It's clear >> at first sight that what is actually done is reading the file. While it's >> true that it's usually easy to write a simple function to do the job that >> still isn't as simple to understand and in most cases when reading the code >> you then have to look at the function to see if anything else is done >> there. Also what if you then do readlines somewhere? Then you need another >> function. >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ericfahlgren at gmail.com Fri Aug 3 20:35:45 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Fri, 3 Aug 2018 17:35:45 -0700 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: On Fri, Aug 3, 2018 at 5:26 PM Abe Dillon wrote: > One last thing: > > Since expressions tend to have pretty limited space, it might be worth it > to consider more concise options like maybe instead of: > > except (Exception[-list])[ as e]): > You're reinventing PEP 463: https://www.python.org/dev/peps/pep-0463/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Fri Aug 3 21:13:11 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 4 Aug 2018 11:13:11 +1000 Subject: [Python-ideas] With expressions In-Reply-To: References: <20180802115613.GJ22431@ando.pearwood.info> <20180803005305.GM22431@ando.pearwood.info> Message-ID: <20180804011311.GN22431@ando.pearwood.info> On Fri, Aug 03, 2018 at 12:49:24PM +0200, Robert Vanden Eynde wrote: > Le ven. 3 ao?t 2018 ? 03:07, Steven D'Aprano a ?crit : > > > On Thu, Aug 02, 2018 at 03:13:25PM +0200, Robert Vanden Eynde wrote: > > > > > This brings the discussion of variable assignement in Expression. > > Functional > > > programming community seems to be more interested in python. > > > > I'm not sure what you mean there. Your English grammar is just slightly > > off, enough to make your meaning unclear, sorry. > > > > When I say "functional programming", I speak about the paradigm used in > language like Haskell. I know what functional programming is. What I don't understand is what you mean when you say that the F.P. community "seems to be more interested in python". Surely they are more interested in functional languages than a multi-paradigm language like Python which does not privilege functional idioms over imperative idioms. [...] > > try...except exceptions have been proposed before and rejected. > > I'm wondering why, that must have been the same reasons of not accepting > "with". Read the PEP. Or the (long!) discussions on Python-Ideas and Python-Dev. https://www.python.org/dev/peps/pep-0463/ > > > value = (x+y**2 where x,y = (2,4)) > > > > A "where" *statement* is interesting, but this is not a good example of > > it. The above is better written in the normal syntax: > > > > value = 2 + 4**2 > > > That's the discussion we had on the list called "variable assignement in > expressions". What you did here is inlining the variables, technically it's > not possible if you're calling a function and using the variable more than > once. Which is why I said it was not a good example. If you're going to propose syntax, you ought to give good examples, not bad examples. In any case, this is not a proposal for a "where" expression. You aren't going to convince people to add a "with" expression by showing them expression forms of "if", "for" or hypothetical "where". Each feature must justify itself, not sneak in behind another feature. [...] > > > with open('hello') as f: > > > lines = f.readlines() > > > del f # f is leaked ! > > > > 99% of the time, I would think that "del f" was a waste of time. If that > > code is in function, then f will be closed when the "with" block is > > exited, and garbage collected when the function returns. > > Yes of course, but what if "f" was defined before? We lose its value, even > if "f" was created only as a temporary variable to have the variables lines. [...] > But maybe we are in a script and we have a lots of > variables? That kind of questions arise, when we wanted a temporary > variable. Then don't use f. Use F, fi, fp, fileobj, f_, f1, ?, ??, or myfileobject. Surely you haven't used them all. There is no shortage of useful identifier names. Or factor your code into named functions with isolated namespaces, so the f in one function doesn't clobber the f in another function. Structured programming won the debate against unstructured programming a long time ago. https://en.wikipedia.org/wiki/Structured_programming#History [...] > One difficultly of finding use cases, it that it's about changing the > paradigm, probably all cases have a really readable implementation in > current python / imperative style. But when I see: > > try: > a_variable = int(input("...")) > except ValueError: > try: > a_variable = fetch_db() > except DbError: > a_variable = default > > I really think "why can't I put it one one line like I do with if". > > a_variable = (int(input("...")) except ValueError: > fetch_db() except DbError: > default) Whereas when I see somebody using a double if...else expression in a single line, I wish they would spread it out over multiple lines so it is readable and understandable, instead of trying to squeeze the maximum amount of code per line they can. > For "with", I'm just wondering "why do I have to indent, it will lose the > focus of the reader on the result itself". If this is a problem, then you can easily focus the reader on the result by factoring the code into a named function. text = read('filename') requires no indentation, no complicated new syntax, and it is easily extensible to more complex examples: text = (prefix + (read('filename') or 'default') + moretext).upper() This argument isn't about whether it might occasionally be useful to use a with expression, but whether it is useful *enough* to justify adding new syntax to the language. -- Steve From python at mrabarnett.plus.com Fri Aug 3 21:17:44 2018 From: python at mrabarnett.plus.com (MRAB) Date: Sat, 4 Aug 2018 02:17:44 +0100 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <80f1bb07-157a-ab9a-dcf0-7947f234752f@gmail.com> References: <80f1bb07-157a-ab9a-dcf0-7947f234752f@gmail.com> Message-ID: <24724c34-c20c-10ac-09af-3733262f5732@mrabarnett.plus.com> On 2018-08-03 23:05, Benedikt Werner wrote: >> There was a proposal to allow overloading boolean operators in Pep-335 >> [2], but that PEP was rejected for a variety of very good reasons.? I >> think none of those reasons (besides the conversation fizzling out) >> apply to my proposal. > Maybe I am missing something, but I don't really see how this idea > solves the problems that lead to PEP 335 getting rejected. As far as I > understand it the main reason for the rejection was that this would > decrease performance for all boolean operations which are extremely > common where as the need for overriding these operators is rather rare. > (See the rejection email here: > https://mail.python.org/pipermail/python-dev/2012-March/117510.html) > > As I see it this proposal only proposes a different syntax and doesn't > solve this problem. > [snip] I've been re-reading PEP 335 and I think that the __and1__ method isn't needed. The __bool__ method is called anyway, and currently must return either False or True, but what if it could return the special value NeedOtherOperand mentioned in the PEP? The disadvantage would be that if the first operand is a bool, the operator could still short-circuit, and I'm not sure how much of an issue that would be. From steve at pearwood.info Fri Aug 3 21:18:10 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 4 Aug 2018 11:18:10 +1000 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> Message-ID: <20180804011810.GO22431@ando.pearwood.info> On Fri, Aug 03, 2018 at 06:30:25AM -0700, Eric Fahlgren wrote: > After looking at the code a bit more, I agree, we've uncovered a bug in the > stdlib and the null coalescing version actually fixes it. [...] > But! We are not here to talk about bugs in the email package, this > discussion is about PEP 505, which means to me that the example is a bug in > the PEP. On the contrary! It strongly suggests to me that None-aware operators, or at least this one, makes it *easier* to write correct code than incorrect code. If your analysis that the email package is buggy is correct, this is a strong example in favour of the none-aware operator. > In my view, the before and after examples should have identical > results, unless there is some very clear and thorough discussion > accompanying the example as to why they are different and more importantly, > why the "after" version is better or worse. In this light, the example > certainly needs a lot of work. It needs some work. Something like "Here's an example in the standard library. On converting it to none-aware version, we realised the std lib version is buggy, because ...". A couple of sentences. -- Steve From steve at pearwood.info Fri Aug 3 21:37:23 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 4 Aug 2018 11:37:23 +1000 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <20180804013723.GP22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 12:28:40AM +0200, Robert Vanden Eynde wrote: > As the code I showed, being just that: > > filename = ... > lines = ... > parsed_data = ... > > With implementation details? The highest value is there, the alg is clear., > one fetches the filename, one preprocess the lines, then parse the data. As programmers, surely we have to care about implementation details of the code we are maintaining or writing. If we don't care about implementation, who does? Of course there is a tension between having to deal with implementation details too earlier, or hiding them too deeply. We have to balance too little refactoring from too much refactoring, and people can legitimately disagree as to when a function, method or class carries its own weight. The same applies to syntactic features. That's why *concrete use-cases* are important, not pretend, made-up toy examples. The Python community as a whole is not very receptive to arguments from functional programming purity. I know Python veterans who still don't like list comprehensions (although they're a minority). As a whole, the community does not believe that using multiple statements is always a problem to be fixed. The question is not whether it is *possible* to have a with expression, or whether we might find some toy examples that kinda look good, but how much it improves *real code*. And arguments that we should have a "with" expression because we already have "if" expressions and comprehensions will just fall flat. Arguments by consistency ("we have A, so we ought to have E too, because they're both vowels") are not very productive. -- Steve From ericfahlgren at gmail.com Fri Aug 3 23:16:20 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Fri, 3 Aug 2018 20:16:20 -0700 Subject: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR In-Reply-To: <20180804011810.GO22431@ando.pearwood.info> References: <613c464f-61b1-3018-54e0-9775428de09a@gmail.com> <7dee6a26-6586-8d4e-7630-1181e51fa8a6@mrabarnett.plus.com> <4e7b1af9-876a-4cf1-6500-bc13149adb18@mrabarnett.plus.com> <6c24c5b6-e788-bd6f-d206-d352483cee7c@mapgears.com> <20180804011810.GO22431@ando.pearwood.info> Message-ID: On Fri, Aug 3, 2018 at 6:19 PM Steven D'Aprano wrote: > It needs some work. Something like "Here's an example in the standard > library. On converting it to none-aware version, we realised the std lib > version is buggy, because ...". A couple of sentences. > Yup, that's what I was getting at... -------------- next part -------------- An HTML attachment was scrubbed... URL: From toddrjen at gmail.com Sat Aug 4 00:00:05 2018 From: toddrjen at gmail.com (Todd) Date: Sat, 4 Aug 2018 00:00:05 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <80f1bb07-157a-ab9a-dcf0-7947f234752f@gmail.com> References: <80f1bb07-157a-ab9a-dcf0-7947f234752f@gmail.com> Message-ID: On Fri, Aug 3, 2018 at 6:05 PM, Benedikt Werner <1benediktwerner at gmail.com> wrote: > There was a proposal to allow overloading boolean operators in Pep-335 >> [2], but that PEP was rejected for a variety of very good reasons. I think >> none of those reasons (besides the conversation fizzling out) apply to my >> proposal. >> > Maybe I am missing something, but I don't really see how this idea solves > the problems that lead to PEP 335 getting rejected. As far as I understand > it the main reason for the rejection was that this would decrease > performance for all boolean operations which are extremely common where as > the need for overriding these operators is rather rare. (See the rejection > email here: https://mail.python.org/pipermail/python-dev/2012-March/ > 117510.html) > > As I see it this proposal only proposes a different syntax and doesn't > solve this problem. > > The only real solution for this would be a new set of operators but I > agree with Chris that overriding the bitwise operators is good enough for > most cases and a new set of operators really is a bit over the top just for > this. I especially dislike using || and && as they are prominently used in > other programming languages and this would be extremely confusing for > newcomers from those languages. Also if the syntax isn't clear and consice > I feel it doesn't really add any value as the main point of operator > overloading is to make code easy to read and understand. This really only > would be the case if we could overload the boolean operators. Otherweise I > think using a function or overloading the bitwise ops is the best solution. > > The proposal is for new operators. The operators would be "bNOT", "bAND", "bOR", and "bXOR". They would be completely independent of the existing "not", "and", and "or" operators, operating purely on boolean values. It would be possible to overload these operators. -------------- next part -------------- An HTML attachment was scrubbed... URL: From toddrjen at gmail.com Sat Aug 4 00:13:33 2018 From: toddrjen at gmail.com (Todd) Date: Sat, 4 Aug 2018 00:13:33 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: On Fri, Aug 3, 2018 at 5:38 PM, Chris Barker wrote: > On Fri, Aug 3, 2018 at 1:02 PM, Nicholas Chammas < > nicholas.chammas at gmail.com> wrote: > >> The project overloaded the bitwise operators &, |, and ~ since they >> could not >> > override the boolean operators and, or, and not. >> >> I actually think that is a good solution to this problem -- the fact is > that for most data types bitwise operators are useless -- and for even more > not-very-useful. > > numpy did not do this, because, as it happens, bitwise operators can be > useful for numpy arrays of integers (though as I write this, bitwise > operations really aren't that common -- maybe requiring a function call for > them would be a good way to go -- too late now). > > Also, in a common use-case, bitwise-and behaves the same as logical_and, > e.g. > > if (arr > x) & (arr2 == y) > > This "works" because both arrays being bitwise-anded are boolean arrays. > > So you really don't need to call: > > np.logical_and and friends very often. > > so -1 on yet another set of operartors. > > -CHB > > There are a few problems with using the bitwise operators. First, and most important in my opinion, is that the precedence is significantly off from that of the logical operators. As your own example shows, any non-trivial example requires a lot of parentheses to keep things working. And if you are switching back and forth between, say, array logical operations and "normal" logical operations it is easy to mess up. Second is that it can be restricted to only working on boolean-like data types. Combining how easy it is to get the precedence wrong with the fact that getting it wrong can silently fail is not a good combination in my opinion. Making sure the operator is actually doing what people want and expect it to do seems like a big benefit to me. Third is that it allows both boolean and bitwise operations to be carried out on the same data types. Numpy is a special case where the two basically are equivalent if you are working with boolean arrays. But that is a special case. -------------- next part -------------- An HTML attachment was scrubbed... URL: From 1benediktwerner at gmail.com Sat Aug 4 01:31:11 2018 From: 1benediktwerner at gmail.com (Benedikt Werner) Date: Sat, 4 Aug 2018 07:31:11 +0200 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <80f1bb07-157a-ab9a-dcf0-7947f234752f@gmail.com> Message-ID: <3e001a29-7017-7f00-062f-b06bcf8f5408@gmail.com> > The proposal is for new operators.? The operators would be "bNOT", > "bAND", "bOR", and "bXOR".? They would be completely independent of > the existing "not", "and", and "or" operators, operating purely on > boolean values.? It would be possible to overload these operators. I see, I misunderstood you there. Then I have to say that these names really don't feel very pythonic to me. I guess they are still the best names out of the ones I have seen so far but I still don't like them very much. I guess having overloadable operators with proper precedences would be quite handy for fluent style APIs but I don't think it's worth justifying a new set of operators. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Sat Aug 4 03:32:22 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 4 Aug 2018 17:32:22 +1000 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <20180804073222.GQ22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 12:40:13AM +0200, Benedikt Werner wrote: > Overall I like the idea of the with-expression as it allows you to make > some common use cases like the open/read example more readable. For some definition of "readable". > It's > clear at first sight that what is actually done is reading the file. Only because the file.read() comes early in the expression. But that applies equally to text = read('filename') > While it's true that it's usually easy to write a simple function to do > the job that still isn't as simple to understand (1) read(filename) Explanation to a beginner: "It reads text from the named file." (2) f.read() with open(filename) as f Explanation to a beginner: "It opens a file -- I'll explain what it means to open a file later -- in a context manager -- that's advanced Python programming, don't worry about context managers for now -- and binds the context manager to the name f, then calls the read method on the object f -- I'll explain object oriented programming later -- which reads text from the named file and closes the file... oh I forgot to mention that the context manager is also a file object." Do you still think that explaining a with expression is simpler than explaining a self-descriptively named function? The beauty of the named function is that it hides a lot of irrelevant detail and focuses *only* on the important feature, which is reading from the file. A with-statement is great for when you care about the implementation details. Somebody has to care about the process of opening a file, reading from it and closing it. But when you *don't* care about those implementation details, a simple interface like a read() function is superior to a with-statement, *or* a with-expression, which shoves those details in your face. > and in most cases when > reading the code you then have to look at the function to see if > anything else is done there. I doubt that many people really spend a lot of time digging into functions to see whether they do more than what they say. Unless and until I ran into unexpected problems, I'd be no more inclined to look into a function called "read" than I would be to do the same to len or math.sin. I'm sure it does what it says it does. In Python 2, one of the problems with the input() function was that it was used by people who didn't read the docs and where taken completely by surprise by the fact that it called eval on the input. That shows that people don't make a habit of digging into functions "just in case". > Also what if you then do readlines > somewhere? Then you need another function. Indeed. But not everything has to be a built-in feature, and refactoring common code into a named function will often be a good idea *even if* ``with`` is an exception: def read(filename, size=-1, **kwargs): return f.read(size) with open(filename, **kwargs) as f -- Steve From steve at pearwood.info Sat Aug 4 03:43:33 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 4 Aug 2018 17:43:33 +1000 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <20180804074333.GR22431@ando.pearwood.info> On Fri, Aug 03, 2018 at 06:57:40PM -0500, Abe Dillon wrote: > tmp = None > with suppress(AttributeError): > tmp = person.name[0] > initial = tmp > > Then it would solve many of the common use cases for the None-aware > operators proposed in PEP 505 No it would not. The None-aware operators are not about suppressing AttributeError, please stop suggesting that it is. If you want to propose a general exception suppressing mechanism (aside from the existing try...except statement) then propose it as an independent PEP. Even if we had a general purpose exception-suppressing expression, it wouldn't meet the functional requirements for PEP 505. It would do too much, like offering somebody a bulldozer when all we want is a dustpan and broom. > especially if we made it easy to filter out > None-specific errors: > > class NoneError(BaseException): > pass > > class NoneAttributeError(AttributeError, NoneError): > pass They're not None specific. Any object can raise them. -- Steve From J.Demeyer at UGent.be Sat Aug 4 03:48:45 2018 From: J.Demeyer at UGent.be (Jeroen Demeyer) Date: Sat, 4 Aug 2018 09:48:45 +0200 Subject: [Python-ideas] With expressions In-Reply-To: References: Message-ID: <5B655A5D.6000003@UGent.be> On 2018-08-04 09:43, Steven D'Aprano wrote: > If you want to > propose a general exception suppressing mechanism (aside from the > existing try...except statement) then propose it as an independent PEP. This was already tried in PEP 463 (which IMHO is a pity that it wasn't accepted because it seems really useful). From robertve92 at gmail.com Sat Aug 4 06:08:22 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 4 Aug 2018 12:08:22 +0200 Subject: [Python-ideas] With expressions In-Reply-To: <20180804011311.GN22431@ando.pearwood.info> References: <20180802115613.GJ22431@ando.pearwood.info> <20180803005305.GM22431@ando.pearwood.info> <20180804011311.GN22431@ando.pearwood.info> Message-ID: > I know what functional programming is. What I don't understand is what > you mean when you say that the F.P. community "seems to be more > interested in python". Surely they are more interested in functional > languages than a multi-paradigm language like Python which does not > privilege functional idioms over imperative idioms. > > Just a personal feeling, it's not really thought out. > > try...except exceptions have been proposed before and rejected. > > > > I'm wondering why, that must have been the same reasons of not accepting > > "with". > > Read the PEP. Or the (long!) discussions on Python-Ideas and Python-Dev. > > https://www.python.org/dev/peps/pep-0463/ > > > I'm reading it. The prelude at the beginning then says there are no convincing use case if I get it right? > > Which is why I said it was not a good example. If you're going to > propose syntax, you ought to give good examples, not bad examples. > When showing toy examples I thought some people would think "indeed, that happens to me often". > In any case, this is not a proposal for a "where" expression. You aren't > going to convince people to add a "with" expression by showing them > expression forms of "if", "for" or hypothetical "where". Each feature > must justify itself, not sneak in behind another feature. > Indeed, I'm talking about it because I think it all relates to "expressionalize simple statements", that's also why I speak about FP, because that's an "expression-first" paradigm. > > Or factor your code into named functions with isolated namespaces, so > the f in one function doesn't clobber the f in another function. > Structured programming won the debate against unstructured programming a > long time ago. > > https://en.wikipedia.org/wiki/Structured_programming#History > > > [...] Of course I would do that, i completely agree that refactoring is useful, but as shown in the end of my post: filename = compute_filename(...) lines = compute_lines(...) parsed_data = compute_parsed_data(...) The functions body being a bit too small to be refactored and doesn't really have another meaning of "code to compute filename", I feel like the "filename =" already catches the idea, I feel like repeating myself (DRY). And the function body in those cases is not very reusable so it doesn't make sense to give it a meaningful name. I would do a named function otherwise indeed. > > One difficultly of finding use cases, it that it's about changing the > > paradigm, probably all cases have a really readable implementation in > > current python / imperative style. But when I see: > > > > try: > > a_variable = int(input("...")) > > except ValueError: > > try: > > a_variable = fetch_db() > > except DbError: > > a_variable = default > > > > I really think "why can't I put it one one line like I do with if". > > > > a_variable = (int(input("...")) except ValueError: > > fetch_db() except DbError: > > default) > > Whereas when I see somebody using a double if...else expression in a > single line, I wish they would spread it out over multiple lines so it > is readable and understandable, instead of trying to squeeze the maximum > amount of code per line they can. > Multiline is clearly better yes. When I say 'one line' I'm just saying "using the expression-statement but probably gonna span it on multiple lines because the Expressions are not short. > > > For "with", I'm just wondering "why do I have to indent, it will lose the > > focus of the reader on the result itself". > > If this is a problem, then you can easily focus the reader on the > result by factoring the code into a named function. > > text = read('filename') > > requires no indentation, no complicated new syntax, and it is easily > extensible to more complex examples: > > text = (prefix + (read('filename') or 'default') + moretext).upper() > > This argument isn't about whether it might occasionally be useful to use > a with expression, but whether it is useful *enough* to justify adding > new syntax to the language. > For 'with', as you all say, it really boils down to finding use cases other than "file manipulation". It's true I can't think of any (expect the fact it does create a function that may not have a meaningful name). > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robertve92 at gmail.com Sat Aug 4 06:22:53 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 4 Aug 2018 12:22:53 +0200 Subject: [Python-ideas] With expressions In-Reply-To: <20180804073222.GQ22431@ando.pearwood.info> References: <20180804073222.GQ22431@ando.pearwood.info> Message-ID: > > > > > A with-statement is great for when you care about the > implementation details. Somebody has to care about the process of > opening a file, reading from it and closing it. But when you *don't* > care about those implementation details, a simple interface like a > read() function is superior to a with-statement, *or* a with-expression, > which shoves those details in your face. > Totally agree. In the case where you care about the implementation details. You can explain to a beginner: something = (f.read() with open('...') as f) Is another way to write: with open('filename') as f: something = f.read() Exactly like the ternary if. And I agree that because with is often relevant for "implementation details" or beginning use as a "enter.. exit' statement (like a cpp destructor), it matches more imperative programming. with stack.push_matrix(Scale(4)): triangle = draw_triangle_using(stack) Is used for it's "enter/close" functionality, but can still be used like: triangle = (draw_triangle_using(stack) with stack.push_matrix(Scale(4)) as NotUsed) But the "as close" is useless here. > > > and in most cases when > > reading the code you then have to look at the function to see if > > anything else is done there. > > I doubt that many people really spend a lot of time digging into > functions to see whether they do more than what they say. Unless and > until I ran into unexpected problems, I'd be no more inclined to look > into a function called "read" than I would be to do the same to len or > math.sin. I'm sure it does what it says it does. > Fair point, the "def" statements generally are passed when read so they don't really count as overhead. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Sat Aug 4 09:13:34 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 4 Aug 2018 23:13:34 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: <20180804131333.GU22431@ando.pearwood.info> On Fri, Aug 03, 2018 at 03:17:42PM -0400, Todd wrote: > Boolean operators like the sort I am discussing have been a standard part > of programming languages since forever. In fact, they are the basic > operations on which modern microprocessors are built. > > The fact that Python, strictly speaking, doesn't have them is extremely > unusual for a programming language. I'm rather surprised at this claim. Can you give a survey of such overridable boolean operators which are available on modern microprocessors? What programming languages already have them? When you say "forever", are you going back to Fortran in the 1950s? > In many cases they aren't necessary in > Python since Python's logical operators do the job well enough, but there > are a set of highly diverse and highly prominent cases where those logical > operators won't work. Can you list some of these diverse and highly prominent use-cases? I can think of two: - elementwise boolean operators, such as in numpy; - SQL-like DSL languages; plus a third rather specialised and obscure use-case: - implementing non-binary logical operators, for (e.g. ternary or fuzzy logic). > There are workarounds, but they are less than > optimal for the reasons I describe, and the previous discussion I linked to > goes into much more detail why these new operators are important. There are certainly advantages to using binary operators over named functions, and a shortage of good, ASCII punctuation suitable for new operators. I don't think much of your names bOR etc. I think that before adding more ad hoc binary operators, we ought to consider the possibility of custom operators. For example, Julia uses |> op <| https://github.com/JuliaLang/julia/issues/16985 (which I think is ugly and excessively verbose); Swift allows code to define custom prefix, infix or postfix operators: https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID380 https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418 Haskell is another language which supports custom infix operators: https://csinaction.com/2015/03/31/custom-infix-operators-in-haskell/ Here's a spur-of-the-moment suggestion: allow ~op for named infix operators. So: a ~foo b is *roughly* equivalent to: if hasattr(a, '__foo__'): return a.__foo__(b) elif hasattr(b, '__foo__'): return b.__rfoo__(a) else: raise TypeError Although possibly we might choose another pseudo-namespace, to avoid custom operators clashing with dunders. Trunders perhaps? (Triple underscores?) Under this scheme, your operators would become: ~or ~and ~xor and call trunders ___or___ etc. -- Steve From dan at tombstonezero.net Sat Aug 4 10:04:01 2018 From: dan at tombstonezero.net (Dan Sommers) Date: Sat, 4 Aug 2018 14:04:01 +0000 (UTC) Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: On Sat, 04 Aug 2018 23:13:34 +1000, Steven D'Aprano wrote: > There are certainly advantages to using binary operators over named > functions, and a shortage of good, ASCII punctuation suitable for new > operators. Hold that thoght. Then again, why is it 2018 (or 5778?) and we're still stuck with ASCII? Doesn't Unicode define a metric boatload of mathematical symbols? If Pythong allows Unicode names,? why not Unicode operators? ? No, I'm not going to call them variables. :-) > I don't think much of your names bOR etc. > > I think that before adding more ad hoc binary operators, we ought to > consider the possibility of custom operators [...] > > a ~foo b Great. Yet another way to spell a.foo(b). Or foo(a, b). :-/ > Although possibly we might choose another pseudo-namespace, to avoid > custom operators clashing with dunders. Trunders perhaps? (Triple > underscores?) > > Under this scheme, your operators would become: > > ~or > ~and > ~xor > > and call trunders ___or___ etc. And now mental gymnastics to jump from ~foo to ___foo___ or ___rfoo___. If it's too hard to tell = from == (see endless threads on this mailing list for proof), then it's also too hard to tell __xor__ from ___xor___. If I want to say a ~foo b then why can't I also say class A: def ~foo(self, b): pass # do something more useful here From 1benediktwerner at gmail.com Sat Aug 4 10:56:56 2018 From: 1benediktwerner at gmail.com (Benedikt Werner) Date: Sat, 4 Aug 2018 16:56:56 +0200 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <20180804131333.GU22431@ando.pearwood.info> References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: > I think that before adding more ad hoc binary operators, we ought to > consider the possibility of custom operators. That actually sounds like the most sensible solution so far, altough the scope of such a change is also much larger. But custom operators really would be a cool addition to Python. > Although possibly we might choose another pseudo-namespace, to avoid > custom operators clashing with dunders. Trunders perhaps? (Triple > underscores?) > > Under this scheme, your operators would become: > > ~or > ~and > ~xor > > and call trunders ___or___ etc. As Dan already pointed out it's very hard to see the difference between two and three underscores so I don't think "trunders" would be a good idea. I think it would make sense to instead use a new keyword to define operators. Maybe something like "defop". I don't think that's a very common variable or function name. Example syntax could be: class MyInt(int): defop combine(self, other): return self, other # and now we can use it x combine y # which is equivalent to x.combine(y) Of course it would actually have to check if and where the operator is defined like currently done for overloading. Also it might be worth considering support for pre/postfix operators, maybe either with a differnt keyword (something like defpre/defprefix, don't really like those but something similar maybe) or a symbol as indicator (e.g. "defop combine(..)" for postifx). From zauddelig at gmail.com Sat Aug 4 12:03:50 2018 From: zauddelig at gmail.com (Fabrizio Messina) Date: Sat, 4 Aug 2018 09:03:50 -0700 (PDT) Subject: [Python-ideas] Syntactic sugar to declare partial functions Message-ID: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Hello, I would like to propose a new method to create a partial function. At the moment we have to load the *partial* function from the *functool* library, and apply it to an existing function, e.g. from functools import partial def add(x: int, y: int) -> int: return x + y add_2 = partial(add, 2) While partial expose the mechanism excellently its instantiation method is, at times, not very friendly, I would like to propose a syntactic sugar to create partial functions, in the case you create a partial function using *curly braces*: def add(x: int, y: int) -> int: return x + y add_2 = add{2} At the moment this causes SyntaxError so the change is retro-compatible. In the case of key word arguments we could have: sort_by_x = sort{key=lambda element: element.x} That could be good as it would be an easy way to pre-load functions without having to eagerly compute it, but without needing to pass the entire function parameters to to other scopes. # prepare the function get_sorted_users: Callable[[], Iterator[User]] = sort{users, key=lambda user : user.creation_date} # continue with job at hand ... # some where else, maybe another process sorted_users = list(get_sorted_users()) Even create a factory method on the fly: @dataclass class Product: name: str category: Category price: Decimal smartphone_factory = Product{category=smartphone_category} Now all this can already be done with partial, but adding this syntactic sugar would reduce the perception of `partial` as an advanced feature, alleviating the use of closures created only for the sake of avoiding an explicit partial. In my opinion this syntactic sugar has a lot of potential adoption seen the general interest in functional programming. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Sat Aug 4 12:37:52 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sun, 5 Aug 2018 02:37:52 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: <20180804163752.GV22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 04:56:56PM +0200, Benedikt Werner wrote: > >I think that before adding more ad hoc binary operators, we ought to > >consider the possibility of custom operators. > > That actually sounds like the most sensible solution so far Thanks :-) Unfortunately there's a flaw, in that the ~ symbol already means unary bitwise-not, so we can't use ~op for operators. Throwing some ideas out to be shot down: spam !op eggs spam :op eggs spam @op eggs spam ..op eggs > >Although possibly we might choose another pseudo-namespace, to avoid > >custom operators clashing with dunders. Trunders perhaps? (Triple > >underscores?) > > > >Under this scheme, your operators would become: > > > > ~or > > ~and > > ~xor > > > >and call trunders ___or___ etc. > As Dan already pointed out it's very hard to see the difference between > two and three underscores so I don't think "trunders" would be a good idea. Three underscores is 50% longer than two. I don't believe that it is harder to tell the difference between ___ and __ at a glance than it is to tell the difference between __ and _ at a glance, even for those with a mild visual impairment like mine. Unless you're reading and writing code using a proportional font, in which case I have no sympathy. Whatever naming convention we use, it should be a subset of dunders, different from all existing dunders, short enough to avoid being annoying to use, and make up an obviously distinct group. How about this? __o_name__ __o_rname__ > I think it would make sense to instead use a new keyword to define > operators. Maybe something like "defop". I don't think that's a very > common variable or function name. New keywords should be a last resort, only for functionality which requires syntactic support. This doesn't. What will this "defop" keyword do that def doesn't already do? Probably nothing, the methods will be ordinary methods just like __add__ and other operator dunders. And even if we needed some sort of extra functionality, say, registering the operators, we could use a decorator for that. > Example syntax could be: > > class MyInt(int): > defop combine(self, other): > return self, other > > # and now we can use it > x combine y > > # which is equivalent to > x.combine(y) That would mean giving up the ability to detect a whole lot of syntax errors at compile time. Remember that under Python's execution model, the compiler cannot tell in advance which custom operators have been defined and which have not. It has to resolve them at runtime. So the only way we could allow `x combine y` as valid syntax would be if we also allowed errors like `print len alist` as valid syntax. This is why I think that named operators should require a special prefix. Without the prefix, x combine y is a syntax error. But with the prefix, say, x :combine y, the compiler can use a custom byte-code to resolve the operator at runtime. (Of course it will still be a runtime error if neither x nor y define the combine operator.) All this supposes that there is sufficient benefit to allowing custom infix operators, including overridable or/and/xor, which is not yet shown. -- Steve From robertve92 at gmail.com Sat Aug 4 12:41:27 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 4 Aug 2018 18:41:27 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: The funcoperators lib on pypi does exactly that: from funcoperators import partially @partially def add(x: int, y: int) -> int: return x + y add_2 = add[2] @partiallymulti def stuff(x,y,z): return x - y + 2*z sort = partially(sorted) sort_by_x = sort.key(key=lambda element: element.x) The ".key" means "give a keyword argument". The ".val" or [] gives a positional argument. The ".part" accept positional and keyword arguments. Le sam. 4 ao?t 2018 ? 18:03, Fabrizio Messina a ?crit : > > Hello, I would like to propose a new method to create a partial function. > > At the moment we have to load the *partial* function from the *functool* > library, and apply it to an existing function, e.g. > > from functools import partial > > > def add(x: int, y: int) -> int: > return x + y > > > add_2 = partial(add, 2) > > > > While partial expose the mechanism excellently its instantiation method > is, at times, not very friendly, I would like to propose a syntactic sugar > to create partial functions, in the case you create a partial function > using *curly braces*: > > > def add(x: int, y: int) -> int: > return x + y > > add_2 = add{2} > > > At the moment this causes SyntaxError so the change is retro-compatible. > > In the case of key word arguments we could have: > > sort_by_x = sort{key=lambda element: element.x} > > > That could be good as it would be an easy way to pre-load functions > without having to eagerly compute it, but without needing to pass the > entire function parameters to to other scopes. > > > # prepare the function > get_sorted_users: Callable[[], Iterator[User]] = sort{users, key=lambda > user: user.creation_date} > > # continue with job at hand > ... > > # some where else, maybe another process > sorted_users = list(get_sorted_users()) > > > > Even create a factory method on the fly: > @dataclass > class Product: > name: str > category: Category > price: Decimal > > > smartphone_factory = Product{category=smartphone_category} > > > > Now all this can already be done with partial, but adding this syntactic > sugar would reduce the perception of `partial` as an advanced feature, > alleviating the use of closures created only for the sake of avoiding an > explicit partial. > > In my opinion this syntactic sugar has a lot of potential adoption seen > the general interest in functional programming. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robertve92 at gmail.com Sat Aug 4 12:44:18 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 4 Aug 2018 18:44:18 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: > @partiallymulti > def stuff(x,y,z): > return x - y + 2*z > f = stuff[1,2] f(4) -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Sat Aug 4 13:07:55 2018 From: rosuav at gmail.com (Chris Angelico) Date: Sun, 5 Aug 2018 03:07:55 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <20180804163752.GV22431@ando.pearwood.info> References: <20180804131333.GU22431@ando.pearwood.info> <20180804163752.GV22431@ando.pearwood.info> Message-ID: On Sun, Aug 5, 2018 at 2:37 AM, Steven D'Aprano wrote: > All this supposes that there is sufficient benefit to allowing custom > infix operators, including overridable or/and/xor, which is not yet > shown. Part of the justification for that is that the bitwise operators have different precedence to the logical operators. But custom operators would have to all be grouped at the same precedence level (or maybe a small handful of precedences, chosen by syntax), so that won't truly solve that problem. A valid justification would be: A single object needs to be able to perform both bitwise and logical operations, AND needs to customize the logical ops. I haven't seen any but they could exist. ChrisA From steve at pearwood.info Sat Aug 4 13:23:54 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sun, 5 Aug 2018 03:23:54 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: <20180804172353.GW22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 02:04:01PM +0000, Dan Sommers wrote: > On Sat, 04 Aug 2018 23:13:34 +1000, Steven D'Aprano wrote: > > > There are certainly advantages to using binary operators over named > > functions, and a shortage of good, ASCII punctuation suitable for new > > operators. > > Hold that thoght. > > Then again, why is it 2018 (or 5778?) and we're still stuck with ASCII? > Doesn't Unicode define a metric boatload of mathematical symbols? If > Pythong allows Unicode names,? why not Unicode operators? Some social problems: - allowing non-ASCII identifiers was controversial, and is still banned for the std lib; - according to critics of PEP 505, even ASCII operators like ?. are virtually unreadable or unspeakably ugly and "Perlish". If you think the uproar over PEP 572 was vicious, imagine what would happen if we introduced new operators like ? ? ? ? ? etc instead. I'm not touching that hornet's nest with a twenty foot pole. And some technical problems: - keyboard support for entering the bulk of Unicode characters is non-existent or poor; - without keyboard support, editor support for entering Unicode characters is as best clunky, requiring the memorization of obscure names, hex codes, or a GUI palette; - and font support for the more exotic code points, including most mathematical operators, is generally rubbish. It may be that these technical problems will *never* be solved. But let other languages, like Julia, blaze this trail. [...] > > I think that before adding more ad hoc binary operators, we ought to > > consider the possibility of custom operators [...] > > > > a ~foo b > > Great. Yet another way to spell a.foo(b). Or foo(a, b). :-/ Indeed. Technically, we don't need *any* operators at all, possibly aside from those that do argument short-circuiting. But for many purposes, we much prefer infix notation to prefix function notation. Which would you rather read and write? or(x, 1) x or 1 [...] > And now mental gymnastics to jump from ~foo to ___foo___ or ___rfoo___. Just as we do "mental gymnastics" to jump from existing operators like + to __add__ or __radd__. If you don't like operator overloading *at all*, that ship has already sailed. > If it's too hard to tell = from == > (see endless threads on this mailing list for proof) > then it's also too hard to tell __xor__ from ___xor___. *shrug* I don't think it is, but I'm open to alternative suggestions. > If I want to say > > a ~foo b > > then why can't I also say > > class A: > def ~foo(self, b): > pass # do something more useful here Infix operators delegate to a pair of methods. What would you call the second one? ~rfoo will clash with operator rfoo. We already have a convention that operators delegate to dunder methods, and I see no reason to make changes to that convention. It's a *good* convention. The smaller the number of changes needed for a proposal, the better its chances of being accepted. My suggestion requires: - one new piece of syntax, ~op or equivalent, as a binary operator; - (possibly) one slight extension to an existing naming convention; - (possibly) one new byte-code; - no new keywords, no new syntax for methods, no new built-in types, no changes to the execution model of the language, and no changes to the characters allowed in Python code. If you want to make a counter-proposal that is more extensive, be my guest :-) -- Steve From jfine2358 at gmail.com Sat Aug 4 13:33:40 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sat, 4 Aug 2018 18:33:40 +0100 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: Here's my opinion, in a nutshell. A diet with a small amount of sugar is healthy. But too much sugar is not. https://www.nhs.uk/live-well/eat-well/how-does-sugar-in-our-diet-affect-our-health/ I have a similar attitude to syntactic sugar. Sometimes helpful. https://news.ycombinator.com/item?id=16216994 Sometimes, perhaps not helpful. https://github.com/benthor/dictator https://github.com/czheo/syntax_sugar_python Every programming construct has semantics. Here's a suggestion. If you're proposing a syntax change, give a pure Python implementation of the semantics. For example (not tested). The construction >>> EXP_1 or EXP_2 is equivalent to >>> OR(lambda: EXP_1, lambda:EXP_2) where we have >>> def OR(fn_1, fn_2): >>> ... val = fn_1() >>> ... if val: return val >>> ... return fn_2() And if your proposal works with current Python, write and publish a pure Python implementation. And help others use it, listening to their feedback. So do it on github or the like, with an issue tracker. In short, if you have a proposal, publish some working code that implements the proposal. -- Jonathan From steve at pearwood.info Sat Aug 4 13:57:45 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sun, 5 Aug 2018 03:57:45 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: <20180804175745.GX22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 09:03:50AM -0700, Fabrizio Messina wrote: > At the moment we have to load the *partial* function from the *functool* > library, and apply it to an existing function [...] > While partial expose the mechanism excellently its instantiation method is, > at times, not very friendly, I disagree with *both* of those statements. As an implementation of partial function application, partial() has a couple of weaknesses: - no support for applying arguments from the right, except by keyword; - no automatic or easy way to inherit docstrings from the original function; - even if you manually set the partial function object's docstring, help() ignores it. (That's possibly not partial's fault.) On the other hand, I think that partial(func, arg, kw=value) is plenty friendly. > I would like to propose a syntactic sugar to > create partial functions, in the case you create a partial function using *curly > braces*: [...] > add_2 = add{2} Too obscure. What do curly braces have to do with partial function application? It seems pretty arbitrary. I know that ultimately ALL conventions are arbitrary, but we already have a couple of very strong conventions for curly braces (dicts and sets) and mathematicians have a few strong conventions for partial function application and currying, neither of which uses curly brackets. Besides, if we ever did support some sort of function-call-like syntax using braces spam{...} I would hope it would be for something more important than partial function application. You should consider prior art: - Scala uses a special value, which when passed to a function, returns a new function: # using Python syntax def add(a, b): return a+b add1 = add(1, _) # like partial(add, 1) - Perl6 gives all functions an "assuming" method: add1 = add.assuming(1) - ML and Haskell define all functions as single-argument functions. Multiple arguments are actually just syntactic sugar: func(a, b, c) # syntactic sugar for func(a)(b)(c) so partial application from the left is trivial: add1 = add(1) - but most other languages that I know of use a function or keyword "partial" (or sometimes, and inaccurately, "curry"). > Now all this can already be done with partial, Indeed it can. > but adding this syntactic > sugar would reduce the perception of `partial` as an advanced feature, > alleviating the use of closures created only for the sake of avoiding an > explicit partial. I don't think that is the case. I think that partial, and currying, are both relatively advanced features. Many programmers never quite grasp, or become comfortable with, functions as values. If we were to push partial application as a mainstream technique, and I'm not saying we should, but if we did, my vote would be to give function (and method) objects a partial method: add1 = add.partial(1) although possibly a less jargon name would be nicer: add1 = add.given(1) -- Steve From mertz at gnosis.cx Sat Aug 4 14:03:05 2018 From: mertz at gnosis.cx (David Mertz) Date: Sat, 4 Aug 2018 14:03:05 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <20180804172353.GW22431@ando.pearwood.info> References: <20180804131333.GU22431@ando.pearwood.info> <20180804172353.GW22431@ando.pearwood.info> Message-ID: On Sat, Aug 4, 2018, 1:24 PM Steven D'Aprano wrote: > If you think the uproar over PEP 572 was vicious, imagine what would > happen if we introduced new operators like ? ? ? ? ? etc instead. > > - keyboard support for entering the bulk of Unicode characters is > non-existent or poor; > > - without keyboard support, editor support for entering Unicode > characters is as best clunky, requiring the memorization of > obscure names, hex codes, or a GUI palette; > This is the essential problem. I write this as someone who has the vim conceal plugin configured to change my Python code into something with many of those funny characters Steven users as examples. But while I like looking at those, although recognizing it's quirky, entering any of them is enormously cumbersome. I did it once to configure my substitution macros (which are purely visual... What I type in is just ASCII and that's what is saved in soak, but it appears on screen with some replacements). > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: FB_IMG_1533405332279.jpg Type: image/jpeg Size: 46585 bytes Desc: not available URL: From stephanh42 at gmail.com Sat Aug 4 14:15:26 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Sat, 4 Aug 2018 20:15:26 +0200 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> <20180804172353.GW22431@ando.pearwood.info> Message-ID: I use these Vim abbreviations, which are derived from LaTeX https://gist.github.com/stephanh42/fc466e62bfb022a890ff2c4643eaf3a5 Stephan Op za 4 aug. 2018 20:03 schreef David Mertz : > On Sat, Aug 4, 2018, 1:24 PM Steven D'Aprano wrote: > >> If you think the uproar over PEP 572 was vicious, imagine what would >> happen if we introduced new operators like ? ? ? ? ? etc instead. >> >> - keyboard support for entering the bulk of Unicode characters is >> non-existent or poor; >> >> - without keyboard support, editor support for entering Unicode >> characters is as best clunky, requiring the memorization of >> obscure names, hex codes, or a GUI palette; >> > > This is the essential problem. I write this as someone who has the vim > conceal plugin configured to change my Python code into something with many > of those funny characters Steven users as examples. > > But while I like looking at those, although recognizing it's quirky, > entering any of them is enormously cumbersome. I did it once to configure > my substitution macros (which are purely visual... What I type in is just > ASCII and that's what is saved in soak, but it appears on screen with some > replacements). > >> _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Sat Aug 4 14:23:08 2018 From: mertz at gnosis.cx (David Mertz) Date: Sat, 4 Aug 2018 14:23:08 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> <20180804172353.GW22431@ando.pearwood.info> Message-ID: That's very nice Stephan. I think I'll add those to my machines. But not everyone uses vim. And although I use vim a lot, I also use other text editors, by choice or compulsion (e.g. editing code in web interface). And even when I have vim, I don't necessarily have the ability to install and test a .vimrc on the machines I use. There are probably analogous ways to add sequence bindings in other text editors. But until or unless such configurations are universal across operating systems and editors, this offers little help for hypothetical Unicode operators in Python. On Sat, Aug 4, 2018, 2:15 PM Stephan Houben wrote: > I use these Vim abbreviations, > which are derived from LaTeX > > https://gist.github.com/stephanh42/fc466e62bfb022a890ff2c4643eaf3a5 > > Stephan > > Op za 4 aug. 2018 20:03 schreef David Mertz : > >> On Sat, Aug 4, 2018, 1:24 PM Steven D'Aprano wrote: >> >>> If you think the uproar over PEP 572 was vicious, imagine what would >>> happen if we introduced new operators like ? ? ? ? ? etc instead. >>> >>> - keyboard support for entering the bulk of Unicode characters is >>> non-existent or poor; >>> >>> - without keyboard support, editor support for entering Unicode >>> characters is as best clunky, requiring the memorization of >>> obscure names, hex codes, or a GUI palette; >>> >> >> This is the essential problem. I write this as someone who has the vim >> conceal plugin configured to change my Python code into something with many >> of those funny characters Steven users as examples. >> >> But while I like looking at those, although recognizing it's quirky, >> entering any of them is enormously cumbersome. I did it once to configure >> my substitution macros (which are purely visual... What I type in is just >> ASCII and that's what is saved in soak, but it appears on screen with some >> replacements). >> >>> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From toddrjen at gmail.com Sat Aug 4 14:40:54 2018 From: toddrjen at gmail.com (Todd) Date: Sat, 4 Aug 2018 14:40:54 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <20180804131333.GU22431@ando.pearwood.info> References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: On Sat, Aug 4, 2018 at 9:13 AM, Steven D'Aprano wrote: > On Fri, Aug 03, 2018 at 03:17:42PM -0400, Todd wrote: > > > Boolean operators like the sort I am discussing have been a standard part > > of programming languages since forever. In fact, they are the basic > > operations on which modern microprocessors are built. > > > > The fact that Python, strictly speaking, doesn't have them is extremely > > unusual for a programming language. > > I'm rather surprised at this claim. > > Can you give a survey of such overridable boolean operators which are > available on modern microprocessors? > > What programming languages already have them? When you say "forever", > are you going back to Fortran in the 1950s? > Sorry I wasn't clear, I didn't mean overloadable boolean operators are standard, but rather boolean operators in general. I was trying to point out that there is nothing domain-specific about boolean operators. > > In many cases they aren't necessary in > > Python since Python's logical operators do the job well enough, but there > > are a set of highly diverse and highly prominent cases where those > logical > > operators won't work. > > Can you list some of these diverse and highly prominent use-cases? > > I can think of two: > > - elementwise boolean operators, such as in numpy; > > - SQL-like DSL languages; > > plus a third rather specialised and obscure use-case: > > - implementing non-binary logical operators, for (e.g. ternary > or fuzzy logic). > Also symbolic mathematics like in sympy. That is three. > > There are workarounds, but they are less than > > optimal for the reasons I describe, and the previous discussion I linked > to > > goes into much more detail why these new operators are important. > > There are certainly advantages to using binary operators over named > functions, and a shortage of good, ASCII punctuation suitable for new > operators. > > I don't think much of your names bOR etc. > > I think that before adding more ad hoc binary operators, we ought to > consider the possibility of custom operators. I am personally very strongly against custom operators. I just have visions of someone not liking how addition works for some particular class and deciding implementing a "?" operator would be a great idea. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Sat Aug 4 14:48:56 2018 From: rosuav at gmail.com (Chris Angelico) Date: Sun, 5 Aug 2018 04:48:56 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: On Sun, Aug 5, 2018 at 4:40 AM, Todd wrote: > > > On Sat, Aug 4, 2018 at 9:13 AM, Steven D'Aprano wrote: >> >> On Fri, Aug 03, 2018 at 03:17:42PM -0400, Todd wrote: >> >> > Boolean operators like the sort I am discussing have been a standard >> > part >> > of programming languages since forever. In fact, they are the basic >> > operations on which modern microprocessors are built. >> > >> > The fact that Python, strictly speaking, doesn't have them is extremely >> > unusual for a programming language. >> >> I'm rather surprised at this claim. >> >> Can you give a survey of such overridable boolean operators which are >> available on modern microprocessors? >> >> What programming languages already have them? When you say "forever", >> are you going back to Fortran in the 1950s? > > > Sorry I wasn't clear, I didn't mean overloadable boolean operators are > standard, but rather boolean operators in general. I was trying to point > out that there is nothing domain-specific about boolean operators. You say that Python doesn't have them. What aspect of boolean operators doesn't Python have? > I am personally very strongly against custom operators. I just have visions > of someone not liking how addition works for some particular class and > deciding implementing a "?" operator would be a great idea. Eww. (Before anyone jumps in and says "uhh you already have __add__", that is *not* U+002B PLUS SIGN, it is U+FF0B FULLWIDTH PLUS SIGN, which would indeed be a custom operator.) But ultimately, there is already nothing stopping people from doing this: def Ien(obj): """Return object size in machine words""" return sys.getsizeof(obj) // (sys.maxsize.bit_length() + 1) and mixing and matching that with the built-in len function. Give people freedom, and some will abuse it horrifically... but others will use it usefully and safely. ChrisA From danielhilst at gmail.com Sat Aug 4 18:18:32 2018 From: danielhilst at gmail.com (Daniel.) Date: Sat, 4 Aug 2018 19:18:32 -0300 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: That's an awesome library! Congratulation for doing this and thanks for sharing! Em s?b, 4 de ago de 2018 ?s 13:42, Robert Vanden Eynde escreveu: > The funcoperators lib on pypi does exactly that: > > from funcoperators import partially > > @partially > def add(x: int, y: int) -> int: > return x + y > > add_2 = add[2] > > @partiallymulti > def stuff(x,y,z): > return x - y + 2*z > > sort = partially(sorted) > sort_by_x = sort.key(key=lambda element: element.x) > > The ".key" means "give a keyword argument". > The ".val" or [] gives a positional argument. > The ".part" accept positional and keyword arguments. > > Le sam. 4 ao?t 2018 ? 18:03, Fabrizio Messina a > ?crit : > >> >> Hello, I would like to propose a new method to create a partial function. >> >> At the moment we have to load the *partial* function from the *functool* >> library, and apply it to an existing function, e.g. >> >> from functools import partial >> >> >> def add(x: int, y: int) -> int: >> return x + y >> >> >> add_2 = partial(add, 2) >> >> >> >> While partial expose the mechanism excellently its instantiation method >> is, at times, not very friendly, I would like to propose a syntactic sugar >> to create partial functions, in the case you create a partial function >> using *curly braces*: >> >> >> def add(x: int, y: int) -> int: >> return x + y >> >> add_2 = add{2} >> >> >> At the moment this causes SyntaxError so the change is retro-compatible. >> >> In the case of key word arguments we could have: >> >> sort_by_x = sort{key=lambda element: element.x} >> >> >> That could be good as it would be an easy way to pre-load functions >> without having to eagerly compute it, but without needing to pass the >> entire function parameters to to other scopes. >> >> >> # prepare the function >> get_sorted_users: Callable[[], Iterator[User]] = sort{users, key=lambda >> user: user.creation_date} >> >> # continue with job at hand >> ... >> >> # some where else, maybe another process >> sorted_users = list(get_sorted_users()) >> >> >> >> Even create a factory method on the fly: >> @dataclass >> class Product: >> name: str >> category: Category >> price: Decimal >> >> >> smartphone_factory = Product{category=smartphone_category} >> >> >> >> Now all this can already be done with partial, but adding this syntactic >> sugar would reduce the perception of `partial` as an advanced feature, >> alleviating the use of closures created only for the sake of avoiding an >> explicit partial. >> >> In my opinion this syntactic sugar has a lot of potential adoption seen >> the general interest in functional programming. >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -- ?If you're going to try, go all the way. Otherwise, don't even start. ..." Charles Bukowski -------------- next part -------------- An HTML attachment was scrubbed... URL: From robertve92 at gmail.com Sat Aug 4 18:38:15 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sun, 5 Aug 2018 00:38:15 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: You can read the other functionalities on the project page : https://pypi.org/project/funcoperators/ And if you want to solve the "can't partial from right that allows to use the Ellipsis '...' : # the built-in "pow" doesn't take keyword arguments, so partial can't be used. from funcoperators import elipartial, bracket square = elipartial (pow, ..., 2) # = pow(something, 2) square(3) # 9 @bracket def f(x,y,z): return x - y + 2 * z r = f(1,2,3) g = f[1, ..., 3] # g = a function with one argument: y r = g(2) bracket merges the concept of partiallymulti, and elipartial. Partially Multi allowing to write f[1, 2] as a sugar for f[1][2] (which is different than partial(f, (1,2)) ). Le dim. 5 ao?t 2018 ? 00:18, Daniel. a ?crit : > That's an awesome library! Congratulation for doing this and thanks for > sharing! > > Em s?b, 4 de ago de 2018 ?s 13:42, Robert Vanden Eynde < > robertve92 at gmail.com> escreveu: > >> The funcoperators lib on pypi does exactly that: >> >> from funcoperators import partially >> >> @partially >> def add(x: int, y: int) -> int: >> return x + y >> >> add_2 = add[2] >> >> @partiallymulti >> def stuff(x,y,z): >> return x - y + 2*z >> >> sort = partially(sorted) >> sort_by_x = sort.key(key=lambda element: element.x) >> >> The ".key" means "give a keyword argument". >> The ".val" or [] gives a positional argument. >> The ".part" accept positional and keyword arguments. >> >> Le sam. 4 ao?t 2018 ? 18:03, Fabrizio Messina a >> ?crit : >> >>> >>> Hello, I would like to propose a new method to create a partial function. >>> >>> At the moment we have to load the *partial* function from the *functool* >>> library, and apply it to an existing function, e.g. >>> >>> from functools import partial >>> >>> >>> def add(x: int, y: int) -> int: >>> return x + y >>> >>> >>> add_2 = partial(add, 2) >>> >>> >>> >>> While partial expose the mechanism excellently its instantiation method >>> is, at times, not very friendly, I would like to propose a syntactic sugar >>> to create partial functions, in the case you create a partial function >>> using *curly braces*: >>> >>> >>> def add(x: int, y: int) -> int: >>> return x + y >>> >>> add_2 = add{2} >>> >>> >>> At the moment this causes SyntaxError so the change is retro-compatible. >>> >>> In the case of key word arguments we could have: >>> >>> sort_by_x = sort{key=lambda element: element.x} >>> >>> >>> That could be good as it would be an easy way to pre-load functions >>> without having to eagerly compute it, but without needing to pass the >>> entire function parameters to to other scopes. >>> >>> >>> # prepare the function >>> get_sorted_users: Callable[[], Iterator[User]] = sort{users, key=lambda >>> user: user.creation_date} >>> >>> # continue with job at hand >>> ... >>> >>> # some where else, maybe another process >>> sorted_users = list(get_sorted_users()) >>> >>> >>> >>> Even create a factory method on the fly: >>> @dataclass >>> class Product: >>> name: str >>> category: Category >>> price: Decimal >>> >>> >>> smartphone_factory = Product{category=smartphone_category} >>> >>> >>> >>> Now all this can already be done with partial, but adding this syntactic >>> sugar would reduce the perception of `partial` as an advanced feature, >>> alleviating the use of closures created only for the sake of avoiding an >>> explicit partial. >>> >>> In my opinion this syntactic sugar has a lot of potential adoption seen >>> the general interest in functional programming. >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > > -- > ?If you're going to try, go all the way. Otherwise, don't even start. ..." > Charles Bukowski > -------------- next part -------------- An HTML attachment was scrubbed... URL: From toddrjen at gmail.com Sat Aug 4 21:16:35 2018 From: toddrjen at gmail.com (Todd) Date: Sat, 4 Aug 2018 21:16:35 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: On Sat, Aug 4, 2018 at 2:48 PM, Chris Angelico wrote: > On Sun, Aug 5, 2018 at 4:40 AM, Todd wrote: > > > > > > On Sat, Aug 4, 2018 at 9:13 AM, Steven D'Aprano > wrote: > >> > >> On Fri, Aug 03, 2018 at 03:17:42PM -0400, Todd wrote: > >> > >> > Boolean operators like the sort I am discussing have been a standard > >> > part > >> > of programming languages since forever. In fact, they are the basic > >> > operations on which modern microprocessors are built. > >> > > >> > The fact that Python, strictly speaking, doesn't have them is > extremely > >> > unusual for a programming language. > >> > >> I'm rather surprised at this claim. > >> > >> Can you give a survey of such overridable boolean operators which are > >> available on modern microprocessors? > >> > >> What programming languages already have them? When you say "forever", > >> are you going back to Fortran in the 1950s? > > > > > > Sorry I wasn't clear, I didn't mean overloadable boolean operators are > > standard, but rather boolean operators in general. I was trying to point > > out that there is nothing domain-specific about boolean operators. > > You say that Python doesn't have them. What aspect of boolean > operators doesn't Python have? > Python's "and" and "or" don't return "True" or "False" per se, they return one of the inputs based on their respective truthiness. So although they are logical operators, they are not strictly boolean operators. > > I am personally very strongly against custom operators. I just have > visions > > of someone not liking how addition works for some particular class and > > deciding implementing a "?" operator would be a great idea. > > Eww. (Before anyone jumps in and says "uhh you already have __add__", > that is *not* U+002B PLUS SIGN, it is U+FF0B FULLWIDTH PLUS SIGN, > which would indeed be a custom operator.) > > But ultimately, there is already nothing stopping people from doing this: > > def Ien(obj): > """Return object size in machine words""" > return sys.getsizeof(obj) // (sys.maxsize.bit_length() + 1) > > and mixing and matching that with the built-in len function. Give > people freedom, and some will abuse it horrifically... but others will > use it usefully and safely. > In your example, you are intentionally picking a character purely because it happens to look similar to a completely different character. That isn't the sort of thing that can happen innocently or by accident. By contrast, using a valid mathematical symbol for the corresponding mathematical operation is exactly the sort of thing allowing new operators is meant to support. The fact that this symbol happens to look similar in some fonts to the normal plus operator is something that may not even occur to the person who chose to use the operator. It would likely seem obvious to the developer at the time. So although we can't generally prevent people from being actively malicious, I think we should at least try to avoid making it overly easy to make code an unreadable mess. And allowing custom operators seems to me to make it way too easy to produce an unreadable mess. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Sat Aug 4 21:48:33 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sun, 5 Aug 2018 11:48:33 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: <20180805014833.GZ22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 02:40:54PM -0400, Todd wrote: > On Sat, Aug 4, 2018 at 9:13 AM, Steven D'Aprano wrote: > > > On Fri, Aug 03, 2018 at 03:17:42PM -0400, Todd wrote: > > > > > Boolean operators like the sort I am discussing have been a standard part > > > of programming languages since forever. In fact, they are the basic > > > operations on which modern microprocessors are built. > > > > > > The fact that Python, strictly speaking, doesn't have them is extremely > > > unusual for a programming language. [...] > Sorry I wasn't clear, I didn't mean overloadable boolean operators are > standard, but rather boolean operators in general. I was trying to point > out that there is nothing domain-specific about boolean operators. Right -- and Python has such common boolean operators. It isn't clear that there's much need for xor, nand, nor, etc. (There are a grand total of 16 distinct boolean operators which take two operands, but few of them are useful except under very specialised circumstances.) [I asked:] > > Can you list some of these diverse and highly prominent use-cases? > > > > I can think of two: > > > > - elementwise boolean operators, such as in numpy; > > > > - SQL-like DSL languages; > > > > plus a third rather specialised and obscure use-case: > > > > - implementing non-binary logical operators, for (e.g. ternary > > or fuzzy logic). > > Also symbolic mathematics like in sympy. That is three. I don't think symbolic mathematics is "highly prominent" (your words). I would consider it in the same category as fuzzy logic: specialised and unusual. To my mind, this basically means there are two important use-cases: - numpy and elementwise boolean operators; - SQL-like queries; and a couple of more specialised uses. > > I think that before adding more ad hoc binary operators, we ought to > > consider the possibility of custom operators. > > I am personally very strongly against custom operators. I just have > visions of someone not liking how addition works for some particular class > and deciding implementing a "?" operator would be a great idea. I have visions of someone not liking how boolean operators `or` and `and` work for some particular class and deciding that overridable boolean operators would be a great idea. Under my proposal, you couldn't invent new symbolic operators like ?. Operators would be limited to legal identifiers, so people can do no worse than they can already do for method names, e.g. ugly names like "bOR" or "bAND". Given this proposal, your overridable boolean operators are instantly available, and using the proper names "or" and "and". There's no ambiguity, because the custom operators will always require a prefix (I suggested ~ but that won't work, perhaps ! or @ will work). And the benefit is that you don't have to come back next year with another PEP to introduce bNAND and bNOR operators. -- Steve From steve at pearwood.info Sat Aug 4 22:28:00 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sun, 5 Aug 2018 12:28:00 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180804131333.GU22431@ando.pearwood.info> Message-ID: <20180805022800.GA22431@ando.pearwood.info> On Sat, Aug 04, 2018 at 09:16:35PM -0400, Todd wrote: [Chris said:] > > You say that Python doesn't have them. What aspect of boolean > > operators doesn't Python have? > > > > Python's "and" and "or" don't return "True" or "False" per se, they return > one of the inputs based on their respective truthiness. So although they > are logical operators, they are not strictly boolean operators. According to Python's rules for truthiness, they are boolean operators. According to Python's rules, True and False aren't the only boolean values. They're merely the canonical true and false values, but otherwised unprivileged. So I don't think this is a difference that makes any real difference. You might as well complain that Python doesn't strictly have ints, because some other languages limit their ints to 32 or 64 bits, and Python doesn't. But either way, this isn't a really important factor. If we add overridable "boolean operators" like bOR and bAND, the fact that they can be overridden means that they won't be limited to returning True and False either: - numpy elementwise operators will return arrays; - sympy will return symbolic expressions; - ternary logic will return trits (say, true/false/maybe); etc. So the question of Python truthiness is not really relevant. [...] > In your example, you are intentionally picking a character purely because > it happens to look similar to a completely different character. That isn't > the sort of thing that can happen innocently or by accident. I see lots of newbies, and experienced coders who ought to know better, using variables like l and sometimes even O. Don't underestimate the power of laziness and thoughtlessness. On the other hand, such poor choices are easily fixed with a gentle or not-so-gentle application of the Clue Bat and a bit of minor refactoring. Changing variable names is easy. Likewise, if somebody chooses an ugly custom operator like O01l it isn't hard to refactor it to something more meaningful. > By contrast, > using a valid mathematical symbol for the corresponding mathematical > operation is exactly the sort of thing allowing new operators is meant to > support. The term "strawman fallacy" gets misused a lot on the internet, mostly by people who use it as a short-hand for: Dammit, you've just found the flaw in my argument I didn't notice, so I'll try to distract attention by falsely accusing you of a fallacy. But your comments about symbols like ? truly are a strawman: Substituting a person?s actual position or argument with a distorted, exaggerated, or misrepresented version of the position of the argument. https://www.logicallyfallacious.com/tools/lp/Bo/LogicalFallacies/169/Strawman-Fallacy I never proposed supporting arbitrary Unicode symbols like ? (full width plus sign), in fact the opposite, I explicitly ruled it out. In response to a question about supporting Unicode operators, I said "I'm not touching that hornet's nest with a twenty foot pole." and listed a number of social and technical reasons for not supporting Unicode operators. I said that the operators would have to be legal identifiers. So no, operators like ? ? ? ? ? and ? are not an option under my proposal. -- Steve From gregory.lielens at gmail.com Sun Aug 5 01:13:44 2018 From: gregory.lielens at gmail.com (=?UTF-8?Q?Gr=C3=A9gory_Lielens?=) Date: Sat, 4 Aug 2018 22:13:44 -0700 (PDT) Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <20180805022800.GA22431@ando.pearwood.info> References: <20180804131333.GU22431@ando.pearwood.info> <20180805022800.GA22431@ando.pearwood.info> Message-ID: <3a229905-0832-41a8-b304-3f7d8a67071f@googlegroups.com> You should have a look at old PEP225 "Elementwise operators", that proposed ~ as a modifier for many existing operator, to indicate they do mostly what their "normal counterpart do, but act on the inner/ elements of an object instead of on the whole. This was only a memorisation technique, as all tilde operators were defined individually and has associated magic/dunder method (they had also the same precedence as the non-tilded version). It was mainly for ~* to be used as classic numpy multiply and * used as matrix multiply, but as an aside, ~and, ~or, ~not and ~xor were defined as elementwise logical operators, bitwise when applied on int-like objects. Also xor was proposed as a new short-circuiting Classic operator, for orthogonality (the value returned when doing true_a xor true_b was not fixed in the PEP, I can not decide between False and None ;-) Funny this come back after all this time From gregory.lielens at gmail.com Sun Aug 5 01:36:36 2018 From: gregory.lielens at gmail.com (=?UTF-8?Q?Gr=C3=A9gory_Lielens?=) Date: Sat, 4 Aug 2018 22:36:36 -0700 (PDT) Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <3a229905-0832-41a8-b304-3f7d8a67071f@googlegroups.com> References: <20180804131333.GU22431@ando.pearwood.info> <20180805022800.GA22431@ando.pearwood.info> <3a229905-0832-41a8-b304-3f7d8a67071f@googlegroups.com> Message-ID: <1f71926a-68a9-4cd2-9863-89bb8982b63b@googlegroups.com> Obviously I'm +1 on this, but a little bit less so than at the time of proposal, let's say +0.8...at PEP 225 time, @ matmul operator did not exist (it was the competing PEP 211, also to address matrix multiply, that proposed @...both were rejected at the time lol). But now that @ exists, there would be either redundancy or lack of orthogonality among the family of multiplication infix operators... From chris.barker at noaa.gov Mon Aug 6 14:11:17 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Mon, 6 Aug 2018 11:11:17 -0700 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: On Fri, Aug 3, 2018 at 9:13 PM, Todd wrote: > >> Also, in a common use-case, bitwise-and behaves the same as logical_and, >> e.g. >> >> if (arr > x) & (arr2 == y) >> >> This "works" because both arrays being bitwise-anded are boolean arrays. >> > > There are a few problems with using the bitwise operators. > > First, and most important in my opinion, is that the precedence is > significantly off from that of the logical operators. > yes, that's true, and perhaps too bad, but as they are spelled differently, not a killer. if you are switching back and forth between, say, array logical operations > and "normal" logical operations it is easy to mess up. > well, as you generally are working with arrays or not, again, not too bad. > Third is that it allows both boolean and bitwise operations to be carried > out on the same data types. Numpy is a special case where the two > basically are equivalent if you are working with boolean arrays. But that > is a special case. > I kind of muddled my point -- the main trust was that overloading the bitwise operators to do logical operations is a fine idea -- many objects will have no or limited use for bitwise operations. In fact, if I were to re-design the numpy API, I would overload the bitwise operators to do logic, and use the special functions for bitwise operations: np.bitwise_and etc. rather than having to use logical_and and friends the way we do now. So any new class that doesn't already make use of the bitwise operators can do that. (yes, still the precedence issue, but what can you do?) -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Mon Aug 6 14:14:36 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Mon, 6 Aug 2018 11:14:36 -0700 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: On Mon, Aug 6, 2018 at 11:11 AM, Chris Barker wrote: > So any new class that doesn't already make use of the bitwise operators > can do that. > just like set() -- which I think has been mentioned here already. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Mon Aug 6 17:44:24 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Mon, 6 Aug 2018 14:44:24 -0700 (PDT) Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: This doesn't work because the logical Boolean operators short circuit in Python. So you could not even define these operators for the regular Python types. Your two examples numpy and SQLAlchemy don't want this short-circuiting behavior, so you would never want to write anything like (some_array or some_other_array) The reader of this code might imagine that there is some short circuiting or conversion to Boolean. The essential problem here is that you want a nicer way to create symbolic graphs with Boolean operators. But the general problem is that Python always has wrinkles when creating symbolic graphs. Besides numpy conditions and SQLAlchemy, sympy and tensorflow also build symbolic graphs. They also struggle with succinctness. You will never get the symbolic graph to look just like pseudocode the way pure Python does. On Friday, August 3, 2018 at 1:48:02 PM UTC-4, Todd Jennings wrote: > > Coming back to the previous discussion about a new set of overloadable > boolean operators [1], I have an idea for overloadable boolean operators > that I think might work. The idea would be to define four new operators > that take two inputs and return a boolean result based on them. This > behavior can be overridden in appropriate dunder methods. These operators > would have similar precedence to existing logical operators. The operators > would be: > > bNOT - boolean "not" > bAND - boolean "and" > bOR - boolean "or" > bXOR - boolean "xor" > > With corresponding dunder methods: > > __bNOT__ and _rbNOT__ (or __r_bNOT__) > __bAND__ and _rbAND__ (or __r_bAND__) > __bOR__ and _rbOR__ (or __r_bOR__) > __bXOR__ and _rbXOR__ (or __r_bXOR__) > > The basic idea is that the "b" is short for "boolean", and we change the > rest of the operator to upercase to avoid confusions with the existing > operators. I think these operators would be preferably to the proposals so > far (see [1] again) for a few reasons: > > 1. They are not easy to mistake with existing operators. They are > clearly not similar to the existing bitwise operators like & or |, and > although they are clearly related to the "not", "and", and "or" I think > they are distinct enough that it should not be easy to confuse the two or > accidentally use one in place of the other. > > 2. They are related to the operations they carry out, which is also an > advantage over the existing bitwise operators. > > 3. The corresponding dunder methods (such as __bAND__ and _rbAND__) are > obvious and not easily confused with anything else. > > 4. The unusual capitalization means they are not likely to be used much > in existing Python code. It doesn't fall under any standard capitalization > scheme I am aware of. > > 5. At least for english the capitalization means they are not easy to > confuse with existing words. For example Band is a word, but it is not > likely to be capitalized as bAND. > > As to why this is useful, the overall problem is that the current logical > operators, like and, or, and not, cannot be overloaded, which means > projects like numpy and SQLAlchemy instead have to (ab)use bitwise > operators to define their own boolean operations (for example elementwise > "and" in numpy arrays). This has a variety of problems, such not having > appropriate precedence leading to precedence errors being common, and the > simple fact that this precludes them from using the bitwise operators for > bitwise operations. > > There was a proposal to allow overloading boolean operators in Pep-335 > [2], but that PEP was rejected for a variety of very good reasons. I think > none of those reasons (besides the conversation fizzling out) apply to my > proposal. > > So the alternative proposal that has been floating around is to instead > define new operators specifically for this. Although there seemed to be > some support for this in principle, the actually operators so far have not > met with much enthusiasm. So far the main operators proposed so far seem > to be: > > 1. Double bitwise operators, such as && and ||. These have the > disadvantage of looking like they should be a type of bitwise operator. > > 2. the existing operators, with some non-letter character at the front and > back, like ".and.". These have the advantage that they are currently not > valid syntax in most cases, but I think are too similar to existing logical > operators, to easy to confuse, and it is not immediately obvious in what > way they should differ from existing operators. They also mean different > things in other languages. > > So I think my proposal addresses the main issues raised with existing > proposals, but has the downside that it requires new keywords. > > Thoughts? > > [1] > https://mail.python.org/pipermail/python-ideas/2015-November/037207.html > [2] https://www.python.org/dev/peps/pep-0335/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Mon Aug 6 17:46:58 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Mon, 6 Aug 2018 14:46:58 -0700 (PDT) Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> Message-ID: <708500b6-cb0e-4354-a637-ce9ed4f0e591@googlegroups.com> By the way, these are not "partial functions", and shouldn't be called that. These are "partial function applications". On Saturday, August 4, 2018 at 12:03:50 PM UTC-4, Fabrizio Messina wrote: > > > Hello, I would like to propose a new method to create a partial function. > > At the moment we have to load the *partial* function from the *functool* > library, and apply it to an existing function, e.g. > > from functools import partial > > > def add(x: int, y: int) -> int: > return x + y > > > add_2 = partial(add, 2) > > > > While partial expose the mechanism excellently its instantiation method > is, at times, not very friendly, I would like to propose a syntactic sugar > to create partial functions, in the case you create a partial function > using *curly braces*: > > > def add(x: int, y: int) -> int: > return x + y > > add_2 = add{2} > > > At the moment this causes SyntaxError so the change is retro-compatible. > > In the case of key word arguments we could have: > > sort_by_x = sort{key=lambda element: element.x} > > > That could be good as it would be an easy way to pre-load functions > without having to eagerly compute it, but without needing to pass the > entire function parameters to to other scopes. > > > # prepare the function > get_sorted_users: Callable[[], Iterator[User]] = sort{users, key=lambda > user: user.creation_date} > > # continue with job at hand > ... > > # some where else, maybe another process > sorted_users = list(get_sorted_users()) > > > > Even create a factory method on the fly: > @dataclass > class Product: > name: str > category: Category > price: Decimal > > > smartphone_factory = Product{category=smartphone_category} > > > > Now all this can already be done with partial, but adding this syntactic > sugar would reduce the perception of `partial` as an advanced feature, > alleviating the use of closures created only for the sake of avoiding an > explicit partial. > > In my opinion this syntactic sugar has a lot of potential adoption seen > the general interest in functional programming. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Mon Aug 6 21:02:30 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 7 Aug 2018 11:02:30 +1000 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: <20180807010228.GD22431@ando.pearwood.info> On Mon, Aug 06, 2018 at 02:44:24PM -0700, Neil Girdhar wrote: > This doesn't work because the logical Boolean operators short circuit in > Python. So you could not even define these operators for the regular > Python types. Todd is not proposing to add dunder methods for the existing "or" and "and" operators. Todd is proposing four new operators spelled "bAND", "bOR", "bXOR" and "bNOT", which aren't short-circuiting and call dunder methods, just like other operators including "in". You seem to be saying that "this" (defining new operators that call dunder methods) doesn't work because a set of *completely different* existing operators short-circuit. If that's not what you meant, I don't understand what you actually did mean. > Your two examples numpy and SQLAlchemy don't want this > short-circuiting behavior, so you would never want to write anything like > > (some_array or some_other_array) > > The reader of this code might imagine that there is some short circuiting > or conversion to Boolean. Fortunately Todd isn't proposing that. -- Steve From mistersheik at gmail.com Mon Aug 6 21:14:20 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Mon, 6 Aug 2018 21:14:20 -0400 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: <20180807010228.GD22431@ando.pearwood.info> References: <20180807010228.GD22431@ando.pearwood.info> Message-ID: Oh, I see, I thought he wanted to override the original logical operators. I don't like adding more operators just to make symbolic equation generation simpler. I think keeping the language simple and using the "numpy.logical_and" function is better than making the language more complicated for a small fraction of users. There will always be a gap between Python and symbolic equation generation. On Mon, Aug 6, 2018 at 9:03 PM Steven D'Aprano wrote: > On Mon, Aug 06, 2018 at 02:44:24PM -0700, Neil Girdhar wrote: > > > This doesn't work because the logical Boolean operators short circuit in > > Python. So you could not even define these operators for the regular > > Python types. > > Todd is not proposing to add dunder methods for the existing "or" and > "and" operators. > > Todd is proposing four new operators spelled "bAND", "bOR", "bXOR" and > "bNOT", which aren't short-circuiting and call dunder methods, just like > other operators including "in". > > You seem to be saying that "this" (defining new operators that call > dunder methods) doesn't work because a set of *completely different* > existing operators short-circuit. If that's not what you meant, I > don't understand what you actually did mean. > > > > Your two examples numpy and SQLAlchemy don't want this > > short-circuiting behavior, so you would never want to write anything like > > > > (some_array or some_other_array) > > > > The reader of this code might imagine that there is some short > circuiting > > or conversion to Boolean. > > Fortunately Todd isn't proposing that. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/LgwmlPp6YqM/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gregory.lielens at gmail.com Tue Aug 7 00:38:57 2018 From: gregory.lielens at gmail.com (=?UTF-8?Q?Gr=C3=A9gory_Lielens?=) Date: Mon, 6 Aug 2018 21:38:57 -0700 (PDT) Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: <20180807010228.GD22431@ando.pearwood.info> Message-ID: <0203920a-c182-4e94-bb1f-ebec11466f33@googlegroups.com> A small remark for Todd's proposal: I think you should treat the new not (bNOT in the original proposal) differently: it's not binary, so it should not have 2 dunders, the right one is not needed (or there is only the right one, in a way, but other unary ops use the classic dunder iirc...) Also, not having xor is made more painful by this proposal (or for any proposal for new Boolean operators using variants of and/or/not)... I have been bitten a few times writing xor in my code (not often, because xor is done less often), it already feel like it's missing from python. With additional duplicated operators, including bXOR, the missing xor is annoying like a missing teeth: even if you don't use it so much, you think of it all the time ;-) Greg. From porton at narod.ru Tue Aug 7 17:57:51 2018 From: porton at narod.ru (Victor Porton) Date: Wed, 8 Aug 2018 00:57:51 +0300 Subject: [Python-ideas] File format for automatic and manual tests Message-ID: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> This is an idea of a new PEP. I propose to create a portable file format which will list command line options to run Python scripts with dual purpose: 1. for automatic tests executing scripts from this file (and optionally checking their stdout against specified values). 2. for running the scripts in a Python debugger. The scripts may be either real command line applications written in Python or scripts created specifically for testing. Currently I use PyCharm to debug my command line application. PyCharm allows to define and store different command line options for Python scripts. This has two drawbacks: 1. It is not portable and this makes me not to submit the PyCharm configuration into my GitHub repo. 2. I can't (at least easily) use these command line profiles for automated testing. I propose to create the file format listing such test/debug cases based on options available in PyCharm, that is: - Python script path - command line parameters - environment variables - Python interpreter and interpreter options - working directory - tweaks of PYTHONPATH to include our source directory as necessary - redirect input from It would be nice to add "variables" (substituted with strings) to our file format. Automated tests should support iterations of command lines with different vars substituted. I hope a future version of PyCharm will support our file format. From steve at pearwood.info Tue Aug 7 19:18:42 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 8 Aug 2018 09:18:42 +1000 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> Message-ID: <20180807231842.GE22431@ando.pearwood.info> On Wed, Aug 08, 2018 at 12:57:51AM +0300, Victor Porton wrote: > This is an idea of a new PEP. > > I propose to create a portable file format which will list command line > options to run Python scripts with dual purpose: Feel free to create whatever file format you like. There are tens of thousands of them, one more won't hurt, and you certainly don't need to write a PEP first. But I see no reason why this has anything to do with the Python standard library. Can you explain why you want to distribute an experimental file format in the Python std lib? That means that the file format must be stable (you cannot make any future changes, due to backwards compatibility), and only available for Python 3.8 or higher. [...] > PyCharm allows to define and store different command line options for > Python scripts. > > This has two drawbacks: > > 1. It is not portable and this makes me not to submit the PyCharm > configuration into my GitHub repo. You can put anything you like in your GitHub repo, GitHub won't care whether it is portable or not. -- Steve From porton at narod.ru Tue Aug 7 19:32:41 2018 From: porton at narod.ru (Victor Porton) Date: Wed, 8 Aug 2018 02:32:41 +0300 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <20180807231842.GE22431@ando.pearwood.info> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> <20180807231842.GE22431@ando.pearwood.info> Message-ID: <4cf674f3-a001-042d-3336-c1778f72fa50@narod.ru> On 08/08/18 02:18, Steven D'Aprano wrote: > On Wed, Aug 08, 2018 at 12:57:51AM +0300, Victor Porton wrote: >> This is an idea of a new PEP. >> >> I propose to create a portable file format which will list command line >> options to run Python scripts with dual purpose: > Feel free to create whatever file format you like. There are tens of > thousands of them, one more won't hurt, and you certainly don't need to > write a PEP first. > > But I see no reason why this has anything to do with the Python standard > library. Can you explain why you want to distribute an experimental > file format in the Python std lib? As I pointed out, I want this format to become common (standardized!) for different IDEs and other development environment. > That means that the file format must be stable (you cannot make any > future changes, due to backwards compatibility), and only available for > Python 3.8 or higher. We can support this file format with an library (rather than to distribute it with Python) for: 1. make it available for the current version of Python; 2. don't take space in Python distribution. The issue is in the file format itself, not in the libraries it may be processed by. I propose to make the PEP containing a description of the file format (to be developed). It is important for integration among different development environments. The PEP should be marked as "stable" when the format becomes stable. > > [...] >> PyCharm allows to define and store different command line options for >> Python scripts. >> >> This has two drawbacks: >> >> 1. It is not portable and this makes me not to submit the PyCharm >> configuration into my GitHub repo. > You can put anything you like in your GitHub repo, GitHub won't care > whether it is portable or not. > > > From arj.python at gmail.com Tue Aug 7 22:28:34 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Wed, 8 Aug 2018 06:28:34 +0400 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> Message-ID: a suggest : don't make it obligatory i think it might come as suggested settings as settings on different environments different. or we can specify only in modules like in setup.py the name of the file, then each user configures it's own (considering pip we can make use it false by default) in the case of using it in a script, we can add a special comment # -*- file settings : True -*- Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From kenlhilton at gmail.com Wed Aug 8 02:14:47 2018 From: kenlhilton at gmail.com (Ken Hilton) Date: Wed, 8 Aug 2018 08:14:47 +0200 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError Message-ID: This mostly springs off of a comment I saw in some thread. The point of a with statement is that it ensures that some resource will be disposed of, yes? For example, this: with open(filename) as f: contents = f.read() is better than this: contents = open(filename).read() because the former definitely closes the file while the latter relies on garbage collection? The point of a yield expression is to suspend execution. This is nice for efficient looping because instead of having to hold all results in memory, each result can be consumed immediately, yes? Therefore this: def five_to_one(): for i in range(4): yield 5 - i is better than this: def five_to_one(): result = [] for i in range(4): result.append(5 - i) return result because the former suspends execution of "five_to_one" while the latter holds all five results in memory? Now, let's take a look at the following scenario: def read_multiple(*filenames): for filename in filenames: with open(filename) as f: yield f.read() Can you spot the problem? The "with open(filename)" statement is supposed to ensure that the file object is disposed of properly. However, the "yield f.read()" statement suspends execution within the with block, so if this happened: for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): if contents == 'hello': break and the contents of "chunk2" were "hello" then the loop would exit, and "chunk2" would never be closed! Yielding inside a with block, therefore, doesn't make sense and can only lead to obscure bugs. The proper way to define the "read_multiple" function would be like so: def read_multiple(*filenames): for filename in filenames: with open(filename) as f: contents = f.read() yield contents Save the contents in a variable somewhere, then yield the variable, instead of suspending execution within a context manager. I believe all possible cases where one would yield inside a context manager can be covered by saving anything required from the context manager and then yielding the results outside. Therefore, I propose making a "yield" inside a with block become a SyntaxError. This means the first "read_multiple" definition I presented will become illegal and fail *at compile-time*. However, it is still legal to define a generator inside a with block: def pass_file_chars(oldfunc): with open('secretfile') as f: contents = f.read() @functools.wraps def newfunc(*args, **kwargs): for char in contents: yield oldfunc(char, *args, **kwargs) return newfunc This is probably a bad example, but I hope it still explains why it should be legal to define generators in context managers - as long as the with block serves its purpose correctly, everything else should still work normally. For those concerned about backwards compatibility: I believe that those who attempt to yield inside a context manager will already discover that results are undefined when doing so; this will simply make it more obvious that suspending execution in a with block is not meant to happen, and convert undefined behavior into a straight-up SyntaxError. What are your thoughts? Sharing, Ken Hilton; -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Wed Aug 8 02:24:16 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Wed, 8 Aug 2018 10:24:16 +0400 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: i think a SyntaxError won't be appropriate as it is valid syntax as the lexer finds nothing wrong it falls more i think like out of index errors and the like, a ContextManagerError ? else, a request to add headings like EXAMPLES ========= in your discussion yours, -- Abdur-Rahmaan Janhangeer https://github.com/abdur-rahmaanj Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From elazarg at gmail.com Wed Aug 8 02:31:35 2018 From: elazarg at gmail.com (Elazar) Date: Tue, 7 Aug 2018 23:31:35 -0700 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: On Tue, Aug 7, 2018 at 11:16 PM Ken Hilton wrote: > ... > Now, let's take a look at the following scenario: > > def read_multiple(*filenames): > for filename in filenames: > with open(filename) as f: > yield f.read() > > Can you spot the problem? The "with open(filename)" statement is supposed > to ensure that the file object is disposed of properly. However, the "yield > f.read()" statement suspends execution within the with block, so if this > happened: > > for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): > if contents == 'hello': > break > > and the contents of "chunk2" were "hello" then the loop would exit, and > "chunk2" would never be closed! Yielding inside a with block, therefore, > doesn't make sense and can only lead to obscure bugs. > Instead of disallowing code, this is a case for allowing with expressions: def read_multiple(*filenames): for filename in filenames: yield (f.read() with open(filename) as f) Elazar -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 8 02:32:15 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 8 Aug 2018 16:32:15 +1000 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: On Wed, Aug 8, 2018 at 4:14 PM, Ken Hilton wrote: > This mostly springs off of a comment I saw in some thread. > > The point of a with statement is that it ensures that some resource will be > disposed of, yes? For example, this: > > with open(filename) as f: > contents = f.read() > > is better than this: > > contents = open(filename).read() > > because the former definitely closes the file while the latter relies on > garbage collection? Technically, the 'with' statement ensures that the file will be closed before the line of code following it is run. So in this example: with open(filename, "w") as f: f.write(...) os.rename(filename, target_filename) you have a guarantee that the file is closed prior to the rename call. > Now, let's take a look at the following scenario: > > def read_multiple(*filenames): > for filename in filenames: > with open(filename) as f: > yield f.read() > > Can you spot the problem? The "with open(filename)" statement is supposed to > ensure that the file object is disposed of properly. However, the "yield > f.read()" statement suspends execution within the with block, so if this > happened: > > for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): > if contents == 'hello': > break > > and the contents of "chunk2" were "hello" then the loop would exit, and > "chunk2" would never be closed! Yielding inside a with block, therefore, > doesn't make sense and can only lead to obscure bugs. This is only a problem if you consider it to be one. The value of the 'with' statement is not destroyed; for example, you're capped at _one_ open file (whereas without the context manager, it's entirely possible for file-open in a loop to leak a large number of handles). > I believe all possible cases where one would yield inside a context manager > can be covered by saving anything required from the context manager and then > yielding the results outside. Therefore, I propose making a "yield" inside a > with block become a SyntaxError. What about this: def read_words(*filenames): for filename in filenames: with open(filename) as f: for line in f: yield from line.split() It'll read from a series of files and yield individual words (ignoring annoying little things like punctuation and hyphenation for the sake of simplicity). You are assuming that every yield-inside-with is a *single* yield. > This means the first "read_multiple" definition I presented will become > illegal and fail at compile-time. However, it is still legal to define a > generator inside a with block: > > def pass_file_chars(oldfunc): > with open('secretfile') as f: > contents = f.read() > @functools.wraps > def newfunc(*args, **kwargs): > for char in contents: > yield oldfunc(char, *args, **kwargs) > return newfunc > > This is probably a bad example, but I hope it still explains why it should > be legal to define generators in context managers - as long as the with > block serves its purpose correctly, everything else should still work > normally. I have no idea what this is supposed to be doing, nor why you're defining the function this way. Perhaps a better example will illustrate your point more clearly? > For those concerned about backwards compatibility: I believe that those who > attempt to yield inside a context manager will already discover that results > are undefined when doing so; this will simply make it more obvious that > suspending execution in a with block is not meant to happen, and convert > undefined behavior into a straight-up SyntaxError. The current results are most certainly not undefined, and you're attempting to fix something which is not a problem. If you really find yourself running into situations like this, program your linter to warn you when you do it. ChrisA From j.van.dorp at deonet.nl Wed Aug 8 02:51:23 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Wed, 8 Aug 2018 08:51:23 +0200 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: I don't think this is a major problem. In this case, the file will be closed when the generator is garbage collected. So you'd also have to leak the generator to actually get this problem. And if leaking generators won't harm your application, neither will leaking the occasional file handle. Also, I think "Yielding inside a with block, therefore, doesn't make sense and can only lead to obscure bugs." is somewhat of an overstatement. Also, the problem isn't the with block. The cause of the "issue" you describe is that a with statement is a try...finally in disguise. With the finally clause being guaranteed to be executed. IIRC, but I can't remember where, I remember a statement from guide referencing this, and calling it an issue that any fix will cause far more pain than the issue ever will. Or something to that point. 2018-08-08 8:32 GMT+02:00 Chris Angelico : > On Wed, Aug 8, 2018 at 4:14 PM, Ken Hilton wrote: >> This mostly springs off of a comment I saw in some thread. >> >> The point of a with statement is that it ensures that some resource will be >> disposed of, yes? For example, this: >> >> with open(filename) as f: >> contents = f.read() >> >> is better than this: >> >> contents = open(filename).read() >> >> because the former definitely closes the file while the latter relies on >> garbage collection? > > Technically, the 'with' statement ensures that the file will be closed > before the line of code following it is run. So in this example: > > with open(filename, "w") as f: > f.write(...) > os.rename(filename, target_filename) > > you have a guarantee that the file is closed prior to the rename call. > >> Now, let's take a look at the following scenario: >> >> def read_multiple(*filenames): >> for filename in filenames: >> with open(filename) as f: >> yield f.read() >> >> Can you spot the problem? The "with open(filename)" statement is supposed to >> ensure that the file object is disposed of properly. However, the "yield >> f.read()" statement suspends execution within the with block, so if this >> happened: >> >> for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): >> if contents == 'hello': >> break >> >> and the contents of "chunk2" were "hello" then the loop would exit, and >> "chunk2" would never be closed! Yielding inside a with block, therefore, >> doesn't make sense and can only lead to obscure bugs. > > This is only a problem if you consider it to be one. The value of the > 'with' statement is not destroyed; for example, you're capped at _one_ > open file (whereas without the context manager, it's entirely possible > for file-open in a loop to leak a large number of handles). > >> I believe all possible cases where one would yield inside a context manager >> can be covered by saving anything required from the context manager and then >> yielding the results outside. Therefore, I propose making a "yield" inside a >> with block become a SyntaxError. > > What about this: > > def read_words(*filenames): > for filename in filenames: > with open(filename) as f: > for line in f: > yield from line.split() > > It'll read from a series of files and yield individual words (ignoring > annoying little things like punctuation and hyphenation for the sake > of simplicity). You are assuming that every yield-inside-with is a > *single* yield. > >> This means the first "read_multiple" definition I presented will become >> illegal and fail at compile-time. However, it is still legal to define a >> generator inside a with block: >> >> def pass_file_chars(oldfunc): >> with open('secretfile') as f: >> contents = f.read() >> @functools.wraps >> def newfunc(*args, **kwargs): >> for char in contents: >> yield oldfunc(char, *args, **kwargs) >> return newfunc >> >> This is probably a bad example, but I hope it still explains why it should >> be legal to define generators in context managers - as long as the with >> block serves its purpose correctly, everything else should still work >> normally. > > I have no idea what this is supposed to be doing, nor why you're > defining the function this way. Perhaps a better example will > illustrate your point more clearly? > >> For those concerned about backwards compatibility: I believe that those who >> attempt to yield inside a context manager will already discover that results >> are undefined when doing so; this will simply make it more obvious that >> suspending execution in a with block is not meant to happen, and convert >> undefined behavior into a straight-up SyntaxError. > > The current results are most certainly not undefined, and you're > attempting to fix something which is not a problem. > > If you really find yourself running into situations like this, program > your linter to warn you when you do it. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ From barry at barrys-emacs.org Wed Aug 8 03:05:53 2018 From: barry at barrys-emacs.org (Barry Scott) Date: Wed, 08 Aug 2018 08:05:53 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: <3214525.yWTb9eZEfb@varric.chelsea.private> On Wednesday, 8 August 2018 07:14:47 BST Ken Hilton wrote: > Now, let's take a look at the following scenario: > > def read_multiple(*filenames): > for filename in filenames: > with open(filename) as f: > yield f.read() In this particular case you can fix the code: def read_multiple(*filenames): for filename in filenames: with open(filename) as f: result = f.read() yield result Of course if you used readline() and not read() the problem returns. But so long as you do not leak the generator the file will be closed immediately after the loop as the ref count of the generater hits 0. Barry From rosuav at gmail.com Wed Aug 8 03:31:45 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 8 Aug 2018 17:31:45 +1000 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: <3214525.yWTb9eZEfb@varric.chelsea.private> References: <3214525.yWTb9eZEfb@varric.chelsea.private> Message-ID: On Wed, Aug 8, 2018 at 5:05 PM, Barry Scott wrote: > But so long as you do not leak the generator the file will be closed > immediately after the loop as the ref count of the generater hits 0. Technically that's not guaranteed (since refcounts aren't a language feature), but if you're using this generator somewhere and want to be able to force it to close its files, all you have to do is close the generator. ChrisA From njs at pobox.com Wed Aug 8 03:48:40 2018 From: njs at pobox.com (Nathaniel Smith) Date: Wed, 8 Aug 2018 00:48:40 -0700 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: On Tue, Aug 7, 2018 at 11:14 PM, Ken Hilton wrote: > This mostly springs off of a comment I saw in some thread. > > The point of a with statement is that it ensures that some resource will be > disposed of, yes? For example, this: > > with open(filename) as f: > contents = f.read() > > is better than this: > > contents = open(filename).read() > > because the former definitely closes the file while the latter relies on > garbage collection? > > The point of a yield expression is to suspend execution. This is nice for > efficient looping because instead of having to hold all results in memory, > each result can be consumed immediately, yes? Therefore this: > > def five_to_one(): > for i in range(4): > yield 5 - i > > is better than this: > > def five_to_one(): > result = [] > for i in range(4): > result.append(5 - i) > return result > > because the former suspends execution of "five_to_one" while the latter > holds all five results in memory? > > Now, let's take a look at the following scenario: > > def read_multiple(*filenames): > for filename in filenames: > with open(filename) as f: > yield f.read() > > Can you spot the problem? The "with open(filename)" statement is supposed to > ensure that the file object is disposed of properly. However, the "yield > f.read()" statement suspends execution within the with block, so if this > happened: > > for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): > if contents == 'hello': > break > > and the contents of "chunk2" were "hello" then the loop would exit, and > "chunk2" would never be closed! Yielding inside a with block, therefore, > doesn't make sense and can only lead to obscure bugs. This is a real problem. (Well, technically the 'with' block's __exit__ function *will* eventually close the file, when the generator is garbage-collected ? see PEP 342 for details ? but this is not exactly satisfying, because the whole purpose of the 'with' block is to close the file *without* relying on the garbage collector.) Unfortunately, your proposal for solving it is a non-starter -- there are lots of cases where 'yield' inside a 'with' block is not only used, but is clearly the right thing to do. A notable one is when defining a next contextmanager in terms of a pre-existing contextmanager: @contextmanager def tempfile(): # This is an insecure way of making a temp file but good enough for an example tempname = pick_random_filename() with open(tempname, "w") as f: yield f Here are some links for previous discussions around these kinds of issues, none of which have really gone anywhere but might help you get a sense of the landscape of options: https://www.python.org/dev/peps/pep-0533/ https://www.python.org/dev/peps/pep-0521/ https://www.python.org/dev/peps/pep-0568/ https://github.com/python-trio/trio/issues/264 One small step that might be doable would be to start issuing ResourceWarning whenever a generator that was suspended inside a 'with' or 'try' block is GC'ed. -n -- Nathaniel J. Smith -- https://vorpus.org From turnbull.stephen.fw at u.tsukuba.ac.jp Wed Aug 8 04:13:49 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Wed, 8 Aug 2018 17:13:49 +0900 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: <23402.42557.839712.671414@turnbull.sk.tsukuba.ac.jp> Ken Hilton writes: > Can you spot the problem? The "with open(filename)" statement is supposed > to ensure that the file object is disposed of properly. However, the "yield > f.read()" statement suspends execution within the with block, so if this > happened: > > for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): > if contents == 'hello': > break > > and the contents of "chunk2" were "hello" then the loop would exit, and > "chunk2" would never be closed! Yielding inside a with block, therefore, > doesn't make sense and can only lead to obscure bugs. You have one example of a bad outcome. That hardly shows that *no* yield in a with block makes sense. On the contrary Chris A's suggestion that a function might yield multiple times within one context manager seems valid, although it might be bad practice. There's another possibility. Context managers have general initialize-operate-finalize semantics. True, they *often* have the simple form "return the value of *expr* bound to *var* at entry, clean up the contents of *var* at exit". But I find it easy to imagine that there are situations where the __enter__ method is complex and the __exit__ method is a no-op. In that case the problem you identify can't happen, and yielding inside such a context manager would be harmless. A third possibility is that the __exit__ method has semantics like the "else" of "while ... else", where the "normal" use case involves a break, but occasionally the input is exhausted, and some "default" action needs to be taken. I grant that I don't have examples of the latter (after all, writing context managers is a relatively rare activity, and the resource acquisition-and-release paradigm is prominent). But Chris's point about line-oriented generators seems both plausible and common. His analysis of why the risk is small also seems plausible, so I would say this problematic case (and it is problematic) is covered by the "consenting adults" principle. Steve From p.f.moore at gmail.com Wed Aug 8 05:08:33 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Wed, 8 Aug 2018 10:08:33 +0100 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <4cf674f3-a001-042d-3336-c1778f72fa50@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> <20180807231842.GE22431@ando.pearwood.info> <4cf674f3-a001-042d-3336-c1778f72fa50@narod.ru> Message-ID: On Wed, 8 Aug 2018 at 00:35, Victor Porton wrote: > > > But I see no reason why this has anything to do with the Python standard > > library. Can you explain why you want to distribute an experimental > > file format in the Python std lib? > > As I pointed out, I want this format to become common (standardized!) > for different IDEs and other development environment. This strikes me as *absolutely* something that should be promoted outside of the stdlib, as a 3rd party project, and once it's established as a commonly used and accepted standard, only then propose that the stdlib offer support for it (if that's even needed at that point). Trying to promote a standard by making it "official" and then encouraging tools to accept it "because it's the official standard" seems like it's doing things backwards, to me at least. Paul From barry at barrys-emacs.org Wed Aug 8 05:25:40 2018 From: barry at barrys-emacs.org (Barry Scott) Date: Wed, 08 Aug 2018 10:25:40 +0100 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> Message-ID: <18717214.l0sqFkdKtD@varric.chelsea.private> On Tuesday, 7 August 2018 22:57:51 BST Victor Porton wrote: > This is an idea of a new PEP. > > I propose to create a portable file format which will list command line > options to run Python scripts with dual purpose: At the moment I solve this problem with various solutions, depending on requirements. * use python unittest * add a test target to a makefile. * write a bash script to run the tests and diff output if required * on windows do the same with CMD scripts * use python to run python in a subprocess that run the tests. Given all these ways to solve the problem what extra are you looking for? Barry From oscar.j.benjamin at gmail.com Wed Aug 8 06:12:21 2018 From: oscar.j.benjamin at gmail.com (Oscar Benjamin) Date: Wed, 8 Aug 2018 11:12:21 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: On 8 August 2018 at 08:48, Nathaniel Smith wrote: > On Tue, Aug 7, 2018 at 11:14 PM, Ken Hilton wrote: >> >> Now, let's take a look at the following scenario: >> >> def read_multiple(*filenames): >> for filename in filenames: >> with open(filename) as f: >> yield f.read() >> >> Can you spot the problem? The "with open(filename)" statement is supposed to >> ensure that the file object is disposed of properly. However, the "yield >> f.read()" statement suspends execution within the with block, so if this >> happened: >> >> for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): >> if contents == 'hello': >> break >> >> and the contents of "chunk2" were "hello" then the loop would exit, and >> "chunk2" would never be closed! Yielding inside a with block, therefore, >> doesn't make sense and can only lead to obscure bugs. > > This is a real problem. (Well, technically the 'with' block's __exit__ > function *will* eventually close the file, when the generator is > garbage-collected ? see PEP 342 for details ? but this is not exactly > satisfying, because the whole purpose of the 'with' block is to close > the file *without* relying on the garbage collector.) PEP 342 guarantees that *if* a generator is garbage collected its .close() method will be called which would in turn trigger __exit__() for any active context managers in the generator. However PEP 342 does not guarantee that the generator would be garbage collected. As you noted in PEP 533: In Python implementations that do not use reference counting (e.g. PyPy, Jython), calls to __del__ may be arbitrarily delayed... However this statement does not go far enough. It is not guaranteed that __del__ will be called *at all* under other implementations. An example to test this is: $ cat gencm.py class CM: def __enter__(self): print("Entering") return self def __exit__(self, *args): print("Exiting") def generator(): with CM(): yield 1 yield 2 yield 3 g = generator() def f(): for x in g: break # Or return f() print("End of program") $ python3 gencm.py Entering End of program Exiting $ pypy --version Python 2.7.2 (1.8+dfsg-2, Feb 19 2012, 19:18:08) [PyPy 1.8.0 with GCC 4.6.2] $ pypy gencm.py Entering End of program (I don't actually have pypy to hand right now so I'm copying this from here: https://www.mail-archive.com/tutor at python.org/msg70961.html) What the above shows is that for this example: 1) Under CPython __exit__ is called by __del__ at process exit after every line of Python code has finished. 2) Under PyPy __exit__ was not called at any point That's not a bug in PyPy: Python the language makes very few guarantees about garbage collection. > Unfortunately, your proposal for solving it is a non-starter -- there > are lots of cases where 'yield' inside a 'with' block is not only > used, but is clearly the right thing to do. A notable one is when > defining a next contextmanager in terms of a pre-existing > contextmanager: > > @contextmanager > def tempfile(): > # This is an insecure way of making a temp file but good enough > for an example > tempname = pick_random_filename() > with open(tempname, "w") as f: > yield f This is the only example I can think of where yielding from a with statement is the right thing to do. Really this comes from the way that the contextmanager is abusing syntax though. It takes a bunch of strange machinery to make this work as it does: https://github.com/python/cpython/blob/3.7/Lib/contextlib.py#L116 > One small step that might be doable would be to start issuing > ResourceWarning whenever a generator that was suspended inside a > 'with' or 'try' block is GC'ed. This seems like a great idea to me. -- Oscar From porton at narod.ru Wed Aug 8 07:08:31 2018 From: porton at narod.ru (Victor Porton) Date: Wed, 8 Aug 2018 14:08:31 +0300 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <18717214.l0sqFkdKtD@varric.chelsea.private> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> <18717214.l0sqFkdKtD@varric.chelsea.private> Message-ID: <144a3729-1bd9-abf1-ede7-0e28aba20529@narod.ru> On 08/08/18 12:25, Barry Scott wrote: > On Tuesday, 7 August 2018 22:57:51 BST Victor Porton wrote: >> This is an idea of a new PEP. >> >> I propose to create a portable file format which will list command line >> options to run Python scripts with dual purpose: > At the moment I solve this problem with various solutions, depending on > requirements. > > * use python unittest > * add a test target to a makefile. > * write a bash script to run the tests and diff output if required > * on windows do the same with CMD scripts > * use python to run python in a subprocess that run the tests. > > Given all these ways to solve the problem what extra are you looking for? As I notes, I want to keep it in sync with PyCharm debug targets. We need a standard to make PyCharm and others to conform to it. From jfine2358 at gmail.com Wed Aug 8 07:20:35 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 8 Aug 2018 12:20:35 +0100 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <144a3729-1bd9-abf1-ede7-0e28aba20529@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> <18717214.l0sqFkdKtD@varric.chelsea.private> <144a3729-1bd9-abf1-ede7-0e28aba20529@narod.ru> Message-ID: Hi Victor Thank you for your contribution, regarding standards for Python tools. Here is my two cents worth. You wrote: > We need a standard to make PyCharm and others to conform to it. Things don't quite work that way, in the Python community. True, we have a Benevolent Dictator For Life (BDFL), but that's more an expression of respect for Guido, than a position of power. And anyway, he's on well-deserved vacation. For what you're suggesting, it's more that standards emerge through community use, and then are adopted as a PEP Python standard. Wherever possible, start first with an 'ad hoc' standard. You say your proposal enhances PyCharm. So ask PyCharm and its users set something up. As a first step, solve your own personal problem, and put it up somewhere where others can pick it up. Prove that the idea is good by establishing a group of users, starting perhaps with yourself. -- Jonathan From rhodri at kynesim.co.uk Wed Aug 8 08:28:06 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 8 Aug 2018 13:28:06 +0100 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> Message-ID: <98c5dcfa-dba7-5331-d530-a4cc898d5dc7@kynesim.co.uk> On 07/08/18 22:57, Victor Porton wrote: > This is an idea of a new PEP. > > I propose to create a portable file format which will list command line > options to run Python scripts with dual purpose: You are going about this the wrong way. If you want IDE-makers to use your putative file format, you are going to have to persuade them that it is useful. Demanding that they do something because you like it is not persuasive. (Personally I don't use IDEs, so you proposal is exactly no use to me. I don't think it's a suitable subject for a PEP.) -- Rhodri James *-* Kynesim Ltd From oscar.j.benjamin at gmail.com Wed Aug 8 08:32:10 2018 From: oscar.j.benjamin at gmail.com (Oscar Benjamin) Date: Wed, 8 Aug 2018 13:32:10 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: On 8 August 2018 at 07:32, Chris Angelico wrote: > On Wed, Aug 8, 2018 at 4:14 PM, Ken Hilton wrote: >> >> Now, let's take a look at the following scenario: >> >> def read_multiple(*filenames): >> for filename in filenames: >> with open(filename) as f: >> yield f.read() >> >> Can you spot the problem? The "with open(filename)" statement is supposed to >> ensure that the file object is disposed of properly. However, the "yield >> f.read()" statement suspends execution within the with block, so if this >> happened: >> >> for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): >> if contents == 'hello': >> break >> >> and the contents of "chunk2" were "hello" then the loop would exit, and >> "chunk2" would never be closed! Yielding inside a with block, therefore, >> doesn't make sense and can only lead to obscure bugs. > > This is only a problem if you consider it to be one. The value of the > 'with' statement is not destroyed; for example, you're capped at _one_ > open file (whereas without the context manager, it's entirely possible > for file-open in a loop to leak a large number of handles). Without the context manager you could write: def read_multiple(*filenames): for filename in filenames: f = open(filename) yield f.read() f.close() Which also only leaks one file descriptor. The point of the with statement is that this was considered unsatisfactory but when you yield from a with statement the advantage of with is lost. In fact if you're happy depending on garbage collection for cleanup then you can write this more conveniently: def read_multiple(*filenames): for filename in filenames: yield open(filename).read() Or even: for text in (open(filename).read() for filename in filenames): # stuff In any case saying that you only leak one file descriptor misses the point. The with statement can do many different things and it's purpose is to guarantee *without depending on garbage collection* that the __exit__ method will be called. Yielding from the with statement circumvents that guarantee. >> I believe all possible cases where one would yield inside a context manager >> can be covered by saving anything required from the context manager and then >> yielding the results outside. Therefore, I propose making a "yield" inside a >> with block become a SyntaxError. > > What about this: > > def read_words(*filenames): > for filename in filenames: > with open(filename) as f: > for line in f: > yield from line.split() > > It'll read from a series of files and yield individual words (ignoring > annoying little things like punctuation and hyphenation for the sake > of simplicity). You are assuming that every yield-inside-with is a > *single* yield. Actually the general way to solve this problem is to move all context managers out of iterators/generators. Instead of a helper generator what you really want in this situation is a helper context manager. I think the reason this isn't always used is just because it's a bit harder to write a context manager than a generator e.g.: from contextlib import contextmanager @contextmanager def open_cat_split(*filenames): f = None def get_words(): nonlocal f for filename in filenames: with open(filename) as f: for line in f: yield from line.split() else: f = None try: yield get_words() finally: if f is not None: f.close() Then you can do: with open_cat_split('file1.txt', 'file2.txt') as words: for word in words: print(word) I am not sure exactly what the best primitive would be to make this sort of thing easier. I most often see examples of this when someone wants to process multiple files concatenated. The stdlib fileinput module has a context manager that *almost* works: https://docs.python.org/3.7/library/fileinput.html#fileinput.input The corner case that isn't handled correctly by fileinput.input is that when the list of filenames is empty it uses sys.argv or stdin which is unlikely to be what someone wants in most of these situations. You could fix that with from contextlib import contextmanager import fileinput def open_cat(*filenames): if not filenames: @contextmanager def dummy(): yield () return dummy() else: return fileinput.input(filenames) And with that you could do: def map_split(strings): for string in strings: yield from string.split() with open_cat('file1.txt', 'file2.txt') as lines: for word in map_split(lines): print(word) Perhaps actually what is wanted is a more generic contextlib helper. I guess ExitStack is intended for this sort of thing but it's a bit unwieldy to use: https://docs.python.org/3.7/library/contextlib.html#contextlib.ExitStack We can use ExitStack to make something more convenient though: from contextlib import ExitStack, contextmanager @contextmanager def map_with(func, iterable): stack = ExitStack() def g(): for arg in iterable: stack.close() iterable_cm = func(arg) stack.push(iterable_cm) yield iterable_cm with stack: yield g() The you can do something like: def cat_split(files): for f in files: for line in f: yield from line.split() with map_with(open, ['file1.txt', 'file2.txt']) as files: for word in cat_split(files): print(word) -- Oscar From rhodri at kynesim.co.uk Wed Aug 8 08:35:56 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 8 Aug 2018 13:35:56 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> On 08/08/18 07:14, Ken Hilton wrote: > Now, let's take a look at the following scenario: > > def read_multiple(*filenames): > for filename in filenames: > with open(filename) as f: > yield f.read() > > Can you spot the problem? The "with open(filename)" statement is supposed > to ensure that the file object is disposed of properly. However, the "yield > f.read()" statement suspends execution within the with block, so if this > happened: > > for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): > if contents == 'hello': > break > > and the contents of "chunk2" were "hello" then the loop would exit, and > "chunk2" would never be closed! Yielding inside a with block, therefore, > doesn't make sense and can only lead to obscure bugs. An incomplete analysis and therefore an incorrect conclusion. Until the garbage collector comes out to play, read_multiple() will keep the file open, keep the tuple of filenames in memory and of course keep the environment of the generator around. That's all leakage caused by the _break_, and following your logic the obvious solution would be to ban breaks in loops that are reading from generators. But that wouldn't be helpful, obviously. -- Rhodri James *-* Kynesim Ltd From ronaldoussoren at mac.com Wed Aug 8 10:22:42 2018 From: ronaldoussoren at mac.com (Ronald Oussoren) Date: Wed, 08 Aug 2018 16:22:42 +0200 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> Message-ID: <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> > On 8 Aug 2018, at 14:35, Rhodri James wrote: > > On 08/08/18 07:14, Ken Hilton wrote: >> Now, let's take a look at the following scenario: >> def read_multiple(*filenames): >> for filename in filenames: >> with open(filename) as f: >> yield f.read() >> Can you spot the problem? The "with open(filename)" statement is supposed >> to ensure that the file object is disposed of properly. However, the "yield >> f.read()" statement suspends execution within the with block, so if this >> happened: >> for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): >> if contents == 'hello': >> break >> and the contents of "chunk2" were "hello" then the loop would exit, and >> "chunk2" would never be closed! Yielding inside a with block, therefore, >> doesn't make sense and can only lead to obscure bugs. > > An incomplete analysis and therefore an incorrect conclusion. Until the garbage collector comes out to play, read_multiple() will keep the file open, keep the tuple of filenames in memory and of course keep the environment of the generator around. That's all leakage caused by the _break_, and following your logic the obvious solution would be to ban breaks in loops that are reading from generators. But that wouldn't be helpful, obviously. It is also possible to fix the particular issue by using another with statement, that is use: with contextlib.closing(read_multiple(?)) as chunks: for contents in chunks: ? Automatically closing the generator at the end of the for loop would be nice, but getting the semantics right without breaking existing valid code is not trivial. Ronald From steve at pearwood.info Wed Aug 8 10:27:05 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 9 Aug 2018 00:27:05 +1000 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: <20180808142705.GJ22431@ando.pearwood.info> On Tue, Aug 07, 2018 at 11:31:35PM -0700, Elazar wrote: > Instead of disallowing code, this is a case for allowing with expressions: Only if you accept Ken's conclusion, that yielding inside a with statement is harmful (I don't). And if you do accept Ken's conclusion, then with-expressions don't fix the problem of yielding from inside a with statement. (Just because with-expressions are permitted doesn't mean that all the thousands of with-statements will be instantly re-written to use them.) -- Steve From rosuav at gmail.com Wed Aug 8 10:27:29 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 9 Aug 2018 00:27:29 +1000 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: Message-ID: On Wed, Aug 8, 2018 at 10:32 PM, Oscar Benjamin wrote: > Without the context manager you could write: > > def read_multiple(*filenames): > for filename in filenames: > f = open(filename) > yield f.read() > f.close() > > Which also only leaks one file descriptor. The point of the with > statement is that this was considered unsatisfactory but when you > yield from a with statement the advantage of with is lost. What if you remove yield from the picture? def read_multiple(callback, *filenames): for filename in filenames: f = open(filename) callback(f.read()) f.close() This is a classic approach as done in many languages that lack generators. The problem isn't that one file handle is being leaked until the next iteration; it's that an exception could permanently leak that file. Also of note is the "write-then-read" approach: def writer(fn): f = open(fn, "w") f.write(...) def reader(fn): f = open(fn) return f.read() writer("foo"); reader("foo") Without a guarantee that the file is closed *immediately* on losing its last reference, this is risky, because the write handle might still be open when the read handle is opened. The context manager guarantees both of these situations, and that doesn't change when a yield point is inserted, same as it doesn't change when a callback is inserted. The generator mechanism inverts the call stack a bit, but it isn't fundamentally different; at some point in read_multiple, it waits for some other code to do its stuff, then it continues. > In fact if you're happy depending on garbage collection for cleanup > then you can write this more conveniently: > > def read_multiple(*filenames): > for filename in filenames: > yield open(filename).read() And that's the whole point: you cannot be happy with garbage collection cleanup, because a non-refcounting Python implementation is not guaranteed to clean these up promptly. > In any case saying that you only leak one file descriptor misses the > point. The with statement can do many different things and it's > purpose is to guarantee *without depending on garbage collection* that > the __exit__ method will be called. Yielding from the with statement > circumvents that guarantee. Technically, it guarantees that __exit__ will be called before the next line of code after the 'with' block. It cannot actually guarantee that it will be called: with open(filename) as f: while True: pass print("Won't happen") print("Won't happen either") All that's guaranteed is that the second print call will not happen *before* the file is closed. > Actually the general way to solve this problem is to move all context > managers out of iterators/generators. Instead of a helper generator > what you really want in this situation is a helper context manager. I > think the reason this isn't always used is just because it's a bit > harder to write a context manager than a generator e.g.: > > from contextlib import contextmanager > > @contextmanager > def open_cat_split(*filenames): > f = None > def get_words(): > nonlocal f > for filename in filenames: > with open(filename) as f: > for line in f: > yield from line.split() > else: > f = None > try: > yield get_words() > finally: > if f is not None: > f.close() > > Then you can do: > > with open_cat_split('file1.txt', 'file2.txt') as words: > for word in words: > print(word) > So... you still have a yield (in this case a "yield from") inside your 'with' block, but you've wrapped it up in an extra layer, and done a manual try/finally. How is this different? Looking only at the lower half of the function, you have this: try: yield # <== the function stops here finally: # <== the function cleans up here This is exactly the same as the context manager situation. The finally block cannot be executed until the function resumes. What you have accomplished here is a level of nesting, and you can achieve that far more simply by just closing the context manager itself. Going right back to the original "problem code": def read_multiple(*filenames): for filename in filenames: with open(filename) as f: yield f.read() for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): if contents == 'hello': break We can keep the generator completely unchanged, and add a context manager to the loop, since we're not going to pump it completely: with contextlib.closing(read_multiple('chunk1', 'chunk2', 'chunk3')) as stuff: for contents in stuff: if contents == 'hello': break Now, when you exit the loop, the generator will be closed, which uses normal exception handling to clean up everything inside that function. The files are guaranteed to be closed as part of the closing of the generator. > Perhaps actually what is wanted is a more generic contextlib helper. I > guess ExitStack is intended for this sort of thing but it's a bit > unwieldy to use: > https://docs.python.org/3.7/library/contextlib.html#contextlib.ExitStack > > We can use ExitStack to make something more convenient though: > > from contextlib import ExitStack, contextmanager > > @contextmanager > def map_with(func, iterable): > stack = ExitStack() > def g(): > for arg in iterable: > stack.close() > iterable_cm = func(arg) > stack.push(iterable_cm) > yield iterable_cm > with stack: > yield g() > > The you can do something like: > > def cat_split(files): > for f in files: > for line in f: > yield from line.split() > > with map_with(open, ['file1.txt', 'file2.txt']) as files: > for word in cat_split(files): > print(word) Yeah, I think what you have here is close to what you want, but contextlib.closing() can cover it here. The key thing to remember is that generators can be closed. Use that functionality. It'll save you a lot of hassle :) ChrisA From oscar.j.benjamin at gmail.com Wed Aug 8 10:37:09 2018 From: oscar.j.benjamin at gmail.com (Oscar Benjamin) Date: Wed, 8 Aug 2018 15:37:09 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> Message-ID: On 8 August 2018 at 15:22, Ronald Oussoren via Python-ideas wrote: >> >> On 08/08/18 07:14, Ken Hilton wrote: >>> Now, let's take a look at the following scenario: >>> def read_multiple(*filenames): >>> for filename in filenames: >>> with open(filename) as f: >>> yield f.read() >>> Can you spot the problem? The "with open(filename)" statement is supposed >>> to ensure that the file object is disposed of properly. However, the "yield >>> f.read()" statement suspends execution within the with block, so if this >>> happened: >>> for contents in read_multiple('chunk1', 'chunk2', 'chunk3'): >>> if contents == 'hello': >>> break >>> and the contents of "chunk2" were "hello" then the loop would exit, and >>> "chunk2" would never be closed! Yielding inside a with block, therefore, >>> doesn't make sense and can only lead to obscure bugs. > > It is also possible to fix the particular issue by using another with statement, that is use: > > with contextlib.closing(read_multiple(?)) as chunks: > for contents in chunks: > ? That's a very good point Ronald. Having seen this a few times I can't think of any cases that wouldn't be solved by this. If a language change was wanted for this then perhaps it should be to do like file objects and add the __exit__ (calls close()) method to generator objects so that you can omit the closing and just do: with read_multiple(?) as chunks: for contents in chunks: ... -- Oscar From oscar.j.benjamin at gmail.com Wed Aug 8 11:55:55 2018 From: oscar.j.benjamin at gmail.com (Oscar Benjamin) Date: Wed, 8 Aug 2018 16:55:55 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> Message-ID: On 8 August 2018 at 15:37, Oscar Benjamin wrote: > On 8 August 2018 at 15:22, Ronald Oussoren via Python-ideas > wrote: >> >> It is also possible to fix the particular issue by using another with statement, that is use: >> >> with contextlib.closing(read_multiple(?)) as chunks: >> for contents in chunks: >> ? > > That's a very good point Ronald. Having seen this a few times I can't > think of any cases that wouldn't be solved by this. Thinking about this some more: closing() can ensure finalisation but it is still generally bad to yield from a with block. Some context managers are designed to temporarily alter global state between __enter__ and __exit__ - this can be very confusing if you use them around a yield block. As an example the localcontext context manager from the decimal module does this. So if you do something like def decimal_generator(): ... with decimal.localcontext() as ctx: ctx.prec = 4 # Use 4 digits for calculations temporarily yield x + y yield y + z with decimal.localcontext() as ctx: ctx.prec = 10 # Use 10 digits for calculations temporarily total = decimal.Decimal(0) for item in decimal_generator(): total += item Here the line total += item will end up using 4 digit arithmetic rather than 10. That's because the yield allows the "local" context to leak out. The fix for that is something like: def decimal_generator(): ... ctx = decimal.localcontext() ctx.prec = 4 # Use 4 digits for calculations temporarily with ctx: val = x + y yield val with ctx: val = y + z yield val I still think that this is a good idea though: > If a language change was wanted for this then perhaps it should be to > do like file objects and add the __exit__ (calls close()) method to > generator objects so that you can omit the closing and just do: > > with read_multiple(?) as chunks: > for contents in chunks: > ... -- Oscar From __peter__ at web.de Wed Aug 8 12:13:41 2018 From: __peter__ at web.de (Peter Otten) Date: Wed, 08 Aug 2018 18:13:41 +0200 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> Message-ID: Ronald Oussoren via Python-ideas wrote: > It is also possible to fix the particular issue by using another with > statement, that is use: > > with contextlib.closing(read_multiple(?)) as chunks: > for contents in chunks: > ? > > Automatically closing the generator at the end of the for loop would be > nice, but getting the semantics right without breaking existing valid code > is not trivial. How about providing a decorator that turns the generator into a context manager def close_gen(f): @contextmanager @wraps(f) def g(*args, **kw): with closing(f(*args, **kw)) as h: yield h return g @close_gen def read_multiple(...): ... ? A more radical approach would be to add __enter__ and __exit__ methods so that for every generator function f with f() as g: pass would call g.close() From rhodri at kynesim.co.uk Wed Aug 8 12:16:46 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 8 Aug 2018 17:16:46 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> Message-ID: <9fe3d453-6c77-6fad-611c-16d036571885@kynesim.co.uk> On 08/08/18 16:55, Oscar Benjamin wrote: > Thinking about this some more: closing() can ensure finalisation but > it is still generally bad to yield from a with block. Some context > managers are designed to temporarily alter global state between > __enter__ and __exit__ - this can be very confusing if you use them > around a yield block. Yes, but those sorts of context managers need to be used with care in all sorts of circumstances. Fiddling with global state is always fraught. -- Rhodri James *-* Kynesim Ltd From p.f.moore at gmail.com Wed Aug 8 12:28:01 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Wed, 8 Aug 2018 17:28:01 +0100 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> Message-ID: On Wed, 8 Aug 2018 at 16:58, Oscar Benjamin wrote: > Thinking about this some more: closing() can ensure finalisation but > it is still generally bad to yield from a with block. Some context > managers are designed to temporarily alter global state between > __enter__ and __exit__ - this can be very confusing if you use them > around a yield block. Surely that's *precisely* what PEP 567 (Context Variables) was designed to address? Paul From yselivanov.ml at gmail.com Wed Aug 8 13:41:42 2018 From: yselivanov.ml at gmail.com (Yury Selivanov) Date: Wed, 8 Aug 2018 13:41:42 -0400 Subject: [Python-ideas] Make "yield" inside a with statement a SyntaxError In-Reply-To: References: <3de9b727-bd6c-bb6d-6d54-5fb7767a2878@kynesim.co.uk> <1A6F316D-8DCE-4F72-82FB-006248E9C378@mac.com> Message-ID: On Wed, Aug 8, 2018 at 12:28 PM Paul Moore wrote: > > On Wed, 8 Aug 2018 at 16:58, Oscar Benjamin wrote: > > Thinking about this some more: closing() can ensure finalisation but > > it is still generally bad to yield from a with block. Some context > > managers are designed to temporarily alter global state between > > __enter__ and __exit__ - this can be very confusing if you use them > > around a yield block. > > Surely that's *precisely* what PEP 567 (Context Variables) was > designed to address? To be even more precise, PEP 550 was designed to solve state handling problem for both "await" (coroutines) and "yield" (generators). It was rejected in favour of a more simplistic PEP 567 that solves it only for coroutines. PEP 568 was later drafted by Nathaniel. It applies PEP 550's ideas to 567 API/design to allow generators to have execution context too in Python 3.8 or 3.9. The fate of PEP 568 is still undecided. Yury From tjol at tjol.eu Wed Aug 8 19:15:28 2018 From: tjol at tjol.eu (Thomas Jollans) Date: Thu, 9 Aug 2018 01:15:28 +0200 Subject: [Python-ideas] Is this PEP-able? "with" statement inside genexps / list comprehensions In-Reply-To: <20180730191517.GA27867@zero.localdomain> References: <20180730191517.GA27867@zero.localdomain> Message-ID: On 30/07/18 21:15, Rudy Matela wrote: > Hello, > > Do you think it would be nice to allow with statements inside genexps or > list comprehensions? The functions __enter__ and __exit__ would be > automatically called as iterables are traversed. I am thinking of > drafting a PEP about this. Examples: > > > This > > g = (f.read() for fn in filenames with open(fn) as f) > > would be equivalent to the following use of a generator function: > > def __gen(): > for fn in filenames: > with open(fn) as f: > yield f.read() > g = __gen() To sail around Oscar's concern, this should rather be def __gen(): for fn in filenames: with open(fn) as f: _v = f.read() yield _v But in this case I think it'd be clearer to make it an expression rather than a generator expression term: g = (f.read() with open(fn) as f for fn in filenames) where _ = f.read() with open(fn) as f is equivalent to with open(fn) as f: _ = f.read() Currently possibly (if silly) alternative: from functools import wraps class with_one_use: def __init__(self, context): self.__context = context def __getattr__(self, name): exc1 = False obj = self.__context.__enter__() try: temp = getattr(obj, name) except: exc1 = True if not self.__context.__exit__(*sys.exc_info()): raise else: if callable(temp): @wraps(temp) def f(*args, **kwargs): exc2 = False try: return temp(*args, **kwargs) except: exc2 = True if not self.__context.__exit__(*sys.exc_info()): raise finally: if not exc2: self.__context.__exit__(None, None, None) exc1 = True return f else: return temp finally: if not exc1: self.__context.__exit__(None, None, None) g = (with_one_use(open(fn)).read() for fn in filenames) -- Thomas > > > This > > list = [f.read() for fn in filenames with open(fn) as f] > > would be equivalent to the following: > > list = [] > for fn in filenames: > with open(fn) as f: > list.append(f.read()) > > -- > Rudy > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > From barry at barrys-emacs.org Thu Aug 9 03:32:40 2018 From: barry at barrys-emacs.org (Barry) Date: Thu, 9 Aug 2018 08:32:40 +0100 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: <144a3729-1bd9-abf1-ede7-0e28aba20529@narod.ru> References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> <18717214.l0sqFkdKtD@varric.chelsea.private> <144a3729-1bd9-abf1-ede7-0e28aba20529@narod.ru> Message-ID: <16F8F9DE-8355-418E-AD88-A219B06BCDFE@barrys-emacs.org> > On 8 Aug 2018, at 12:08, Victor Porton wrote: > >> On 08/08/18 12:25, Barry Scott wrote: >>> On Tuesday, 7 August 2018 22:57:51 BST Victor Porton wrote: >>> This is an idea of a new PEP. >>> >>> I propose to create a portable file format which will list command line >>> options to run Python scripts with dual purpose: >> At the moment I solve this problem with various solutions, depending on >> requirements. >> >> * use python unittest >> * add a test target to a makefile. >> * write a bash script to run the tests and diff output if required >> * on windows do the same with CMD scripts >> * use python to run python in a subprocess that run the tests. >> >> Given all these ways to solve the problem what extra are you looking for? > > As I notes, I want to keep it in sync with PyCharm debug targets. Then work with pycharm to get what you need. > > We need a standard to make PyCharm and others to conform to it. No you need to convince pycharm it is worth implementing. Barry > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > From nicholas.chammas at gmail.com Thu Aug 9 09:59:27 2018 From: nicholas.chammas at gmail.com (Nicholas Chammas) Date: Thu, 9 Aug 2018 09:59:27 -0400 Subject: [Python-ideas] File format for automatic and manual tests In-Reply-To: References: <40b7790e-79ca-77fd-cc22-a297d25f0d28@narod.ru> <20180807231842.GE22431@ando.pearwood.info> <4cf674f3-a001-042d-3336-c1778f72fa50@narod.ru> Message-ID: On Wed, Aug 8, 2018 at 5:09 AM Paul Moore wrote: > This strikes me as *absolutely* something that should be promoted > outside of the stdlib, as a 3rd party project, and once it's > established as a commonly used and accepted standard, only then > propose that the stdlib offer support for it (if that's even needed at > that point). > > Trying to promote a standard by making it "official" and then > encouraging tools to accept it "because it's the official standard" > seems like it's doing things backwards, to me at least. > +1 -------------- next part -------------- An HTML attachment was scrubbed... URL: From patrick at shimi.co.uk Thu Aug 9 10:56:29 2018 From: patrick at shimi.co.uk (Patrick Morris) Date: Thu, 9 Aug 2018 15:56:29 +0100 Subject: [Python-ideas] Python certification Message-ID: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> Hi all I know this might be a contentious question but ... Does anyone know of any PSF approved training or certifications for Python developers? There is this 10 year old page https://wiki.python.org/psf/Certification%20Proposal but I dont see any evidence that this was ever progressed past the discussion of it. Assuming there is no such thing as PSF approval, are there any certifications / training course that people would recommend, or would recognise for someone seeking employment with them? thanks Patrick [cross posted from python-uk list] From phd at phdru.name Thu Aug 9 12:12:45 2018 From: phd at phdru.name (Oleg Broytman) Date: Thu, 9 Aug 2018 18:12:45 +0200 Subject: [Python-ideas] Python certification In-Reply-To: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> Message-ID: <20180809161245.w7mxxgwsddocowrd@phdru.name> Hi! On Thu, Aug 09, 2018 at 03:56:29PM +0100, Patrick Morris wrote: > Hi all > > I know this might be a contentious question but ... > > Does anyone know of any PSF approved training or certifications for Python > developers? > > There is this 10 year old page > https://wiki.python.org/psf/Certification%20Proposal but I dont see any > evidence that this was ever progressed past the discussion of it. Why not ask PSF? See contacts at https://www.python.org/psf/ > Assuming there is no such thing as PSF approval, are there any > certifications / training course that people would recommend, or would > recognise for someone seeking employment with them? I think the question is better suited for comp.lang.python newsgroup/general mailing list. The python-ideas list is for discussing more speculative design ideas of Python the language and the implementation. > thanks > > Patrick Oleg. -- Oleg Broytman https://phdru.name/ phd at phdru.name Programmers don't die, they just GOSUB without RETURN. From jfine2358 at gmail.com Thu Aug 9 12:42:58 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 9 Aug 2018 17:42:58 +0100 Subject: [Python-ideas] Python certification In-Reply-To: <20180809161245.w7mxxgwsddocowrd@phdru.name> References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> Message-ID: Hi Patrick and Oleg Thank you, respectively, for a good question and a helpful response. Patrick asks: > Does anyone know of any PSF approved training or certifications for Python developers? Oleg writes: > The python-ideas list is for discussing more speculative design ideas of Python the language and the implementation. According to https://mail.python.org/mailman/listinfo/python-ideas > This list is to contain discussion of speculative language ideas for Python for possible inclusion into the language. Python's excellent documentation, including https://docs.python.org/3/tutorial/, is in my opinion part of the language. I'm in favour of discussing Patrick's question here, so that we can perhaps develop something of value that can be added to the tutorial. Is there a forum, better than python-ideas, for discussing speculative ideas for improving Python's documentation? -- Jonathan From desmoulinmichel at gmail.com Thu Aug 9 12:59:20 2018 From: desmoulinmichel at gmail.com (Michel Desmoulin) Date: Thu, 9 Aug 2018 18:59:20 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: I'd rather have functools.partial() to be added as a new method on function objects. > > fromfunctools importpartial > > > def add(x:int,y:int)->int: > returnx +y > > > add_2 = partial(add,2) > Would become: add_2 = add.partial(2) Nothing to change on the parser, no obscure syntax for future readers, and we can get the opportunity of rewriting partial() in C as right now it is amazingly way, way slower than a lambda. From phd at phdru.name Thu Aug 9 13:00:19 2018 From: phd at phdru.name (Oleg Broytman) Date: Thu, 9 Aug 2018 19:00:19 +0200 Subject: [Python-ideas] Python certification In-Reply-To: References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> Message-ID: <20180809170019.c24577irbuajvguw@phdru.name> On Thu, Aug 09, 2018 at 05:42:58PM +0100, Jonathan Fine wrote: > Python's excellent documentation, including > https://docs.python.org/3/tutorial/, is in my opinion part of the > language. I'm in favour of discussing Patrick's question here, so that > we can perhaps develop something of value that can be added to the > tutorial. > > Is there a forum, better than python-ideas, for discussing speculative > ideas for improving Python's documentation? In what way certification programs are related to documentation, especially to the tutorial? > -- > Jonathan Oleg. -- Oleg Broytman https://phdru.name/ phd at phdru.name Programmers don't die, they just GOSUB without RETURN. From desmoulinmichel at gmail.com Thu Aug 9 13:04:22 2018 From: desmoulinmichel at gmail.com (Michel Desmoulin) Date: Thu, 9 Aug 2018 19:04:22 +0200 Subject: [Python-ideas] Revisiting dedicated overloadable boolean operators In-Reply-To: References: Message-ID: Adding one operator is hard in Python. Adding 4 operators, just for the sake of a bit of syntaxic suggar for DSL based projects is never going to fly. And I say that as a long time SQLA user. Le 03/08/2018 ? 19:46, Todd a ?crit?: > Coming back to the previous discussion about a new set of overloadable > boolean operators [1], I have an idea for overloadable boolean operators > that I think might work.? The idea would be to define four new operators > that take two inputs and return a boolean result based on them.? This > behavior can be overridden in appropriate dunder methods.? These > operators would have similar precedence to existing logical operators.? > The operators would be: > > bNOT - boolean "not" > bAND - boolean "and" > bOR - boolean "or" > bXOR - boolean "xor" > > With corresponding dunder methods: > > __bNOT__ and _rbNOT__ (or __r_bNOT__) > __bAND__ and _rbAND__ (or __r_bAND__) > __bOR__ and _rbOR__ (or __r_bOR__) > __bXOR__ and _rbXOR__ (or __r_bXOR__) > > The basic idea is that the "b" is short for "boolean", and we change the > rest of the operator to upercase to avoid confusions with the existing > operators.? I think these operators would be preferably to the proposals > so far (see [1] again) for a few reasons: From mistersheik at gmail.com Thu Aug 9 13:14:03 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 9 Aug 2018 13:14:03 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: That's a nicer solution to me. On Thu, Aug 9, 2018 at 1:00 PM Michel Desmoulin wrote: > I'd rather have functools.partial() to be added as a new method on > function objects. > > > > > fromfunctools importpartial > > > > > > def add(x:int,y:int)->int: > > returnx +y > > > > > > add_2 = partial(add,2) > > > > Would become: > > add_2 = add.partial(2) > > Nothing to change on the parser, no obscure syntax for future readers, > and we can get the opportunity of rewriting partial() in C as right now > it is amazingly way, way slower than a lambda. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 9 13:40:23 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 9 Aug 2018 18:40:23 +0100 Subject: [Python-ideas] Python certification In-Reply-To: <20180809170019.c24577irbuajvguw@phdru.name> References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> <20180809170019.c24577irbuajvguw@phdru.name> Message-ID: Hi Oleg You wrote > In what way certification programs are related to documentation, > especially to the tutorial? One way is through syllabus. Necessarily, a certification via exam requires a syllabus (or a course of study). There is, implicitly, a syllabus in https://docs.python.org/3/tutorial/. Here's a couple of Python syllabuses (the first proprietary, the second perhaps open) https://www.microsoft.com/en-us/learning/exam-98-381.aspx https://pythoninstitute.org/pcap-exam-syllabus/ I think it would help, to compare such syllabuses to the one implicit in the Python Tutorial. It may be, of course, that there's somewhere better than python-ideas for having the related discussion. I hope this is enough to persuade you that this topic is appropriate for python-ideas. Of course, if you know a better forum for this, that would be welcome. -- Jonathan From abedillon at gmail.com Thu Aug 9 14:32:00 2018 From: abedillon at gmail.com (Abe Dillon) Date: Thu, 9 Aug 2018 13:32:00 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: I'd like to push for the less jargon-y `func.given()` version if this gains traction. Not only is it shorter, it's a much more common term with a clear meaning. Words like 'partial', 'curry', 'lambda', and 'closure' are fine for text books, published papers, and technical discussion, but I think they would (or do in the case of 'lambda') harm Python. I know the correct term for the 'if-else' expression is a 'ternary' expression, but that doesn't mean Python should have used the word 'ternary' in the syntax. On Thu, Aug 9, 2018 at 12:14 PM, Neil Girdhar wrote: > That's a nicer solution to me. > > On Thu, Aug 9, 2018 at 1:00 PM Michel Desmoulin > wrote: > >> I'd rather have functools.partial() to be added as a new method on >> function objects. >> >> > >> > fromfunctools importpartial >> > >> > >> > def add(x:int,y:int)->int: >> > returnx +y >> > >> > >> > add_2 = partial(add,2) >> > >> >> Would become: >> >> add_2 = add.partial(2) >> >> Nothing to change on the parser, no obscure syntax for future readers, >> and we can get the opportunity of rewriting partial() in C as right now >> it is amazingly way, way slower than a lambda. >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> -- >> >> --- >> You received this message because you are subscribed to a topic in the >> Google Groups "python-ideas" group. >> To unsubscribe from this topic, visit https://groups.google.com/d/ >> topic/python-ideas/jOMinivFCcQ/unsubscribe. >> To unsubscribe from this group and all its topics, send an email to >> python-ideas+unsubscribe at googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Thu Aug 9 18:46:18 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 9 Aug 2018 18:46:18 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: I prefer partial since many programmers studied computer science, and also it makes the concepts easier to google. Anyway, I don't actually want either a partial member nor new syntax for this, but if I had to choose, I'd choose no new syntax. On Thu, Aug 9, 2018 at 2:32 PM Abe Dillon wrote: > I'd like to push for the less jargon-y `func.given()` version if this > gains traction. Not only is it shorter, it's a much more common term with a > clear meaning. Words like 'partial', 'curry', 'lambda', and 'closure' are > fine for text books, published papers, and technical discussion, but I > think they would (or do in the case of 'lambda') harm Python. I know the > correct term for the 'if-else' expression is a 'ternary' expression, but > that doesn't mean Python should have used the word 'ternary' in the syntax. > > On Thu, Aug 9, 2018 at 12:14 PM, Neil Girdhar > wrote: > >> That's a nicer solution to me. >> >> On Thu, Aug 9, 2018 at 1:00 PM Michel Desmoulin < >> desmoulinmichel at gmail.com> wrote: >> >>> I'd rather have functools.partial() to be added as a new method on >>> function objects. >>> >>> > >>> > fromfunctools importpartial >>> > >>> > >>> > def add(x:int,y:int)->int: >>> > returnx +y >>> > >>> > >>> > add_2 = partial(add,2) >>> > >>> >>> Would become: >>> >>> add_2 = add.partial(2) >>> >>> Nothing to change on the parser, no obscure syntax for future readers, >>> and we can get the opportunity of rewriting partial() in C as right now >>> it is amazingly way, way slower than a lambda. >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >>> -- >>> >>> --- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "python-ideas" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. >>> To unsubscribe from this group and all its topics, send an email to >>> python-ideas+unsubscribe at googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Thu Aug 9 19:30:53 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Thu, 9 Aug 2018 16:30:53 -0700 Subject: [Python-ideas] Python certification In-Reply-To: References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> <20180809170019.c24577irbuajvguw@phdru.name> Message-ID: On Thu, Aug 9, 2018 at 10:40 AM, Jonathan Fine wrote: > There is, implicitly, a > syllabus in https://docs.python.org/3/tutorial/. > The tutorial, is, well, a tutorial, it is by no means a complete course of study. So no, I don't think it's an appropriate place to start to develop a certification. Here's a couple of Python syllabuses (the first proprietary, the > second perhaps open) > > https://www.microsoft.com/en-us/learning/exam-98-381.aspx > https://pythoninstitute.org/pcap-exam-syllabus/ I am developing this: https://uwpce-pythoncert.github.io/PythonCertDevel/index.html Which we use for a "Certificate" program, which is NOT a "certification". But I like to think we've put together a pretty good curriculum. I hope this is enough to persuade you that this topic is appropriate > for python-ideas. Of course, if you know a better forum for this, that > would be welcome. This really isn't the right forum -- maybe the tutor list? https://mail.python.org/mailman/listinfo/tutor But if you think you want to develop a certification, you need to find like-minded people to do it. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Thu Aug 9 20:05:15 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 10 Aug 2018 10:05:15 +1000 Subject: [Python-ideas] Python certification In-Reply-To: References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> <20180809170019.c24577irbuajvguw@phdru.name> Message-ID: <20180810000514.GL22431@ando.pearwood.info> On Thu, Aug 09, 2018 at 06:40:23PM +0100, Jonathan Fine wrote: > Hi Oleg > > You wrote > > > In what way certification programs are related to documentation, > > especially to the tutorial? > > One way is through syllabus. Necessarily, a certification via exam > requires a syllabus (or a course of study). There is, implicitly, a > syllabus in https://docs.python.org/3/tutorial/. I think that Oleg asked the wrong question. With sufficient imagination, it is always possible to draw *some* kind of relationship or connection between virtually any two concepts, "six degrees of separation" kind of thing. A better question is, how are questions about third-party certification programmes on-topic to this mailing list? "This list is to contain discussion of speculative language ideas for Python for possible inclusion into the language." - https://mail.python.org/mailman/listinfo/python-ideas Third-party certification is not a speculative language idea for Python. It's not even an idea for documentation about existing language features. Third-party trainers and teachers may, or may not, mine the standard Python docs and tutorial for concepts, but regardless of whether they do or not, I think that discussions about third-party certification programmes are off-topic and should be taken to either a specialised mailing list or SIG (if there is one): https://mail.python.org/mailman/listinfo or to Python-List. -- Steve From wes.turner at gmail.com Thu Aug 9 20:11:25 2018 From: wes.turner at gmail.com (Wes Turner) Date: Thu, 9 Aug 2018 20:11:25 -0400 Subject: [Python-ideas] Python certification In-Reply-To: <20180810000514.GL22431@ando.pearwood.info> References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> <20180809170019.c24577irbuajvguw@phdru.name> <20180810000514.GL22431@ando.pearwood.info> Message-ID: edu-sig may be a good list for such a discussion; though you may find more information on Python lessons aligned with CS/Science curriculum standards than professional certification. https://mail.python.org/mailman/listinfo/edu-sig > This list is for discussion of Python in education, however (at the request of a majority of readers) explicitly excluding educational politics. https://www.google.com/search?q=python+certification+psf - Wiki content from 2008 - https://www.quora.com/Is-there-any-certification-for-a-Python-programmer On Thursday, August 9, 2018, Steven D'Aprano wrote: > On Thu, Aug 09, 2018 at 06:40:23PM +0100, Jonathan Fine wrote: > > Hi Oleg > > > > You wrote > > > > > In what way certification programs are related to documentation, > > > especially to the tutorial? > > > > One way is through syllabus. Necessarily, a certification via exam > > requires a syllabus (or a course of study). There is, implicitly, a > > syllabus in https://docs.python.org/3/tutorial/. > > I think that Oleg asked the wrong question. With sufficient imagination, > it is always possible to draw *some* kind of relationship or connection > between virtually any two concepts, "six degrees of separation" kind of > thing. > > A better question is, how are questions about third-party certification > programmes on-topic to this mailing list? > > "This list is to contain discussion of speculative language ideas > for Python for possible inclusion into the language." > - https://mail.python.org/mailman/listinfo/python-ideas > > Third-party certification is not a speculative language idea for Python. > It's not even an idea for documentation about existing language > features. Third-party trainers and teachers may, or may not, mine the > standard Python docs and tutorial for concepts, but regardless of > whether they do or not, I think that discussions about third-party > certification programmes are off-topic and should be taken to either a > specialised mailing list or SIG (if there is one): > > https://mail.python.org/mailman/listinfo > > or to Python-List. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From j.van.dorp at deonet.nl Fri Aug 10 02:49:43 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Fri, 10 Aug 2018 08:49:43 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: I actually really like the method-on-function-object syntax. +1, for what it's worth from someone like me. 2018-08-10 0:46 GMT+02:00 Neil Girdhar : > I prefer partial since many programmers studied computer science, and also > it makes the concepts easier to google. > > Anyway, I don't actually want either a partial member nor new syntax for > this, but if I had to choose, I'd choose no new syntax. > > On Thu, Aug 9, 2018 at 2:32 PM Abe Dillon wrote: >> >> I'd like to push for the less jargon-y `func.given()` version if this >> gains traction. Not only is it shorter, it's a much more common term with a >> clear meaning. Words like 'partial', 'curry', 'lambda', and 'closure' are >> fine for text books, published papers, and technical discussion, but I think >> they would (or do in the case of 'lambda') harm Python. I know the correct >> term for the 'if-else' expression is a 'ternary' expression, but that >> doesn't mean Python should have used the word 'ternary' in the syntax. >> >> On Thu, Aug 9, 2018 at 12:14 PM, Neil Girdhar >> wrote: >>> >>> That's a nicer solution to me. >>> >>> On Thu, Aug 9, 2018 at 1:00 PM Michel Desmoulin >>> wrote: >>>> >>>> I'd rather have functools.partial() to be added as a new method on >>>> function objects. >>>> >>>> > >>>> > fromfunctools importpartial >>>> > >>>> > >>>> > def add(x:int,y:int)->int: >>>> > returnx +y >>>> > >>>> > >>>> > add_2 = partial(add,2) >>>> > >>>> >>>> Would become: >>>> >>>> add_2 = add.partial(2) >>>> >>>> Nothing to change on the parser, no obscure syntax for future readers, >>>> and we can get the opportunity of rewriting partial() in C as right now >>>> it is amazingly way, way slower than a lambda. >>>> _______________________________________________ >>>> Python-ideas mailing list >>>> Python-ideas at python.org >>>> https://mail.python.org/mailman/listinfo/python-ideas >>>> Code of Conduct: http://python.org/psf/codeofconduct/ >>>> >>>> -- >>>> >>>> --- >>>> You received this message because you are subscribed to a topic in the >>>> Google Groups "python-ideas" group. >>>> To unsubscribe from this topic, visit >>>> https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. >>>> To unsubscribe from this group and all its topics, send an email to >>>> python-ideas+unsubscribe at googlegroups.com. >>>> For more options, visit https://groups.google.com/d/optout. >>> >>> >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > From steve at pearwood.info Fri Aug 10 03:09:59 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 10 Aug 2018 17:09:59 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: <20180810070958.GM22431@ando.pearwood.info> On Thu, Aug 09, 2018 at 01:32:00PM -0500, Abe Dillon wrote: > I'd like to push for the less jargon-y `func.given()` version if this gains > traction. Not only is it shorter, it's a much more common term with a clear > meaning. It's a clear, *generic* meaning that doesn't have any association with partial application. https://www.google.com/search?q=function+given We'd be trying to create that association from scratch. > Words like 'partial', 'curry', 'lambda', and 'closure' are fine > for text books, published papers, and technical discussion, And programmers. Programming is a technical skill with its own jargon. Classes, inheritence, exceptions, trampolining, processes, threads, protocols, imports, decorator, builders... we are happy with all those, why should we fear partial and lambda? > but I think > they would (or do in the case of 'lambda') harm Python. That's an extreme overreaction. Do you mean to imply that there are people who looked at Python, loved the language, but decided to use something else because they didn't like the choice of the keyword "lambda"? If not, in what way is Python harmed? Would it be faster if the keyword was "function", or use less memory, or more expressive? Remember that to millions of programmers in the world, "function" is just as much an obscure foreign piece of jargon they have to memorise as "lambda" is to English-speakers. -- Steve From patrick at shimi.co.uk Fri Aug 10 03:26:57 2018 From: patrick at shimi.co.uk (Patrick Morris) Date: Fri, 10 Aug 2018 08:26:57 +0100 Subject: [Python-ideas] Python certification In-Reply-To: References: <7876fc8f-9e14-2cc7-8d83-c227c8f06b48@shimi.co.uk> <20180809161245.w7mxxgwsddocowrd@phdru.name> <20180809170019.c24577irbuajvguw@phdru.name> <20180810000514.GL22431@ando.pearwood.info> Message-ID: <951b0cc5-6646-eb1a-202e-cf082c554654@shimi.co.uk> Hi all Thanks to all for feedback on the question, and I will follow up with it on the other channels suggested! thanks Patrick On 10/08/2018 01:11, Wes Turner wrote: > edu-sig may be a good list for such a discussion; though you may find > more information on Python lessons aligned with CS/Science curriculum > standards than professional certification. > https://mail.python.org/mailman/listinfo/edu-sig > > > This list is for discussion of Python in education, however (at the > request of a majority of readers) explicitly excluding educational > politics. > > https://www.google.com/search?q=python+certification+psf > > - Wiki content from 2008 > - https://www.quora.com/Is-there-any-certification-for-a-Python-programmer > > > On Thursday, August 9, 2018, Steven D'Aprano > wrote: > > On Thu, Aug 09, 2018 at 06:40:23PM +0100, Jonathan Fine wrote: > > Hi Oleg > > > > You wrote > > > > > In what way certification programs are related to > documentation, > > > especially to the tutorial? > > > > One way is through syllabus. Necessarily, a certification via exam > > requires a syllabus (or a course of study). There is, implicitly, a > > syllabus in https://docs.python.org/3/tutorial/ > . > > I think that Oleg asked the wrong question. With sufficient > imagination, > it is always possible to draw *some* kind of relationship or > connection > between virtually any two concepts, "six degrees of separation" > kind of > thing. > > A better question is, how are questions about third-party > certification > programmes on-topic to this mailing list? > > "This list is to contain discussion of speculative language ideas > for Python for possible inclusion into the language." > - https://mail.python.org/mailman/listinfo/python-ideas > > > Third-party certification is not a speculative language idea for > Python. > It's not even an idea for documentation about existing language > features. Third-party trainers and teachers may, or may not, mine the > standard Python docs and tutorial for concepts, but regardless of > whether they do or not, I think that discussions about third-party > certification programmes are off-topic and should be taken to > either a > specialised mailing list or SIG (if there is one): > > https://mail.python.org/mailman/listinfo > > > or to Python-List. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 10 18:20:25 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 10 Aug 2018 17:20:25 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <20180810070958.GM22431@ando.pearwood.info> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> Message-ID: [Neil Girdhar] > I prefer partial since many programmers studied computer science Many did not. I studied electrical engineering and wouldn't have been able to tell you what the word 'partial' meant four years ago even though I've been programming in one form or another since the late nineties. Many programmers are scientists, engineers, financial analysts, etc. I'm pretty sure I know what a closure is or what currying is, but if you put me on the spot, I'd probably turn to Wikipedia to make sure I don't screw up the definition. [Neil Girdhar] > It makes the concepts easier to google. That can be an important criteria, but it can also be a red-herring. If an implementation is clear enough, few people would have to google it. If, however, you use obscure enough words like "lambda", people will google it every day and still find it confusing. The ternary expression is difficult to google if you don't know the jargon "ternary", but there's less of a need to google it because it's pretty obvious how it works based simply on its implementation. [Steven D'Aprano] > It's a clear, *generic* meaning that doesn't have any association with > partial application. > We'd be trying to create that association from scratch. Sure, that's a good point. I don't think that sounds like such a big problem, but I also don't hate 'partial'. I just prefer 'given'. At any rate, I don't find the google-ablilty argument super strong because there are many constructs that are difficult to google, but still pretty great (e.g. comprehensions). [Steven D'Aprano] > > Words like 'partial', 'curry', 'lambda', and 'closure' are fine > > for text books, published papers, and technical discussion, > And programmers. > Yes, technical discussion among programmers. [Steven D'Aprano] > Programming is a technical skill with its own jargon. Classes, > inheritence, exceptions, trampolining, processes, threads, protocols, > imports, decorator, builders... we are happy with all those, why should > we fear partial and lambda? I get that programming carries it's own jargon and I understand that it has a beneficial function. It can facilitate concise communication of nuanced concepts. It can also be a needlessly confusing way to convey otherwise simple concepts. In the latter case, it can feel like the intent is to create an air of superiority through esoteric language. I feel like "curry" and "lambda" are needlessly un-descriptive and confusing. "partial" really isn't that bad, I just prefer "given" because I think it's pretty clear. I've never heard of "trampolining", but if I had to guess: it's probably related to recursion that involves more than one function? I suspect that most programmers couldn't describe the difference between a type and a class. I suspect that most programmers couldn't tell you the difference between an exception or an error. I know that lots of programmers refer to the "__init__" method as a "constructor" instead of an "initializer". Precision is less of a problem In a programming language. `func.given` doesn't have dozens of possible meanings. It's meaning has to be completely unambiguous to the machine. [Steven D'Aprano] > > but I think > > they would (or do in the case of 'lambda') harm Python. > That's an extreme overreaction. Extreme? I thought it was a rather benign opinion. I'm not exactly frothing at the mouth here. It's not like I'm declaring holy war on Python for using the word 'lambda'. I just think it was a mistake (and thatdeath should come to all non-believers). [Steven D'Aprano] > Do you mean to imply that there are people who looked at Python, loved > the language, but decided to use something else because they didn't like > the choice of the keyword "lambda"? No. Not at all. Is that what you got out of my sentence? Am I really the one being extreme? [Steven D'Aprano] > If not, in what way is Python harmed? Would it be faster if the keyword > was "function", or use less memory, or more expressive? I didn't realize I'd hit such a nerve. I think there are better ways that anonymous functions could have been implemented. I've already said in past discussions, I think the expression should come before the signature because the signature is often obvious from context so placing it before the logic is kinda noisy. I don't know what the best syntax would have been, but I refuse to believe that an esoteric word from an esoteric branch of calculus with an arbitrary etymology was the absolute best choice available. I think the harm that choice caused is relatively minor, but I don't think it was a great choice. I'm truly sorry if I hurt your feelings. [Steven D'Aprano] > Remember that to millions of programmers in the world, "function" is > just as much an obscure foreign piece of jargon they have to memorise as > "lambda" is to English-speakers. Maybe we should use Egyptian Hieroglyphs then. Even the playing field. It doesn't matter anyway, right? It's all nonsense to someone... Honestly, I don't think 'partial' is that bad. I just wanted to support your own comment: although possibly a less jargon name would be nicer: > add1 = add.given(1) But you seem to have some grudge against me. I don't get all the outrage over what I thought was a fairly benign post. Did I do something to make you so angry at me? I'd like to resolve whatever it is instead of having to deal with this every time I post. On Fri, Aug 10, 2018 at 2:09 AM, Steven D'Aprano wrote: > On Thu, Aug 09, 2018 at 01:32:00PM -0500, Abe Dillon wrote: > > I'd like to push for the less jargon-y `func.given()` version if this > gains > > traction. Not only is it shorter, it's a much more common term with a > clear > > meaning. > > It's a clear, *generic* meaning that doesn't have any association with > partial application. > > https://www.google.com/search?q=function+given > > We'd be trying to create that association from scratch. > > > > Words like 'partial', 'curry', 'lambda', and 'closure' are fine > > for text books, published papers, and technical discussion, > > And programmers. > > Programming is a technical skill with its own jargon. Classes, > inheritence, exceptions, trampolining, processes, threads, protocols, > imports, decorator, builders... we are happy with all those, why should > we fear partial and lambda? > > > > but I think > > they would (or do in the case of 'lambda') harm Python. > > That's an extreme overreaction. > > Do you mean to imply that there are people who looked at Python, loved > the language, but decided to use something else because they didn't like > the choice of the keyword "lambda"? > > If not, in what way is Python harmed? Would it be faster if the keyword > was "function", or use less memory, or more expressive? > > Remember that to millions of programmers in the world, "function" is > just as much an obscure foreign piece of jargon they have to memorise as > "lambda" is to English-speakers. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Fri Aug 10 18:42:12 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Fri, 10 Aug 2018 18:42:12 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> Message-ID: On Fri, Aug 10, 2018 at 6:21 PM Abe Dillon wrote: > [Neil Girdhar] > > I prefer partial since many programmers studied computer science > > > Many did not. I studied electrical engineering and wouldn't have been able > to tell you what the word 'partial' meant four years ago even though I've > been programming in one form or another since the late nineties. Many > programmers are scientists, engineers, financial analysts, etc. I'm pretty > sure I know what a closure is or what currying is, but if you put me on the > spot, I'd probably turn to Wikipedia to make sure I don't screw up the > definition. > > [Neil Girdhar] > >> It makes the concepts easier to google. > > > That can be an important criteria, but it can also be a red-herring. If an > implementation is clear enough, few people would have to google it. If, > however, you use obscure enough words like "lambda", people will google it > every day and still find it confusing. The ternary expression is difficult > to google if you don't know the jargon "ternary", but there's less of a > need to google it because it's pretty obvious how it works based simply on > its implementation. > > [Steven D'Aprano] > >> It's a clear, *generic* meaning that doesn't have any association with >> partial application. >> We'd be trying to create that association from scratch. > > > Sure, that's a good point. I don't think that sounds like such a big > problem, but I also don't hate 'partial'. I just prefer 'given'. > At any rate, I don't find the google-ablilty argument super strong because > there are many constructs that are difficult to google, but still pretty > great (e.g. comprehensions). > Not that it matters, but comprehension is a standard term in mathematics and computer science apparently: https://en.wikipedia.org/wiki/List_comprehension https://en.wikipedia.org/wiki/Set-builder_notation > [Steven D'Aprano] > > > Words like 'partial', 'curry', 'lambda', and 'closure' are fine >> > for text books, published papers, and technical discussion, >> And programmers. >> > > Yes, technical discussion among programmers. > > [Steven D'Aprano] > > Programming is a technical skill with its own jargon. Classes, >> inheritence, exceptions, trampolining, processes, threads, protocols, >> imports, decorator, builders... we are happy with all those, why should >> we fear partial and lambda? > > > I get that programming carries it's own jargon and I understand that it > has a beneficial function. It can facilitate concise communication of > nuanced concepts. It can also be a needlessly confusing way to convey > otherwise simple concepts. In the latter case, it can feel like the intent > is to create an air of superiority through esoteric language. I feel like > "curry" and "lambda" are needlessly un-descriptive and confusing. "partial" > really isn't that bad, I just prefer "given" because I think it's pretty > clear. I've never heard of "trampolining", but if I had to guess: it's > probably related to recursion that involves more than one function? > > I suspect that most programmers couldn't describe the difference between a > type and a class. > I suspect that most programmers couldn't tell you the difference between > an exception or an error. > I know that lots of programmers refer to the "__init__" method as a > "constructor" instead of an "initializer". > > Precision is less of a problem In a programming language. `func.given` > doesn't have dozens of possible meanings. It's meaning has to be completely > unambiguous to the machine. > > [Steven D'Aprano] > > > but I think >> > they would (or do in the case of 'lambda') harm Python. >> That's an extreme overreaction. > > > Extreme? I thought it was a rather benign opinion. I'm not exactly > frothing at the mouth here. It's not like I'm declaring holy war on Python > for using the word 'lambda'. I just think it was a mistake (and thatdeath > should come to all non-believers). > > [Steven D'Aprano] > > Do you mean to imply that there are people who looked at Python, loved >> the language, but decided to use something else because they didn't like >> the choice of the keyword "lambda"? > > > No. Not at all. Is that what you got out of my sentence? Am I really the > one being extreme? > I didn't think you were being extreme at all. I think you're making a reasonable point about keeping things simple. I disagree with you though when it comes to avoiding the technical terms. It's easier for people new to a field to learn the jargon of that field than it is to try to make it easier for them and by essentially creating a whole lot more technical jargon. (Even if that jargon uses common words.) Your idea for "given" isn't obviously doing a partial function application. Someone might wonder if "given" is setting thread local storage, or setting attributes on a callable class, or opening context managers at call time? > > [Steven D'Aprano] > >> If not, in what way is Python harmed? Would it be faster if the keyword >> was "function", or use less memory, or more expressive? > > > I didn't realize I'd hit such a nerve. I think there are better ways that > anonymous functions could have been implemented. I've already said in past > discussions, I think the expression should come before the signature > because the signature is often obvious from context so placing it before > the logic is kinda noisy. I don't know what the best syntax would have > been, but I refuse to believe that an esoteric word from an esoteric branch > of calculus with an arbitrary etymology was the absolute best choice > available. I think the harm that choice caused is relatively minor, but I > don't think it was a great choice. I'm truly sorry if I hurt your feelings. > > [Steven D'Aprano] > > Remember that to millions of programmers in the world, "function" is >> just as much an obscure foreign piece of jargon they have to memorise as >> "lambda" is to English-speakers. > > > Maybe we should use Egyptian Hieroglyphs then. Even the playing field. It > doesn't matter anyway, right? It's all nonsense to someone... > > Honestly, I don't think 'partial' is that bad. I just wanted to support > your own comment: > > > although possibly a less jargon name would be nicer: >> add1 = add.given(1) > > > But you seem to have some grudge against me. I don't get all the outrage > over what I thought was a fairly benign post. > Did I do something to make you so angry at me? I'd like to resolve > whatever it is instead of having to deal with this every time I post. > > On Fri, Aug 10, 2018 at 2:09 AM, Steven D'Aprano > wrote: > >> On Thu, Aug 09, 2018 at 01:32:00PM -0500, Abe Dillon wrote: >> > I'd like to push for the less jargon-y `func.given()` version if this >> gains >> > traction. Not only is it shorter, it's a much more common term with a >> clear >> > meaning. >> >> It's a clear, *generic* meaning that doesn't have any association with >> partial application. >> >> https://www.google.com/search?q=function+given >> >> We'd be trying to create that association from scratch. >> >> >> > Words like 'partial', 'curry', 'lambda', and 'closure' are fine >> > for text books, published papers, and technical discussion, >> >> And programmers. >> >> Programming is a technical skill with its own jargon. Classes, >> inheritence, exceptions, trampolining, processes, threads, protocols, >> imports, decorator, builders... we are happy with all those, why should >> we fear partial and lambda? >> >> >> > but I think >> > they would (or do in the case of 'lambda') harm Python. >> >> That's an extreme overreaction. >> >> Do you mean to imply that there are people who looked at Python, loved >> the language, but decided to use something else because they didn't like >> the choice of the keyword "lambda"? >> >> If not, in what way is Python harmed? Would it be faster if the keyword >> was "function", or use less memory, or more expressive? >> >> Remember that to millions of programmers in the world, "function" is >> just as much an obscure foreign piece of jargon they have to memorise as >> "lambda" is to English-speakers. >> >> >> -- >> Steve >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Fri Aug 10 19:01:59 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Fri, 10 Aug 2018 16:01:59 -0700 (PDT) Subject: [Python-ideas] Consider adding an iterable option to dataclass Message-ID: It would be nice if dataclasses (https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass) had an option to make them a sequence. This would make dataclass(frozen=True, order=True, sequence=True) an optionally-typed version of namedtuple. It would almost totally supplant it except that namedtuples have a smaller memory footprint. sequence would simply inherit from collections.abc.Sequence and implement the two methods __len__ and __getitme__. Best, Neil -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Fri Aug 10 20:29:41 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 11 Aug 2018 10:29:41 +1000 Subject: [Python-ideas] Consider adding an iterable option to dataclass In-Reply-To: References: Message-ID: <20180811002941.GN22431@ando.pearwood.info> On Fri, Aug 10, 2018 at 04:01:59PM -0700, Neil Girdhar wrote: > It would be nice if dataclasses > (https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass) > had an option to make them a sequence. Do you have a use-case or reason for this other than "it would be nice"? Nice in what way? We already have namedtuple, and for backwards compatibility if no other reason it won't be going away. What benefit do we get from allowing dataclasses to do what namedtuple already does? You already mentioned one disadvantage: namedtuple is much more memory efficient. What corresponding benefit do you see? Dataclass already supports explicit conversion to tuples and dicts. What use-cases for sequence-ness don't they support? Conceptually, I think of dataclasses as a record or a struct, not as a sequence. (I'll admit that I think of namedtuples the same way, and almost never make use of their tuple-ness.) I would find it strange for dataclass to support a sequence API out of the box. -- Steve From abedillon at gmail.com Fri Aug 10 20:59:34 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 10 Aug 2018 19:59:34 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> Message-ID: [Neil Girdhar] > > ... I don't find the google-ablilty argument super strong because > there are many constructs that are difficult to google, but still pretty > great (e.g. comprehensions). > Not that it matters, but comprehension is a standard term in mathematics > and computer science apparently: > https://en.wikipedia.org/wiki/List_comprehension > https://en.wikipedia.org/wiki/Set-builder_notation The point I was trying to make is: If you were to read a set comprehension for the first time, not knowing what it was, what would you google? It's not an easily searchable construct, but it's still an elegant, fairly easy to comprehend feature. This is actually a pretty good example of where I stand. Of course we use words like 'comprehensions' when talking about language features, partly because it's easier than "that expression that builds a list, set, or dictionary" and partly because we often discuss how other languages implemented the same general feature. That doesn't mean that the syntax has to contain the word 'comprehension': make_initials = lambda person: "".join(generator(domain=person.names, predicate=bool, term=lambda name: name[0])) initials = list.comprehension(domain=people, predicate=lambda person: any(person.names), term=make_initials) Borrowing from math notation and/or jargon, as comprehensions do, is fine, especially if it's common enough to be taught in grade-school. Set-builder notation is beyond what I learned in grade-school, but Python does more than 'borrow' from set builder notation. It uses familiar words like "for", "in", and "if", in place of that little epsilon (?) and bar and logical conjugation operator (*?*) which I think help make them understandable. [Neil Girdhar] > I disagree with you though when it comes to avoiding the technical terms. > It's easier for people new to a field to learn the jargon of that field > than it is to try to make it easier for them and by essentially creating a > whole lot more technical jargon. I'm willing to concede that that's probably true in this case. I think the term "partial function application" is fairly clear rather than jargon-for-jargon's sake. I could see someone thinking it meant that the function is partially run, but that's a pretty minor worry. I'm sure without looking it up, people would assume all sorts of things about what func.given could mean. I also think the case of someone running into either usage without some pretty glaring context clues about what's going on is pretty unlikely. I won't concede that lambda was an optimal choice. Even a reuse of the keyword "def" would have been better because it would clearly relate it to function declaration: hand = sorted(pocket + community, key=def card: card.suit)[-5:] It's literally short for "define function", so it makes sense. My other complaint about lambdas, that they should be arranged logic first, does go against pretty much all other implementations of anonymous functions , but I still think it makes more sense: hand = sorted(pocket + community, key=card.suit from card)[-5:] There are several possible variations of that concept. I think most of them would be better than the current syntax. An alternate form of lambda is probably never going to come and I'm OK with that. It's just my go-to anti-jargon example. Anonymous functions are not a confusing concept, yet people get caught up on it surprisingly frequently. I think the name is partly to blame. On Fri, Aug 10, 2018 at 5:42 PM, Neil Girdhar wrote: > > > On Fri, Aug 10, 2018 at 6:21 PM Abe Dillon wrote: > >> [Neil Girdhar] >> >> I prefer partial since many programmers studied computer science >> >> >> Many did not. I studied electrical engineering and wouldn't have been >> able to tell you what the word 'partial' meant four years ago even though >> I've been programming in one form or another since the late nineties. Many >> programmers are scientists, engineers, financial analysts, etc. I'm pretty >> sure I know what a closure is or what currying is, but if you put me on the >> spot, I'd probably turn to Wikipedia to make sure I don't screw up the >> definition. >> >> [Neil Girdhar] >> >>> It makes the concepts easier to google. >> >> >> That can be an important criteria, but it can also be a red-herring. If >> an implementation is clear enough, few people would have to google it. If, >> however, you use obscure enough words like "lambda", people will google it >> every day and still find it confusing. The ternary expression is difficult >> to google if you don't know the jargon "ternary", but there's less of a >> need to google it because it's pretty obvious how it works based simply on >> its implementation. >> >> [Steven D'Aprano] >> >>> It's a clear, *generic* meaning that doesn't have any association with >>> partial application. >>> We'd be trying to create that association from scratch. >> >> >> Sure, that's a good point. I don't think that sounds like such a big >> problem, but I also don't hate 'partial'. I just prefer 'given'. >> At any rate, I don't find the google-ablilty argument super strong >> because there are many constructs that are difficult to google, but still >> pretty great (e.g. comprehensions). >> > Not that it matters, but comprehension is a standard term in mathematics > and computer science apparently: > > https://en.wikipedia.org/wiki/List_comprehension > https://en.wikipedia.org/wiki/Set-builder_notation > > >> [Steven D'Aprano] >> >> > Words like 'partial', 'curry', 'lambda', and 'closure' are fine >>> > for text books, published papers, and technical discussion, >>> And programmers. >>> >> >> Yes, technical discussion among programmers. >> >> [Steven D'Aprano] >> >> Programming is a technical skill with its own jargon. Classes, >>> inheritence, exceptions, trampolining, processes, threads, protocols, >>> imports, decorator, builders... we are happy with all those, why should >>> we fear partial and lambda? >> >> >> I get that programming carries it's own jargon and I understand that it >> has a beneficial function. It can facilitate concise communication of >> nuanced concepts. It can also be a needlessly confusing way to convey >> otherwise simple concepts. In the latter case, it can feel like the intent >> is to create an air of superiority through esoteric language. I feel like >> "curry" and "lambda" are needlessly un-descriptive and confusing. "partial" >> really isn't that bad, I just prefer "given" because I think it's pretty >> clear. I've never heard of "trampolining", but if I had to guess: it's >> probably related to recursion that involves more than one function? >> >> I suspect that most programmers couldn't describe the difference between >> a type and a class. >> I suspect that most programmers couldn't tell you the difference between >> an exception or an error. >> I know that lots of programmers refer to the "__init__" method as a >> "constructor" instead of an "initializer". >> >> Precision is less of a problem In a programming language. `func.given` >> doesn't have dozens of possible meanings. It's meaning has to be completely >> unambiguous to the machine. >> >> [Steven D'Aprano] >> >> > but I think >>> > they would (or do in the case of 'lambda') harm Python. >>> That's an extreme overreaction. >> >> >> Extreme? I thought it was a rather benign opinion. I'm not exactly >> frothing at the mouth here. It's not like I'm declaring holy war on Python >> for using the word 'lambda'. I just think it was a mistake (and thatdeath >> should come to all non-believers). >> >> [Steven D'Aprano] >> >> Do you mean to imply that there are people who looked at Python, loved >>> the language, but decided to use something else because they didn't like >>> >>> the choice of the keyword "lambda"? >> >> >> No. Not at all. Is that what you got out of my sentence? Am I really the >> one being extreme? >> > > I didn't think you were being extreme at all. I think you're making a > reasonable point about keeping things simple. > > I disagree with you though when it comes to avoiding the technical terms. > It's easier for people new to a field to learn the jargon of that field > than it is to try to make it easier for them and by essentially creating a > whole lot more technical jargon. (Even if that jargon uses common words.) > > Your idea for "given" isn't obviously doing a partial function > application. Someone might wonder if "given" is setting thread local > storage, or setting attributes on a callable class, or opening context > managers at call time? > > >> >> [Steven D'Aprano] >> >>> If not, in what way is Python harmed? Would it be faster if the keyword >>> was "function", or use less memory, or more expressive? >> >> >> I didn't realize I'd hit such a nerve. I think there are better ways that >> anonymous functions could have been implemented. I've already said in past >> discussions, I think the expression should come before the signature >> because the signature is often obvious from context so placing it before >> the logic is kinda noisy. I don't know what the best syntax would have >> been, but I refuse to believe that an esoteric word from an esoteric branch >> of calculus with an arbitrary etymology was the absolute best choice >> available. I think the harm that choice caused is relatively minor, but I >> don't think it was a great choice. I'm truly sorry if I hurt your feelings. >> >> [Steven D'Aprano] >> >> Remember that to millions of programmers in the world, "function" is >>> just as much an obscure foreign piece of jargon they have to memorise as >>> >>> "lambda" is to English-speakers. >> >> >> Maybe we should use Egyptian Hieroglyphs then. Even the playing field. It >> doesn't matter anyway, right? It's all nonsense to someone... >> >> Honestly, I don't think 'partial' is that bad. I just wanted to support >> your own comment: >> >> >> although possibly a less jargon name would be nicer: >>> add1 = add.given(1) >> >> >> But you seem to have some grudge against me. I don't get all the outrage >> over what I thought was a fairly benign post. >> Did I do something to make you so angry at me? I'd like to resolve >> whatever it is instead of having to deal with this every time I post. >> >> On Fri, Aug 10, 2018 at 2:09 AM, Steven D'Aprano >> wrote: >> >>> On Thu, Aug 09, 2018 at 01:32:00PM -0500, Abe Dillon wrote: >>> > I'd like to push for the less jargon-y `func.given()` version if this >>> gains >>> > traction. Not only is it shorter, it's a much more common term with a >>> clear >>> > meaning. >>> >>> It's a clear, *generic* meaning that doesn't have any association with >>> partial application. >>> >>> https://www.google.com/search?q=function+given >>> >>> We'd be trying to create that association from scratch. >>> >>> >>> > Words like 'partial', 'curry', 'lambda', and 'closure' are fine >>> > for text books, published papers, and technical discussion, >>> >>> And programmers. >>> >>> Programming is a technical skill with its own jargon. Classes, >>> inheritence, exceptions, trampolining, processes, threads, protocols, >>> imports, decorator, builders... we are happy with all those, why should >>> we fear partial and lambda? >>> >>> >>> > but I think >>> > they would (or do in the case of 'lambda') harm Python. >>> >>> That's an extreme overreaction. >>> >>> Do you mean to imply that there are people who looked at Python, loved >>> the language, but decided to use something else because they didn't like >>> the choice of the keyword "lambda"? >>> >>> If not, in what way is Python harmed? Would it be faster if the keyword >>> was "function", or use less memory, or more expressive? >>> >>> Remember that to millions of programmers in the world, "function" is >>> just as much an obscure foreign piece of jargon they have to memorise as >>> "lambda" is to English-speakers. >>> >>> >>> -- >>> Steve >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> >> -- >> >> --- >> You received this message because you are subscribed to a topic in the >> Google Groups "python-ideas" group. >> To unsubscribe from this topic, visit https://groups.google.com/d/ >> topic/python-ideas/jOMinivFCcQ/unsubscribe. >> To unsubscribe from this group and all its topics, send an email to >> python-ideas+unsubscribe at googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> -- >> >> --- >> You received this message because you are subscribed to a topic in the >> Google Groups "python-ideas" group. >> To unsubscribe from this topic, visit https://groups.google.com/d/ >> topic/python-ideas/jOMinivFCcQ/unsubscribe. >> To unsubscribe from this group and all its topics, send an email to >> python-ideas+unsubscribe at googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric at trueblade.com Fri Aug 10 20:29:37 2018 From: eric at trueblade.com (Eric V. Smith) Date: Fri, 10 Aug 2018 20:29:37 -0400 Subject: [Python-ideas] Consider adding an iterable option to dataclass In-Reply-To: References: Message-ID: <25c9112a-f9a0-6c02-d0a9-ea2998914395@trueblade.com> On 8/10/2018 7:01 PM, Neil Girdhar wrote: > It would be nice if dataclasses > (https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass) > had an option to make them a sequence.? This would make > > dataclass(frozen=True, order=True, sequence=True) > > an optionally-typed version of namedtuple.? It would almost totally > supplant it except that namedtuples have a smaller memory footprint. Note that type.NamedTuple already gives you typed namedtuples. Admittedly the feature set is different from dataclasses, though. > sequence would simply inherit from collections.abc.Sequence and > implement the two methods __len__ and __getitme__. Unless I'm misunderstanding you, this falls in to the same problem as setting __slots__: you need to return a new class, in this case since you can't add inheritance after the fact. I don't think __isinstancecheck__ helps you here, but maybe I'm missing something (I'm not a big user of inheritance or ABCs). Not that returning a new class is impossible, it's just that I didn't want to do it in the first go-round with dataclasses. For slots, I have a sample @add_slots() at https://github.com/ericvsmith/dataclasses/blob/master/dataclass_tools.py. Maybe we could do something similar with @add_sequence() and test it out? It would have to be a little more sophisticated than @add_slots(), since it would need to iterate over __dataclass_fields__, etc. I'm on vacation next week, maybe I'll play around with this. Eric From vincent.maillol at gmail.com Sat Aug 11 04:33:59 2018 From: vincent.maillol at gmail.com (Vincent Maillol) Date: Sat, 11 Aug 2018 10:33:59 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: Hello, Currently the user defined functions are mutables, there can be existed python codes like this: >>> def foo(): ... pass ... >>> if not hasattr(foo, 'partial'): ... foo.partial = {} ... Adding a new method to function object can break existing projects, but it is without impact with buit-in functions because they are immutables. 2018-08-09 18:59 GMT+02:00 Michel Desmoulin : > I'd rather have functools.partial() to be added as a new method on > function objects. > > > > > fromfunctools importpartial > > > > > > def add(x:int,y:int)->int: > > returnx +y > > > > > > add_2 = partial(add,2) > > > > Would become: > > add_2 = add.partial(2) > > Nothing to change on the parser, no obscure syntax for future readers, > and we can get the opportunity of rewriting partial() in C as right now > it is amazingly way, way slower than a lambda. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Sat Aug 11 05:48:24 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Sat, 11 Aug 2018 05:48:24 -0400 Subject: [Python-ideas] Consider adding an iterable option to dataclass In-Reply-To: <25c9112a-f9a0-6c02-d0a9-ea2998914395@trueblade.com> References: <25c9112a-f9a0-6c02-d0a9-ea2998914395@trueblade.com> Message-ID: My only motivation for this idea is so that I can forget about namedtuple. Thinking about it again today, I withdraw my suggestion until I one day see a need for it. On Fri, Aug 10, 2018 at 10:14 PM Eric V. Smith wrote: > On 8/10/2018 7:01 PM, Neil Girdhar wrote: > > It would be nice if dataclasses > > ( > https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass) > > had an option to make them a sequence. This would make > > > > dataclass(frozen=True, order=True, sequence=True) > > > > an optionally-typed version of namedtuple. It would almost totally > > supplant it except that namedtuples have a smaller memory footprint. > > Note that type.NamedTuple already gives you typed namedtuples. > Admittedly the feature set is different from dataclasses, though. > > > sequence would simply inherit from collections.abc.Sequence and > > implement the two methods __len__ and __getitme__. > > Unless I'm misunderstanding you, this falls in to the same problem as > setting __slots__: you need to return a new class, in this case since > you can't add inheritance after the fact. I don't think > __isinstancecheck__ helps you here, but maybe I'm missing something (I'm > not a big user of inheritance or ABCs). > > Not that returning a new class is impossible, it's just that I didn't > want to do it in the first go-round with dataclasses. > That's a fair point. I'm sure you know that your decorator could always return a new class that inherits from both Sequence and the original class. As a user of dataclass, I never assumed that it wouldn't do this. > For slots, I have a sample @add_slots() at > https://github.com/ericvsmith/dataclasses/blob/master/dataclass_tools.py. > Maybe we could do something similar with @add_sequence() and test it > out? It would have to be a little more sophisticated than @add_slots(), > since it would need to iterate over __dataclass_fields__, etc. > > I'm on vacation next week, maybe I'll play around with this. > Cool, have a great vacation. > > Eric > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/8C9iVJsba5A/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robertve92 at gmail.com Sat Aug 11 08:53:42 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 11 Aug 2018 14:53:42 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: Le sam. 11 ao?t 2018 ? 10:34, Vincent Maillol a ?crit : > Hello, > > Currently the user defined functions are mutables, there can be existed > python codes like this: > > >>> def foo(): > ... pass > ... > >>> if not hasattr(foo, 'partial'): > ... foo.partial = {} > ... > > Adding a new method to function object can break existing projects, but it > is without impact with buit-in functions because they are immutables. > > Or use a decorator like in the lib ? from funcoperators import partially @partially def f(x, y): return x-y g = f.part(4) g(5) The mutability solution however cannot have a "self" argument : def f(x,y): return x-y f.stuff = lambda self: self(5, 2) f.stuff() # missing self One would have to give "f". f.partial = lambda *a, **b: functools.partial(f, *a, **b) g = f.partial(4) g(5) > 2018-08-09 18:59 GMT+02:00 Michel Desmoulin : > >> I'd rather have functools.partial() to be added as a new method on >> function objects. >> >> > >> > fromfunctools importpartial >> > >> > >> > def add(x:int,y:int)->int: >> > returnx +y >> > >> > >> > add_2 = partial(add,2) >> > >> >> Would become: >> >> add_2 = add.partial(2) >> >> Nothing to change on the parser, no obscure syntax for future readers, >> and we can get the opportunity of rewriting partial() in C as right now >> it is amazingly way, way slower than a lambda. >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robertve92 at gmail.com Sat Aug 11 08:59:35 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Sat, 11 Aug 2018 14:59:35 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: Therefore one can do a decorator that gives .partial: def partialize(f): from functools import partial f.partial = lambda *a, **b: partial(f, *a, **b) return f @partialize def f(x,y): return x-y g = f.partial(5) g(3) That's the same idea as funcoperators.partially but doesn't return a new function (which has the advantage of keeping help(f)) Le sam. 11 ao?t 2018 ? 14:53, Robert Vanden Eynde a ?crit : > > > Le sam. 11 ao?t 2018 ? 10:34, Vincent Maillol > a ?crit : > >> Hello, >> >> Currently the user defined functions are mutables, there can be existed >> python codes like this: >> >> >>> def foo(): >> ... pass >> ... >> >>> if not hasattr(foo, 'partial'): >> ... foo.partial = {} >> ... >> >> Adding a new method to function object can break existing projects, but >> it is without impact with buit-in functions because they are immutables. >> >> > Or use a decorator like in the lib ? > > from funcoperators import partially > > @partially > def f(x, y): > return x-y > > g = f.part(4) > g(5) > > The mutability solution however cannot have a "self" argument : > > def f(x,y): > return x-y > > f.stuff = lambda self: self(5, 2) > f.stuff() # missing self > > One would have to give "f". > > f.partial = lambda *a, **b: functools.partial(f, *a, **b) > > g = f.partial(4) > g(5) > > >> 2018-08-09 18:59 GMT+02:00 Michel Desmoulin : >> >>> I'd rather have functools.partial() to be added as a new method on >>> function objects. >>> >>> > >>> > fromfunctools importpartial >>> > >>> > >>> > def add(x:int,y:int)->int: >>> > returnx +y >>> > >>> > >>> > add_2 = partial(add,2) >>> > >>> >>> Would become: >>> >>> add_2 = add.partial(2) >>> >>> Nothing to change on the parser, no obscure syntax for future readers, >>> and we can get the opportunity of rewriting partial() in C as right now >>> it is amazingly way, way slower than a lambda. >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Sat Aug 11 19:59:09 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Sat, 11 Aug 2018 16:59:09 -0700 (PDT) Subject: [Python-ideas] Is this PEP-able? "with" statement inside genexps / list comprehensions In-Reply-To: <4fb1f54f-ea84-16c8-a445-017a4ad2d079@mozilla.com> References: <20180730191517.GA27867@zero.localdomain> <4fb1f54f-ea84-16c8-a445-017a4ad2d079@mozilla.com> Message-ID: On Monday, July 30, 2018 at 3:55:25 PM UTC-4, Kyle Lahnakoski wrote: > > Rudy, > > I think your proposal may be very specific to iterable context managers; > I don't think his proposal is specific to iterable context managers. You can have a with clause that is used in a following for clause. in which case, make a method that makes that assumption: > > > def iter_with(obj): > > with obj as context: > > yield from context > > and use it > > > g = ( > > f.read() > > for fn in filenames > > for f in iter_with(open(fn)) > > ) > > On 2018-07-30 15:15, Rudy Matela wrote: > > Hello, > > > > Do you think it would be nice to allow with statements inside genexps or > > list comprehensions? The functions __enter__ and __exit__ would be > > automatically called as iterables are traversed. I am thinking of > > drafting a PEP about this. Examples: > > > > > > This > > > > g = (f.read() for fn in filenames with open(fn) as f) > > > > would be equivalent to the following use of a generator function: > > > > def __gen(): > > for fn in filenames: > > with open(fn) as f: > > yield f.read() > > g = __gen() > > > > > > This > > > > list = [f.read() for fn in filenames with open(fn) as f] > > > > would be equivalent to the following: > > > > list = [] > > for fn in filenames: > > with open(fn) as f: > > list.append(f.read()) > > > > -- > > Rudy > > _______________________________________________ > > Python-ideas mailing list > > Python... at python.org > > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > _______________________________________________ > Python-ideas mailing list > Python... at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Sun Aug 12 21:06:13 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 13 Aug 2018 11:06:13 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> Message-ID: <20180813010612.GP22431@ando.pearwood.info> Answering a few of Abe's comments out of order... On Fri, Aug 10, 2018 at 05:20:25PM -0500, Abe Dillon wrote: > I didn't realize I'd hit such a nerve. [...] I'm truly sorry > if I hurt your feelings. [...] > But you seem to have some grudge against me. I don't get all the > outrage over what I thought was a fairly benign post. Did I do > something to make you so angry at me? I'd like to resolve whatever it > is instead of having to deal with this every time I post. Have we become so sensitive to disagreement that criticism of ideas is immediately seen as "angry", "a grudge", "outrage"? If so, I find that sad and worrying. My feelings aren't hurt, you haven't hit a nerve, I'm not angry at anything you wrote, and I'm not holding a grudge. I thought we were discussing *ideas*, not attacking each other. Just because I challenge your statements doesn't mean I'm attacking you. Moving on... [...] > I suspect that most programmers couldn't describe the difference > between a type and a class. In Python, there is none. There is a sense in which types are different from classes, but that sense is not fundamental, and in practice many languages blur the lines between them. > I suspect that most programmers couldn't tell you the difference > between an exception or an error. There's a school of thought that most programmers can't program. https://blog.codinghorror.com/why-cant-programmers-program/ But regardless, we don't design Python based on the misunderstandings of the least competent, most ignorant demographic. That's why we have exceptions, only some of which are errors, and not StopIterationError KeyboardInterruptError SystemExitError etc. I believe that using a well-designed language should gently encourage the programmer to learn, by example. I didn't know the the functional programming techniques of map, reduce or partial until I came across them in Python. I think I'm a better programmer and less ignorant now than I was for that. Consequently, when I hear you describing how few programmers know the term "partial", what I think is "what a great opportunity for them to learn something new!". Or not, of course. For those of us who don't care for functional programming idioms, there's no need to use partial in our own code. > [Steven D'Aprano] > > > Do you mean to imply that there are people who looked at Python, > > loved the language, but decided to use something else because they > > didn't like the choice of the keyword "lambda"? > > No. Not at all. Is that what you got out of my sentence? Am I really > the one being extreme? Yes, that's what I got out of your sentence. If you don't mean that, I don't know what you do mean. You've said that the choice of keyword, "lambda", has caused harm. Given the chance to clarify what you meant, you stood by your comment that the choice of keyword "lambda" has done real, significant, non-trivial harm to Python (the language, or the community). Presumably you fear the same thing will happen again if we choose "partial" (otherwise, why raise the issue?). Harm in what sense? That's what I tried to ask earlier, perhaps not as clearly as I intended. If the choice of name "lambda" doesn't repel would-be users, or cause bugs, or harm performance, then what harm does it do? This is a genuine question. I'm trying to understand your comments, not just dismiss them. You made a comment much stronger than merely "I don't like the name", claiming that the name is harmful. I could just dismiss your comment as meaningless hyperbole and ignore it, but I thought to give you the respect of assuming that you might be correct but I just wasn't understanding why. Hence my question. > [Steven D'Aprano] > > > Remember that to millions of programmers in the world, "function" is > > just as much an obscure foreign piece of jargon they have to memorise as > > "lambda" is to English-speakers. > > > Maybe we should use Egyptian Hieroglyphs then. Even the playing field. It > doesn't matter anyway, right? It's all nonsense to someone... No, we ought to stick to ASCII, for reasons I've discussed recently in other threads. And Python does have a long-standing tradition of sticking to mostly English words, a tradition for which I personally am grateful. But we ought to "check our privilege", as they say. I think that if we as a community automatically reject any word because it isn't "plain English", that would be a sign of unexamined privilege and quite rude to boot. How can we insist that 3/4 of the world learn English words to use Python, if we aren't even willing to move out of our own comfort zone to the extent of learning accurate jargon terms from our own profession? None of this is to rule out "given". (I think it's certainly better than Perl's choice of "assuming".) But if we go down this path (which is by no means decided!), and choose "given" over "partial", we ought to be clear about the reasons why. -- Steve From abedillon at gmail.com Sun Aug 12 23:31:36 2018 From: abedillon at gmail.com (Abe Dillon) Date: Sun, 12 Aug 2018 22:31:36 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <20180813010612.GP22431@ando.pearwood.info> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: [Steven D'Aprano] > Just because I challenge your statements doesn't mean I'm attacking you. No. Telling me I'm having an extreme overreaction means you're attacking me. Pushing the narrative that I'm irrational by enumerating the least charitable interpretations of my words possible then claiming you were just discussing *ideas* is disingenuous. I don't know who you think you're kidding, Steven. You could have simply asked me what I meant. It would have been much easier. All those extra words serve a very clear purpose and everyone knows it, so you can stop acting "sad and worried" when someone calls you out. I explained my position on lambda as fully as I care to in my response to Niel if you care to read it. I only think lambda harms Python in so far as there were better alternatives that communicate their intention much better and are more readable. That's an opinion. If you must know, i'm not currently frothing at the mouth as I state it. My original post was agreeing with you. Supporting your own words. If you don't agree with my position that we should avoid jargon for jargon's sake, then what exactly did you mean when you said, "although possibly a less jargon name would be nicer?" Can you articulate why you think it might be nicer to use a less jargon name? What about my saying it all of a sudden makes it an "extreme overreaction"? [Steven D'Aprano] > You've said that the choice of keyword, "lambda", has caused harm. Given > the chance to clarify what you meant, you stood by your comment that the > choice of keyword "lambda" has done real, significant, non-trivial harm > to Python (the language, or the community). What are you talking about? I explained exactly what I meant: I think there are better ways that anonymous functions could have been > implemented. I've already said in past discussions, I think the expression > should come before the signature because the signature is often obvious > from context so placing it before the logic is kinda noisy. I don't know > what the best syntax would have been, but I refuse to believe that an > esoteric word from an esoteric branch of calculus with an arbitrary > etymology was the absolute best choice available. I think the harm that > choice caused is relatively minor, but I don't think it was a great choice. Notice: I never said "real, significant, non-trivial harm" anywhere in this entire discussion. I never said anything close to that. Stop jamming bullshit in my mouth to suit your narrative that I'm "extremely overreacting". It's not cute. [Steven D'Aprano] > This is a genuine question. I'm trying to understand your comments, not just > dismiss them. If you're so genuinely interested, then how come you couldn't be bothered to read my explaination above? [Steven D'Aprano] > Presumably you fear the same thing will happen again if we choose > "partial" (otherwise, why raise the issue?). There is no issue. I've already conceded that. Please read the conversation that followed with Neil Girdhar. I was simply stating a preference and trying to articulate my reasoning behind that preference. My whole intent was to +1 your alternative and say "I prefer given to partial". That's it. [Steven D'Aprano] > Python does have a long-standing tradition of sticking to mostly English > words, a tradition for which I personally am grateful. I am too. I'd like that to continue. [Steven D'Aprano] > But we ought to "check our privilege", as they say. I think that if we > as a community automatically reject any word because it isn't "plain > English", that would be a sign of unexamined privilege and quite rude to > boot. Rude? Who would it be rude to if we had chosen "anonfunc" instead of "lambda"? [Steven D'Aprano] > How can we insist that 3/4 of the world learn English words to use Python Do you really think that 3/4 of the world learns English just to write Python? Do you think the only english they learn are the built-ins and standard library of Python? English is a dominant language in business and programming. That statement is no more "privileged" than the statement that the US Dollar is the most popular global reserve currency. It's a fact that I have no control over. [Steven D'Aprano] > ...if we aren't even willing to move out of our own comfort zone to > the extent of learning accurate jargon terms from our own profession? Very few of us are computer scientists by profession. That's not even where 'lambda' comes from. In computer science, it's called an "anonymous function". "lambda" comes from lambda calculus. [Steven D'Aprano] > If we go down this path... and choose "given" over "partial", we ought to > be > clear about the reasons why. I gave my reasons: it's shorter and less jargon while remaining fairly clear (in my opinion) You've already claimed that "possibly a less jargon name would be nicer", so I don't see the fuss. Apparently it's extreme when I say it. On Sun, Aug 12, 2018 at 8:06 PM, Steven D'Aprano wrote: > Answering a few of Abe's comments out of order... > > On Fri, Aug 10, 2018 at 05:20:25PM -0500, Abe Dillon wrote: > > I didn't realize I'd hit such a nerve. [...] I'm truly sorry > > if I hurt your feelings. > [...] > > But you seem to have some grudge against me. I don't get all the > > outrage over what I thought was a fairly benign post. Did I do > > something to make you so angry at me? I'd like to resolve whatever it > > is instead of having to deal with this every time I post. > > Have we become so sensitive to disagreement that criticism of ideas is > immediately seen as "angry", "a grudge", "outrage"? If so, I find that > sad and worrying. > > My feelings aren't hurt, you haven't hit a nerve, I'm not angry at > anything you wrote, and I'm not holding a grudge. I thought we were > discussing *ideas*, not attacking each other. Just because I challenge > your statements doesn't mean I'm attacking you. > > Moving on... > > [...] > > I suspect that most programmers couldn't describe the difference > > between a type and a class. > > In Python, there is none. > > There is a sense in which types are different from classes, but that > sense is not fundamental, and in practice many languages blur the lines > between them. > > > > I suspect that most programmers couldn't tell you the difference > > between an exception or an error. > > There's a school of thought that most programmers can't program. > > https://blog.codinghorror.com/why-cant-programmers-program/ > > But regardless, we don't design Python based on the misunderstandings of > the least competent, most ignorant demographic. That's why we have > exceptions, only some of which are errors, and not > > StopIterationError > KeyboardInterruptError > SystemExitError > > etc. > > I believe that using a well-designed language should gently encourage > the programmer to learn, by example. I didn't know the the functional > programming techniques of map, reduce or partial until I came across > them in Python. I think I'm a better programmer and less ignorant now > than I was for that. > > Consequently, when I hear you describing how few programmers know the > term "partial", what I think is "what a great opportunity for them to > learn something new!". > > Or not, of course. For those of us who don't care for functional > programming idioms, there's no need to use partial in our own code. > > > > [Steven D'Aprano] > > > > > Do you mean to imply that there are people who looked at Python, > > > loved the language, but decided to use something else because they > > > didn't like the choice of the keyword "lambda"? > > > > No. Not at all. Is that what you got out of my sentence? Am I really > > the one being extreme? > > Yes, that's what I got out of your sentence. If you don't mean that, I > don't know what you do mean. > > You've said that the choice of keyword, "lambda", has caused harm. Given > the chance to clarify what you meant, you stood by your comment that the > choice of keyword "lambda" has done real, significant, non-trivial harm > to Python (the language, or the community). Presumably you fear the same > thing will happen again if we choose "partial" (otherwise, why raise the > issue?). > > Harm in what sense? That's what I tried to ask earlier, perhaps not as > clearly as I intended. > > If the choice of name "lambda" doesn't repel would-be users, or cause > bugs, or harm performance, then what harm does it do? > > This is a genuine question. I'm trying to understand your comments, not > just dismiss them. > > You made a comment much stronger than merely "I don't like the name", > claiming that the name is harmful. I could just dismiss your comment as > meaningless hyperbole and ignore it, but I thought to give you the > respect of assuming that you might be correct but I just wasn't > understanding why. Hence my question. > > > > [Steven D'Aprano] > > > > > Remember that to millions of programmers in the world, "function" is > > > just as much an obscure foreign piece of jargon they have to memorise > as > > > "lambda" is to English-speakers. > > > > > > Maybe we should use Egyptian Hieroglyphs then. Even the playing field. It > > doesn't matter anyway, right? It's all nonsense to someone... > > No, we ought to stick to ASCII, for reasons I've discussed recently in > other threads. And Python does have a long-standing tradition of > sticking to mostly English words, a tradition for which I personally am > grateful. > > But we ought to "check our privilege", as they say. I think that if we > as a community automatically reject any word because it isn't "plain > English", that would be a sign of unexamined privilege and quite rude to > boot. How can we insist that 3/4 of the world learn English words to use > Python, if we aren't even willing to move out of our own comfort zone to > the extent of learning accurate jargon terms from our own profession? > > None of this is to rule out "given". (I think it's certainly better than > Perl's choice of "assuming".) But if we go down this path (which is by > no means decided!), and choose "given" over "partial", we ought to be > clear about the reasons why. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tritium-list at sdamon.com Sun Aug 12 23:49:01 2018 From: tritium-list at sdamon.com (Alex Walters) Date: Sun, 12 Aug 2018 23:49:01 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: <8b06701d432b8$9367ed60$ba37c820$@sdamon.com> > [Steven D'Aprano] > > > You've said that the choice of keyword, "lambda", has caused harm. > Given > the chance to clarify what you meant, you stood by your comment > that the > choice of keyword "lambda" has done real, significant, non-trivial > harm > to Python (the language, or the community). > > > What are you talking about? I explained exactly what I meant: > > > > I think there are better ways that anonymous functions could have > been implemented. I've already said in past discussions, I think the > expression should come before the signature because the signature is often > obvious from context so placing it before the logic is kinda noisy. I don't know > what the best syntax would have been, but I refuse to believe that an > esoteric word from an esoteric branch of calculus with an arbitrary etymology > was the absolute best choice available. I think the harm that choice caused is > relatively minor, but I don't think it was a great choice. > > > Notice: I never said "real, significant, non-trivial harm" anywhere in this > entire discussion. I never said anything close to that. Stop jamming bullshit in > my mouth to suit your narrative that I'm "extremely overreacting". It's not > cute. > He is questioning the concept that the lambda keyword has caused any harm. You assert that it caused minor harm. Minor harm can still be real, significant, and non-trivial. Has the keyword choice done any harm aside from mailing list jamming, and forum posts. I believe he is asserting that it hasn't. The burden of proof would be on you that it has caused any level of harm to the language of community, the criteria being that the harm be real, significant (if minor) and non-trivial. You will find no evidence to support your argument. You might find evidence that functional programming techniques are less useful with anonymous functions in python due to the restriction to only use expressions, but that isn't what is being argued. From rosuav at gmail.com Sun Aug 12 23:50:38 2018 From: rosuav at gmail.com (Chris Angelico) Date: Mon, 13 Aug 2018 13:50:38 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On Mon, Aug 13, 2018 at 1:31 PM, Abe Dillon wrote: > [Steven D'Aprano] >> >> Just because I challenge your statements doesn't mean I'm attacking you. > > > No. Telling me I'm having an extreme overreaction means you're attacking me. If your reaction was extreme, saying so isn't attacking you. > [Steven D'Aprano] >> >> You've said that the choice of keyword, "lambda", has caused harm. Given >> the chance to clarify what you meant, you stood by your comment that the >> choice of keyword "lambda" has done real, significant, non-trivial harm >> to Python (the language, or the community). > > > What are you talking about? I explained exactly what I meant: > >> I think there are better ways that anonymous functions could have been >> implemented. I've already said in past discussions, I think the expression >> should come before the signature because the signature is often obvious from >> context so placing it before the logic is kinda noisy. I don't know what the >> best syntax would have been, but I refuse to believe that an esoteric word >> from an esoteric branch of calculus with an arbitrary etymology was the >> absolute best choice available. I think the harm that choice caused is >> relatively minor, but I don't think it was a great choice. > > > Notice: I never said "real, significant, non-trivial harm" anywhere in this > entire discussion. I never said anything close to that. Stop jamming > bullshit in my mouth to suit your narrative that I'm "extremely > overreacting". It's not cute. Explain, please, what the HARM is that comes from the use of the word "lambda". In contrast, using the word "function" does definitely have harm, because you can no longer use the name "function" as a variable or parameter. Also, the signature is most decidedly NOT obvious from context, nor is it insignificant. Putting it first gives context to the body of the function. Python made the correct choice here. > [Steven D'Aprano] >> >> But we ought to "check our privilege", as they say. I think that if we >> as a community automatically reject any word because it isn't "plain >> English", that would be a sign of unexamined privilege and quite rude to >> boot. > > > Rude? Who would it be rude to if we had chosen "anonfunc" instead of > "lambda"? No, but it's no less jargonny. > Very few of us are computer scientists by profession. That's not even where > 'lambda' comes from. In computer science, it's called an "anonymous > function". "lambda" comes from lambda calculus. https://en.wikipedia.org/wiki/Anonymous_function "In computer programming, an anonymous function (function literal, lambda abstraction, or lambda expression) is a function definition that is not bound to an identifier." So... I would say "lambda" is very firmly connected with anonymous functions. ChrisA From abedillon at gmail.com Mon Aug 13 00:56:24 2018 From: abedillon at gmail.com (Abe Dillon) Date: Sun, 12 Aug 2018 23:56:24 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: [Alex Walters] > He is questioning the concept that the lambda keyword has caused any > harm. You assert that it caused minor harm. Minor harm can still be real, > significant, and non-trivial. What, exactly, is the difference between "minor" and "non-trivial" and when did I say the harm was "significant and non-trivial"? [Alex Walters] > You will find no evidence to support your argument. > You could read what I wrote to Neil Girdhar who was able to engage with me without implying that I've lost my mind. [Chris Angelico] > If your reaction was extreme, saying so isn't attacking you. Is this a hypothetical now? I said "*I think* they would (or do in the case of 'lambda') harm Python." I wasn't aware the word "harm" was something only deranged maniacs use. [Chris Angelico] > Explain, please, what the HARM is that comes from the use of the word > "lambda". I HAVE. [Chris Angelico] > Also, the signature is most decidedly NOT obvious from context Who decided this? It's been decided by some committee? When you write a key function, you don't know how many arguments are going to be passed? [Chris Angelico] > nor is it insignificant. I never said it was. I just said that the logic is more important from the standpoint of the reader. [Chris Angelico] > Putting it first gives context to the body of the > function. Python made the correct choice here. I disagree. This forum is looking more and more toxic. I've explained myself over and over again. I just wanted to +1 Steven's original comment. This is ridiculous. I guess I've pissed of the good-old-boys by calling out Steven's unnecessary condescension. Great. It looks like Python is in fantastic hands. On Sun, Aug 12, 2018 at 10:50 PM, Chris Angelico wrote: > On Mon, Aug 13, 2018 at 1:31 PM, Abe Dillon wrote: > > [Steven D'Aprano] > >> > >> Just because I challenge your statements doesn't mean I'm attacking you. > > > > > > No. Telling me I'm having an extreme overreaction means you're attacking > me. > > If your reaction was extreme, saying so isn't attacking you. > > > [Steven D'Aprano] > >> > >> You've said that the choice of keyword, "lambda", has caused harm. Given > >> the chance to clarify what you meant, you stood by your comment that the > >> choice of keyword "lambda" has done real, significant, non-trivial harm > >> to Python (the language, or the community). > > > > > > What are you talking about? I explained exactly what I meant: > > > >> I think there are better ways that anonymous functions could have been > >> implemented. I've already said in past discussions, I think the > expression > >> should come before the signature because the signature is often obvious > from > >> context so placing it before the logic is kinda noisy. I don't know > what the > >> best syntax would have been, but I refuse to believe that an esoteric > word > >> from an esoteric branch of calculus with an arbitrary etymology was the > >> absolute best choice available. I think the harm that choice caused is > >> relatively minor, but I don't think it was a great choice. > > > > > > Notice: I never said "real, significant, non-trivial harm" anywhere in > this > > entire discussion. I never said anything close to that. Stop jamming > > bullshit in my mouth to suit your narrative that I'm "extremely > > overreacting". It's not cute. > > Explain, please, what the HARM is that comes from the use of the word > "lambda". In contrast, using the word "function" does definitely have > harm, because you can no longer use the name "function" as a variable > or parameter. > > Also, the signature is most decidedly NOT obvious from context, nor is > it insignificant. Putting it first gives context to the body of the > function. Python made the correct choice here. > > > [Steven D'Aprano] > >> > >> But we ought to "check our privilege", as they say. I think that if we > >> as a community automatically reject any word because it isn't "plain > >> English", that would be a sign of unexamined privilege and quite rude to > >> boot. > > > > > > Rude? Who would it be rude to if we had chosen "anonfunc" instead of > > "lambda"? > > No, but it's no less jargonny. > > > Very few of us are computer scientists by profession. That's not even > where > > 'lambda' comes from. In computer science, it's called an "anonymous > > function". "lambda" comes from lambda calculus. > > https://en.wikipedia.org/wiki/Anonymous_function > > "In computer programming, an anonymous function (function literal, > lambda abstraction, or lambda expression) is a function definition > that is not bound to an identifier." > > So... I would say "lambda" is very firmly connected with anonymous > functions. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Mon Aug 13 01:04:51 2018 From: rosuav at gmail.com (Chris Angelico) Date: Mon, 13 Aug 2018 15:04:51 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On Mon, Aug 13, 2018 at 2:56 PM, Abe Dillon wrote: > [Chris Angelico] >> >> Also, the signature is most decidedly NOT obvious from context > > Who decided this? It's been decided by some committee? When you write a key > function, you don't know how many arguments are going to be passed? lst.onselect = anonfunc(print(target_item)) What's target_item? If you can't see the signature and see that it's a parameter, you should look externally for it. What are the parameters to an onselect function? Doesn't that seem important enough to see the signature up front? It's not just *how many* arguments are being passed. It's what they're called, too. You cannot interpret the body of a function without knowing that. Hiding that off to the end would make the language worse, not better. Plus, can you name any similar language that does that? Every other language I can think of has the parameters before the body. While this isn't a clinching argument by any means (Python has a different argument order for the ternary if operator, for instance), it's indicative. ChrisA From rymg19 at gmail.com Mon Aug 13 01:12:50 2018 From: rymg19 at gmail.com (Ryan Gonzalez) Date: Mon, 13 Aug 2018 00:12:50 -0500 Subject: [Python-ideas] Reminder about intent of messages (Was: Syntactic sugar to declare partial functions) In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: Now that the discussion has officially devolved into something that has absolutely nothing to do with the original topic, I'd like to point out something: (Note that I have no affiliation with the managers of this mailing list at all and am just posting this as an outsider.) In Steven D'Aprano's original message, I didn't see anything there as being a personal attack or as having an angry tone, at least based on his normal posting style. Maybe a bit critical and stern, but not really personal. You may have interpreted it as that, but I seriously doubt it was the intention. I'd like to propose an alternative to Hanlon's razor, the Internet razor: Never attribute to malice that which is adequately explained by lack of context in online conversations. Online, there is no tone of voice, facial expressions, or extra context to really help distinguish intent. Misinterpreting has been a classic issue that's been around for ages and has only gotten worse. When writing a message, we're responsible for ensuring that the intent is clearly portrayed. When reading a message, we're responsible for correctly interpreting such intent, and everyone is usually better off if, when in doubt, the interpretation leans towards ambiguity over malice. On Sun, Aug 12, 2018, 11:57 PM Abe Dillon wrote: > [Alex Walters] > >> He is questioning the concept that the lambda keyword has caused any >> harm. You assert that it caused minor harm. Minor harm can still be real, >> significant, and non-trivial. > > What, exactly, is the difference between "minor" and "non-trivial" and > when did I say the harm was "significant and non-trivial"? > > [Alex Walters] > >> You will find no evidence to support your argument. >> > You could read what I wrote to Neil Girdhar who was able to engage with me > without implying that I've lost my mind. > > [Chris Angelico] > >> If your reaction was extreme, saying so isn't attacking you. > > Is this a hypothetical now? I said "*I think* they would (or do in the > case of 'lambda') harm Python." I wasn't aware the word "harm" was > something only deranged maniacs use. > > [Chris Angelico] > >> Explain, please, what the HARM is that comes from the use of the word >> "lambda". > > > I HAVE. > > [Chris Angelico] > >> Also, the signature is most decidedly NOT obvious from context > > Who decided this? It's been decided by some committee? When you write a > key function, you don't know how many arguments are going to be passed? > > [Chris Angelico] > >> nor is it insignificant. > > > I never said it was. I just said that the logic is more important from the > standpoint of the reader. > > [Chris Angelico] > >> Putting it first gives context to the body of the >> function. Python made the correct choice here. > > > I disagree. > > This forum is looking more and more toxic. I've explained myself over and > over again. I just wanted to +1 Steven's original comment. This is > ridiculous. I guess I've pissed of the good-old-boys by calling out > Steven's unnecessary condescension. Great. It looks like Python is in > fantastic hands. > > On Sun, Aug 12, 2018 at 10:50 PM, Chris Angelico wrote: > >> On Mon, Aug 13, 2018 at 1:31 PM, Abe Dillon wrote: >> > [Steven D'Aprano] >> >> >> >> Just because I challenge your statements doesn't mean I'm attacking >> you. >> > >> > >> > No. Telling me I'm having an extreme overreaction means you're >> attacking me. >> >> If your reaction was extreme, saying so isn't attacking you. >> >> > [Steven D'Aprano] >> >> >> >> You've said that the choice of keyword, "lambda", has caused harm. >> Given >> >> the chance to clarify what you meant, you stood by your comment that >> the >> >> choice of keyword "lambda" has done real, significant, non-trivial harm >> >> to Python (the language, or the community). >> > >> > >> > What are you talking about? I explained exactly what I meant: >> > >> >> I think there are better ways that anonymous functions could have been >> >> implemented. I've already said in past discussions, I think the >> expression >> >> should come before the signature because the signature is often >> obvious from >> >> context so placing it before the logic is kinda noisy. I don't know >> what the >> >> best syntax would have been, but I refuse to believe that an esoteric >> word >> >> from an esoteric branch of calculus with an arbitrary etymology was the >> >> absolute best choice available. I think the harm that choice caused is >> >> relatively minor, but I don't think it was a great choice. >> > >> > >> > Notice: I never said "real, significant, non-trivial harm" anywhere in >> this >> > entire discussion. I never said anything close to that. Stop jamming >> > bullshit in my mouth to suit your narrative that I'm "extremely >> > overreacting". It's not cute. >> >> Explain, please, what the HARM is that comes from the use of the word >> "lambda". In contrast, using the word "function" does definitely have >> harm, because you can no longer use the name "function" as a variable >> or parameter. >> >> Also, the signature is most decidedly NOT obvious from context, nor is >> it insignificant. Putting it first gives context to the body of the >> function. Python made the correct choice here. >> >> > [Steven D'Aprano] >> >> >> >> But we ought to "check our privilege", as they say. I think that if we >> >> as a community automatically reject any word because it isn't "plain >> >> English", that would be a sign of unexamined privilege and quite rude >> to >> >> boot. >> > >> > >> > Rude? Who would it be rude to if we had chosen "anonfunc" instead of >> > "lambda"? >> >> No, but it's no less jargonny. >> >> > Very few of us are computer scientists by profession. That's not even >> where >> > 'lambda' comes from. In computer science, it's called an "anonymous >> > function". "lambda" comes from lambda calculus. >> >> https://en.wikipedia.org/wiki/Anonymous_function >> >> "In computer programming, an anonymous function (function literal, >> lambda abstraction, or lambda expression) is a function definition >> that is not bound to an identifier." >> >> So... I would say "lambda" is very firmly connected with anonymous >> functions. >> >> ChrisA >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Ryan (????) Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else https://refi64.com/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Mon Aug 13 01:25:57 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 13 Aug 2018 00:25:57 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: [Chris Angelico] > lst.onselect = anonfunc(print(target_item)) > What's target_item? If you can't see the signature and see that it's a > parameter, you should look externally for it. If you're not even going to read the explanation I've already given, then I have no reason to respond. Your example looks nothing like what I've suggested and this whole conversation is being derailed by your need to win the argument. On Mon, Aug 13, 2018 at 12:04 AM, Chris Angelico wrote: > On Mon, Aug 13, 2018 at 2:56 PM, Abe Dillon wrote: > > [Chris Angelico] > >> > >> Also, the signature is most decidedly NOT obvious from context > > > > Who decided this? It's been decided by some committee? When you write a > key > > function, you don't know how many arguments are going to be passed? > > lst.onselect = anonfunc(print(target_item)) > > What's target_item? If you can't see the signature and see that it's a > parameter, you should look externally for it. What are the parameters > to an onselect function? Doesn't that seem important enough to see the > signature up front? > > It's not just *how many* arguments are being passed. It's what they're > called, too. You cannot interpret the body of a function without > knowing that. Hiding that off to the end would make the language > worse, not better. > > Plus, can you name any similar language that does that? Every other > language I can think of has the parameters before the body. While this > isn't a clinching argument by any means (Python has a different > argument order for the ternary if operator, for instance), it's > indicative. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Mon Aug 13 01:27:38 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Mon, 13 Aug 2018 09:27:38 +0400 Subject: [Python-ideas] Reminder about intent of messages (Was: Syntactic sugar to declare partial functions) In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: it becomes "toxic" only after off-topic. fine list needs just a reminder from time to time ! Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Mon Aug 13 01:32:39 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Mon, 13 Aug 2018 01:32:39 -0400 Subject: [Python-ideas] Reminder about intent of messages (Was: Syntactic sugar to declare partial functions) In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: I don't really want to get involved in this, but I feel like everyone is piling up on Abe unfairly. On Mon, Aug 13, 2018 at 1:14 AM Ryan Gonzalez wrote: > Now that the discussion has officially devolved into something that has > absolutely nothing to do with the original topic, I'd like to point out > something: (Note that I have no affiliation with the managers of this > mailing list at all and am just posting this as an outsider.) > > In Steven D'Aprano's original message, I didn't see anything there as > being a personal attack or as having an angry tone, at least based on his > normal posting style. Maybe a bit critical and stern, but not really > personal. You may have interpreted it as that, but I seriously doubt it was > the intention. > When Abe wrote just this: "but I think they would (or do in the case of 'lambda') harm Python" ? which is nothing but an opinion. We're all welcome to our opinions without having to prove them like lawyers. Steve replied this: "That's an extreme overreaction. Do you mean to imply that there are people who looked at Python, loved the language, but decided to use something else because they didn't like the choice of the keyword "lambda"? If not, in what way is Python harmed? Would it be faster if the keyword was "function", or use less memory, or more expressive?" To my perhaps tender Canadian ears, that is incredibly abrasive. Steve could have just explained why he felt differently without slamming Abe's opinion as "an extreme overreaction" and then diving into a set of rhetorical questions that assume an extreme reading of Abe's statement. Now, as you say, this is Steve's usual posting style. But new people don't know him. I also found him quite abrasive when I started posting here, but then I noticed that it's not personal and he treats everyone this way. There are some great posters here, and I like to read python-ideas because I learn so much from them: Nick, Antoine, Brett, and Nathaniel to name a few, but there are many more. I think it's important for newcomers to try to be respectful, but it's also important to treat newcomers with the same kindness you would treat a guest in your home. Best, Neil > I'd like to propose an alternative to Hanlon's razor, the Internet razor: > > Never attribute to malice that which is adequately explained by lack of > context in online conversations. > > Online, there is no tone of voice, facial expressions, or extra context to > really help distinguish intent. Misinterpreting has been a classic issue > that's been around for ages and has only gotten worse. When writing a > message, we're responsible for ensuring that the intent is clearly > portrayed. When reading a message, we're responsible for correctly > interpreting such intent, and everyone is usually better off if, when in > doubt, the interpretation leans towards ambiguity over malice. > > On Sun, Aug 12, 2018, 11:57 PM Abe Dillon wrote: > >> [Alex Walters] >> >>> He is questioning the concept that the lambda keyword has caused any >>> harm. You assert that it caused minor harm. Minor harm can still be real, >>> significant, and non-trivial. >> >> What, exactly, is the difference between "minor" and "non-trivial" and >> when did I say the harm was "significant and non-trivial"? >> >> [Alex Walters] >> >>> You will find no evidence to support your argument. >>> >> You could read what I wrote to Neil Girdhar who was able to engage with >> me without implying that I've lost my mind. >> >> [Chris Angelico] >> >>> If your reaction was extreme, saying so isn't attacking you. >> >> Is this a hypothetical now? I said "*I think* they would (or do in the >> case of 'lambda') harm Python." I wasn't aware the word "harm" was >> something only deranged maniacs use. >> >> [Chris Angelico] >> >>> Explain, please, what the HARM is that comes from the use of the word >>> "lambda". >> >> >> I HAVE. >> >> [Chris Angelico] >> >>> Also, the signature is most decidedly NOT obvious from context >> >> Who decided this? It's been decided by some committee? When you write a >> key function, you don't know how many arguments are going to be passed? >> >> [Chris Angelico] >> >>> nor is it insignificant. >> >> >> I never said it was. I just said that the logic is more important from >> the standpoint of the reader. >> >> [Chris Angelico] >> >>> Putting it first gives context to the body of the >>> function. Python made the correct choice here. >> >> >> I disagree. >> >> This forum is looking more and more toxic. I've explained myself over and >> over again. I just wanted to +1 Steven's original comment. This is >> ridiculous. I guess I've pissed of the good-old-boys by calling out >> Steven's unnecessary condescension. Great. It looks like Python is in >> fantastic hands. >> >> On Sun, Aug 12, 2018 at 10:50 PM, Chris Angelico >> wrote: >> >>> On Mon, Aug 13, 2018 at 1:31 PM, Abe Dillon wrote: >>> > [Steven D'Aprano] >>> >> >>> >> Just because I challenge your statements doesn't mean I'm attacking >>> you. >>> > >>> > >>> > No. Telling me I'm having an extreme overreaction means you're >>> attacking me. >>> >>> If your reaction was extreme, saying so isn't attacking you. >>> >>> > [Steven D'Aprano] >>> >> >>> >> You've said that the choice of keyword, "lambda", has caused harm. >>> Given >>> >> the chance to clarify what you meant, you stood by your comment that >>> the >>> >> choice of keyword "lambda" has done real, significant, non-trivial >>> harm >>> >> to Python (the language, or the community). >>> > >>> > >>> > What are you talking about? I explained exactly what I meant: >>> > >>> >> I think there are better ways that anonymous functions could have been >>> >> implemented. I've already said in past discussions, I think the >>> expression >>> >> should come before the signature because the signature is often >>> obvious from >>> >> context so placing it before the logic is kinda noisy. I don't know >>> what the >>> >> best syntax would have been, but I refuse to believe that an esoteric >>> word >>> >> from an esoteric branch of calculus with an arbitrary etymology was >>> the >>> >> absolute best choice available. I think the harm that choice caused is >>> >> relatively minor, but I don't think it was a great choice. >>> > >>> > >>> > Notice: I never said "real, significant, non-trivial harm" anywhere in >>> this >>> > entire discussion. I never said anything close to that. Stop jamming >>> > bullshit in my mouth to suit your narrative that I'm "extremely >>> > overreacting". It's not cute. >>> >>> Explain, please, what the HARM is that comes from the use of the word >>> "lambda". In contrast, using the word "function" does definitely have >>> harm, because you can no longer use the name "function" as a variable >>> or parameter. >>> >>> Also, the signature is most decidedly NOT obvious from context, nor is >>> it insignificant. Putting it first gives context to the body of the >>> function. Python made the correct choice here. >>> >>> > [Steven D'Aprano] >>> >> >>> >> But we ought to "check our privilege", as they say. I think that if we >>> >> as a community automatically reject any word because it isn't "plain >>> >> English", that would be a sign of unexamined privilege and quite rude >>> to >>> >> boot. >>> > >>> > >>> > Rude? Who would it be rude to if we had chosen "anonfunc" instead of >>> > "lambda"? >>> >>> No, but it's no less jargonny. >>> >>> > Very few of us are computer scientists by profession. That's not even >>> where >>> > 'lambda' comes from. In computer science, it's called an "anonymous >>> > function". "lambda" comes from lambda calculus. >>> >>> https://en.wikipedia.org/wiki/Anonymous_function >>> >>> "In computer programming, an anonymous function (function literal, >>> lambda abstraction, or lambda expression) is a function definition >>> that is not bound to an identifier." >>> >>> So... I would say "lambda" is very firmly connected with anonymous >>> functions. >>> >>> ChrisA >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -- > > Ryan (????) > Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else > https://refi64.com/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/jOMinivFCcQ/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From solipsis at pitrou.net Mon Aug 13 06:28:47 2018 From: solipsis at pitrou.net (Antoine Pitrou) Date: Mon, 13 Aug 2018 12:28:47 +0200 Subject: [Python-ideas] Toxic forum References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: <20180813122847.24a9df01@fsol> On Sun, 12 Aug 2018 23:56:24 -0500 Abe Dillon wrote: > > This forum is looking more and more toxic. I've explained myself over and > over again. I just wanted to +1 Steven's original comment. This is > ridiculous. I guess I've pissed of the good-old-boys by calling out > Steven's unnecessary condescension. Great. It looks like Python is in > fantastic hands. My experience is that this forum was toxic almost from the start, because it encourages people to engage into the kind of behaviour you are witnessing now (i.e. largely pointless and semi-agressive nit-picking which sometimes feels straight out of the well-known Argument Clinic sketch). Regards Antoine. From levkivskyi at gmail.com Mon Aug 13 07:08:29 2018 From: levkivskyi at gmail.com (Ivan Levkivskyi) Date: Mon, 13 Aug 2018 12:08:29 +0100 Subject: [Python-ideas] Consider adding an iterable option to dataclass In-Reply-To: <25c9112a-f9a0-6c02-d0a9-ea2998914395@trueblade.com> References: <25c9112a-f9a0-6c02-d0a9-ea2998914395@trueblade.com> Message-ID: On 11 August 2018 at 01:29, Eric V. Smith wrote: > On 8/10/2018 7:01 PM, Neil Girdhar wrote: > >> [...] > > [...] > >> sequence would simply inherit from collections.abc.Sequence and implement >> the two methods __len__ and __getitme__. >> > > Unless I'm misunderstanding you, this falls in to the same problem as > setting __slots__: you need to return a new class, in this case since you > can't add inheritance after the fact. I don't think __isinstancecheck__ > helps you here, but maybe I'm missing something (I'm not a big user of > inheritance or ABCs). > > Here are three points to add: 1. collections.abc.Sequence doesn't have a __subclasshook__, i.e. it doesn't support structural behaviour. There was an idea as a part of PEP 544 to make Sequence and Mapping structural, but it was rejected after all. 2. Mutating __bases__ doesn't require creating a new class. So one can just add Sequence after creation. That said, I don't like this idea, `typing` used to do some manipulations with bases, and it caused several confusions and subtle bugs, until it was "standardised" in PEP 560. 3. In my experience with some real life code the most used tuple API in named tuples is unpacking, for example: class Row(NamedTuple): id: int name: str rows: List[Row] for id, name in rows: ... I proposed to add it some time ago in https://github.com/ericvsmith/dataclasses/issues/21, it will be enough to just generate an __iter__ (btw such classes will be automatically subclasses of collections.abc.Iterable, which is structural): @data(iterable=True)class Point: x: int y: int origin = Point(0, 0) x, y = origin But this idea was postponed/deferred. Maybe we can reconsider it? -- Ivan -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Mon Aug 13 07:40:09 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Mon, 13 Aug 2018 12:40:09 +0100 Subject: [Python-ideas] Toxic forum In-Reply-To: <20180813122847.24a9df01@fsol> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: On Mon, 13 Aug 2018 at 11:30, Antoine Pitrou wrote: > > On Sun, 12 Aug 2018 23:56:24 -0500 > Abe Dillon wrote: > > > > This forum is looking more and more toxic. I've explained myself over and > > over again. I just wanted to +1 Steven's original comment. This is > > ridiculous. I guess I've pissed of the good-old-boys by calling out > > Steven's unnecessary condescension. Great. It looks like Python is in > > fantastic hands. > > My experience is that this forum was toxic almost from the start, > because it encourages people to engage into the kind of behaviour you > are witnessing now (i.e. largely pointless and semi-agressive > nit-picking which sometimes feels straight out of the well-known > Argument Clinic sketch). IMO, things have got worse over time. As a forum explicitly designed for discussing speculative ideas, the general tone has become less and less sympathetic towards people (particularly newcomers, which is especially unfortunate) expressing ideas which are, shall we say, less than perfectly thought through. I'm OK with gently pointing out to a poster that they will need to tighten up their arguments and assertions as the discussion progresses towards a concrete proposal, but that's not how things feel any more. In particular there seems to be an extremely aggressive dislike of anything that seems like "opinion" which can't be backed up with solid evidence. Certainly we don't expect proposals based purely on subjective opinion to make it through to implementation, but we shouldn't be holding the process of exploring ideas to such rigorous standards. Anyway, I won't say any more, as I don't really know how we could change things. And yes, a lot of the above is my view, and is subjective. Asking me to provide evidence and back up my assertions sort of proves my point, so please treat it as just that, my opinion, and take it or leave it on that basis. Paul From nicholas.chammas at gmail.com Mon Aug 13 08:58:41 2018 From: nicholas.chammas at gmail.com (Nicholas Chammas) Date: Mon, 13 Aug 2018 08:58:41 -0400 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: >From what I?ve seen on this list in my relatively brief time here, this forum is mostly fine and the participants generally behave like adults. I don?t read every thread, so maybe I don?t have an accurate picture. From what I?ve seen, there is the occasional spat, where people just need to step away from the keyboard for a bit and cool off, but I wouldn?t consider the environment toxic. That seems like too strong a word. What I feel we lack are better tools for checking bad behavior and nudging people in the right direction, apart from having discussions like this. Temporarily locking threads that have become heated comes to mind. As do temporary bans for rowdy members. As does closing threads that have ceased to serve any good purpose. These things would have been pretty handy in several recent and heated discussions, including the PEP 505 one I participated in a couple of weeks ago. How much of this is possible on a mailing list? I don?t know. But I remember a year or two ago there was a proposal to move python-ideas to a different format, perhaps a Discourse forum or similar, which would provide some handy administration tools and other UX improvements. That discussion, ironically, was beset by some of the very animosity that better tooling would help control. (And I learned a bit about email etiquette and top-posting...) Maybe we need to revive that discussion? Overall, I don?t think we have a people problem on this list as much as we have an administration tooling problem. -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Mon Aug 13 12:31:27 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Mon, 13 Aug 2018 20:31:27 +0400 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: normally at above 20+ posts it gets crazy Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From mike at selik.org Mon Aug 13 13:06:23 2018 From: mike at selik.org (Michael Selik) Date: Mon, 13 Aug 2018 10:06:23 -0700 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: On Mon, Aug 13, 2018, 5:59 AM Nicholas Chammas wrote: > Maybe we need to revive that discussion? Overall, I don?t think we have a > people problem on this list as much as we have an administration tooling > problem. > +1 Even the fact that "straw poll" votes aren't counted automatically shows that better tools could help. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Mon Aug 13 13:09:44 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 14 Aug 2018 03:09:44 +1000 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: On Tue, Aug 14, 2018 at 3:06 AM, Michael Selik wrote: > > > On Mon, Aug 13, 2018, 5:59 AM Nicholas Chammas > wrote: >> >> Maybe we need to revive that discussion? Overall, I don?t think we have a >> people problem on this list as much as we have an administration tooling >> problem. > > > +1 > > Even the fact that "straw poll" votes aren't counted automatically shows > that better tools could help. > How often are straw polls actually needed? The popular vote is almost entirely meaningless. ChrisA From mike at selik.org Mon Aug 13 13:11:08 2018 From: mike at selik.org (Michael Selik) Date: Mon, 13 Aug 2018 10:11:08 -0700 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: Something that limits posts to once per day per thread could be useful, maybe even once per week. On Mon, Aug 13, 2018, 10:06 AM Michael Selik wrote: > > > On Mon, Aug 13, 2018, 5:59 AM Nicholas Chammas > wrote: > >> Maybe we need to revive that discussion? Overall, I don?t think we have a >> people problem on this list as much as we have an administration tooling >> problem. >> > > +1 > > Even the fact that "straw poll" votes aren't counted automatically shows > that better tools could help. > >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From mike at selik.org Mon Aug 13 13:12:31 2018 From: mike at selik.org (Michael Selik) Date: Mon, 13 Aug 2018 10:12:31 -0700 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: On Mon, Aug 13, 2018, 10:09 AM Chris Angelico wrote: > On Tue, Aug 14, 2018 at 3:06 AM, Michael Selik wrote: > > > > > > On Mon, Aug 13, 2018, 5:59 AM Nicholas Chammas < > nicholas.chammas at gmail.com> > > wrote: > >> > >> Maybe we need to revive that discussion? Overall, I don?t think we have > a > >> people problem on this list as much as we have an administration tooling > >> problem. > > > > > > +1 > > > > Even the fact that "straw poll" votes aren't counted automatically shows > > that better tools could help. > > > > How often are straw polls actually needed? The popular vote is almost > entirely meaningless. > That fact is not obvious. It's frustrating to find oneself engaging in meaningless discussion. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Mon Aug 13 13:18:19 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 13 Aug 2018 12:18:19 -0500 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: This is a half-baked thought, but perhaps a sub-reddit would facilitate better moderation and we'd get the bonus of threaded discussions and a side-bar for ediquite and other important info. I know Reddit has a mixed reputation, but some of the best moderated subs like /r/science and /r/neutralpolitics have fantastic discussions. We could open /r/pythonideas and see if it gains traction. We also have the skill set to write a pretty good moderation bot. On Mon, Aug 13, 2018, 12:11 PM Michael Selik wrote: > Something that limits posts to once per day per thread could be useful, > maybe even once per week. > > > On Mon, Aug 13, 2018, 10:06 AM Michael Selik wrote: > >> >> >> On Mon, Aug 13, 2018, 5:59 AM Nicholas Chammas < >> nicholas.chammas at gmail.com> wrote: >> >>> Maybe we need to revive that discussion? Overall, I don?t think we have >>> a people problem on this list as much as we have an administration tooling >>> problem. >>> >> >> +1 >> >> Even the fact that "straw poll" votes aren't counted automatically shows >> that better tools could help. >> >>> _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Mon Aug 13 13:22:14 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Mon, 13 Aug 2018 21:22:14 +0400 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: some mods warnings or reminders might also help ! Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Mon Aug 13 13:23:56 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Mon, 13 Aug 2018 18:23:56 +0100 Subject: [Python-ideas] Python Community Code of Conduct Message-ID: https://www.python.org/psf/codeofconduct/ Python Community Code of Conduct The Python community is made up of members from around the globe with a diverse set of skills, personalities, and experiences. It is through these differences that our community experiences great successes and continued growth. When you're working with members of the community, we encourage you to follow these guidelines which help steer our interactions and strive to keep Python a positive, successful, and growing community. A member of the Python community is: Open Members of the community are open to collaboration, whether it's on PEPs, patches, problems, or otherwise. We're receptive to constructive comment and criticism, as the experiences and skill sets of other members contribute to the whole of our efforts. We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference. Considerate Members of the community are considerate of their peers -- other Python users. We're thoughtful when addressing the efforts of others, keeping in mind that often times the labor was completed simply for the good of the community. We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views. Respectful Members of the community are respectful. We're respectful of others, their positions, their skills, their commitments, and their efforts. We're respectful of the volunteer efforts that permeate the Python community. We're respectful of the processes set forth in the community, and we work within them. When we disagree, we are courteous in raising our issues. Overall, we're good to each other. We contribute to this community not because we have to, but because we want to. If we remember that, these guidelines will come naturally. Questions/comments/reports? Please write to psf at python.org. Note: this email address is to all of the PSF Board of Directors and the PSF Staff. Alternatively, you may reach Ewa Jodlowska, Director of Operations, at ewa at python.org. From tritium-list at sdamon.com Mon Aug 13 13:41:52 2018 From: tritium-list at sdamon.com (Alex Walters) Date: Mon, 13 Aug 2018 13:41:52 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: <9176901d4332c$ec47c0d0$c4d74270$@sdamon.com> > -----Original Message----- > From: Python-ideas list=sdamon.com at python.org> On Behalf Of Abe Dillon > Sent: Monday, August 13, 2018 12:56 AM > To: Chris Angelico > Cc: Python-Ideas > Subject: Re: [Python-ideas] Syntactic sugar to declare partial functions > > [Alex Walters] > > > He is questioning the concept that the lambda keyword has caused > any harm. You assert that it caused minor harm. Minor harm can still be real, > significant, and non-trivial. > > What, exactly, is the difference between "minor" and "non-trivial" and when > did I say the harm was "significant and non-trivial"? > > [Alex Walters] > > > You will find no evidence to support your argument. > > > You could read what I wrote to Neil Girdhar who was able to engage with me > without implying that I've lost my mind. I never said or implied that you lost your mind. Only that you were wrong. It is possible to be wrong and sane. However if you really insist that the two are one in the same... you might actually need to seek out professional help. > > [Chris Angelico] > > > If your reaction was extreme, saying so isn't attacking you. > > Is this a hypothetical now? I said "I think they would (or do in the case of > 'lambda') harm Python." I wasn't aware the word "harm" was something only > deranged maniacs use. > > > [Chris Angelico] > > > Explain, please, what the HARM is that comes from the use of the > word > "lambda". > > > I HAVE. > > [Chris Angelico] > > > Also, the signature is most decidedly NOT obvious from context > > Who decided this? It's been decided by some committee? When you write a > key function, you don't know how many arguments are going to be passed? > > [Chris Angelico] > > > nor is it insignificant. > > > I never said it was. I just said that the logic is more important from the > standpoint of the reader. > > [Chris Angelico] > > > Putting it first gives context to the body of the > function. Python made the correct choice here. > > > I disagree. > > This forum is looking more and more toxic. I've explained myself over and > over again. I just wanted to +1 Steven's original comment. This is ridiculous. I > guess I've pissed of the good-old-boys by calling out Steven's unnecessary > condescension. Great. It looks like Python is in fantastic hands. > > On Sun, Aug 12, 2018 at 10:50 PM, Chris Angelico > wrote: > > > On Mon, Aug 13, 2018 at 1:31 PM, Abe Dillon > wrote: > > [Steven D'Aprano] > >> > >> Just because I challenge your statements doesn't mean I'm > attacking you. > > > > > > No. Telling me I'm having an extreme overreaction means you're > attacking me. > > If your reaction was extreme, saying so isn't attacking you. > > > [Steven D'Aprano] > >> > >> You've said that the choice of keyword, "lambda", has caused > harm. Given > >> the chance to clarify what you meant, you stood by your > comment that the > >> choice of keyword "lambda" has done real, significant, non-trivial > harm > >> to Python (the language, or the community). > > > > > > What are you talking about? I explained exactly what I meant: > > > >> I think there are better ways that anonymous functions could > have been > >> implemented. I've already said in past discussions, I think the > expression > >> should come before the signature because the signature is often > obvious from > >> context so placing it before the logic is kinda noisy. I don't know > what the > >> best syntax would have been, but I refuse to believe that an > esoteric word > >> from an esoteric branch of calculus with an arbitrary etymology > was the > >> absolute best choice available. I think the harm that choice caused > is > >> relatively minor, but I don't think it was a great choice. > > > > > > Notice: I never said "real, significant, non-trivial harm" anywhere in > this > > entire discussion. I never said anything close to that. Stop jamming > > bullshit in my mouth to suit your narrative that I'm "extremely > > overreacting". It's not cute. > > Explain, please, what the HARM is that comes from the use of the > word > "lambda". In contrast, using the word "function" does definitely have > harm, because you can no longer use the name "function" as a > variable > or parameter. > > Also, the signature is most decidedly NOT obvious from context, nor > is > it insignificant. Putting it first gives context to the body of the > function. Python made the correct choice here. > > > [Steven D'Aprano] > >> > >> But we ought to "check our privilege", as they say. I think that if > we > >> as a community automatically reject any word because it isn't > "plain > >> English", that would be a sign of unexamined privilege and quite > rude to > >> boot. > > > > > > Rude? Who would it be rude to if we had chosen "anonfunc" > instead of > > "lambda"? > > No, but it's no less jargonny. > > > Very few of us are computer scientists by profession. That's not > even where > > 'lambda' comes from. In computer science, it's called an > "anonymous > > function". "lambda" comes from lambda calculus. > > https://en.wikipedia.org/wiki/Anonymous_function > > > "In computer programming, an anonymous function (function literal, > lambda abstraction, or lambda expression) is a function definition > that is not bound to an identifier." > > So... I would say "lambda" is very firmly connected with anonymous > functions. > > ChrisA > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > From stefan_ml at behnel.de Mon Aug 13 13:46:49 2018 From: stefan_ml at behnel.de (Stefan Behnel) Date: Mon, 13 Aug 2018 19:46:49 +0200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: Michel Desmoulin schrieb am 09.08.2018 um 18:59: > I'd rather have functools.partial() to be added as a new method on > function objects. > >> from functools import partial >> >> def add(x:int,y:int)->int: >> returnx +y >> >> add_2 = partial(add,2) > > Would become: > > add_2 = add.partial(2) Except that this only works for functions, not for other callables. Meaning, code that uses this for anything but its self-defined functions will break as soon as someone passes in a callable object that is not a function. Stefan From bruce at leban.us Mon Aug 13 14:00:57 2018 From: bruce at leban.us (Bruce Leban) Date: Mon, 13 Aug 2018 11:00:57 -0700 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On Sun, Aug 12, 2018 at 8:31 PM, Abe Dillon wrote: > > [Steven D'Aprano] > >> ...if we aren't even willing to move out of our own comfort zone to >> the extent of learning accurate jargon terms from our own profession? > > > Very few of us are computer scientists by profession. That's not even > where 'lambda' comes from. In computer science, it's called an "anonymous > function". "lambda" comes from lambda calculus. > Lambda calculus IS computer science. Rejecting lambda as CS is as bad as rejecting the + operator because that's mathematics. I can legitimately argue that + in Python is not the + in mathematics because the Python mathematical operators operate on integers and floats, not real numbers. Therefore we should use a different word like "floatadd". Of course not. Lambda calculus is a model of computation. It was invented about 30 years before the name "computer science" but is nonetheless foundational computer science. If using lambda as a keyword leads people to go and learn about lambda calculus that is a good thing. And as to saying a lambda function is an "anonymous function": the anonymity is not a property of the function. If I assign it to a name, it's no longer anonymous. Really a "lambda" or "lambda function" is just a function, but "lambda" is a synecdoche for "function created with a lambda expression". --- Bruce -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Mon Aug 13 14:09:55 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 14 Aug 2018 04:09:55 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On Tue, Aug 14, 2018 at 4:00 AM, Bruce Leban wrote: > And as to saying a lambda function is an "anonymous function": the anonymity > is not a property of the function. If I assign it to a name, it's no longer > anonymous. Really a "lambda" or "lambda function" is just a function, but > "lambda" is a synecdoche for "function created with a lambda expression". True, but at that point, you get into hairy points of definitions. Which of these functions is anonymous? def do_stuff(callback): ... do_stuff(do_stuff) do_stuff(lambda: 42) do_stuff(callback=lambda: 42) Obviously do_stuff itself has a name. When you pass it a parameter, it can access that as "callback", which means the function has been assigned to a name. Does it cease to be anonymous? What if you use a keyword argument? Within Python, there's a fairly clear definition: if there is something in the source code which sets the function's __name__ attribute, it's not an anonymous function. So anonymous functions come from: * Lambda expressions, always called "" * Comprehensions/genexps, always called "" etc * Callable objects that aren't functions (or classes, since those have names) * Maybe something else that I've forgotten. You're absolutely right that a "lambda function" isn't really a thing, in the same way that Python doesn't have "raw strings" (only "raw string literals", which are literals which result in perfectly ordinary strings). But the anonymity of them is a somewhat measurable feature, even if it isn't very important. The distinction between "lambda functions" and "def functions" is important to style guides, but otherwise shouldn't matter. ChrisA From abedillon at gmail.com Mon Aug 13 15:08:39 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 13 Aug 2018 14:08:39 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: [Bruce Leban] > Lambda calculus IS computer science. It's a foundation of computer science. That doesn't mean it "IS" computer science. Set theory is a foundation of computer science. It's still it's own discipline. [Bruce Leban] > Rejecting lambda as CS is as bad as rejecting the + operator because > that's mathematics. This is a complete misunderstanding of my argument. Not all programmers are computer scientists. In fact, not all programmers are professional. Many, including myself, came from engineering. Many came from other scientific fields. Many came from finance and all sorts of fields. Many are teenagers who just want to build a cool website or a video game or scrape song lyrics for their favorite bands. The whole point of a programming language is to bridge the gap between machine code and natural language (in Python's case English, as with most other languages). It's to make reading and writing code easier through abstraction, not to create ivory towers through the use of esoteric jargon. It's not supposed to make a cool kids club for people privileged enough to study CS in college. At least that's not my goal. [Bruce Leban] > Lambda calculus is a model of computation. It was invented about 30 years > before the name "computer science" but is nonetheless foundational computer > science. Yes. I know. [Bruce Leban] > If using lambda as a keyword leads people to go and learn about lambda > calculus that is a good thing. I don't think the point of Python is to force people to eat their vegetables. You might think it's a good thing if everyone learns about Turing machines and the Halting problem and Kolmogorov Complexity and X86 machine code, etc. but that's not what Python is for. I may think that everyone should learn what I learned in college about electromagnetics and semiconductor physics, etc. But I'm not arrogant enough to force that on people who just want to use abstract tools to get some job done. I didn't realize that my distaste for 'lambda' was such an unheard-of opinion. I could have sworn that the likes of Guido Van Rossum and Raymond Hetinger also found the term at least a little troublesome. As someone who has taught Python professionally, I can say that there is a strange mental block regarding lambda expressions. Pretty much every student I've had has struggled with lambda expressions, even those who grasp similarly complex constructs like decorators with ease. This includes students who learned english as a second language. I can only attribute that to the word 'lambda' being confusing as hell. [Bruce Leban] > And as to saying a lambda function is an "anonymous function": the > anonymity is not a property of the function. Yes, It is: >>> def func(x): return x*x >>> func.__name__ 'func' >>> func = lambda x: x*x >>> func.__name__ '' [Bruce Leban] > If I assign it to a name, it's no longer anonymous. That's not how variable assignment works in Python. The name of the variable doesn't become an attribute of the object assigned to the variable. [Bruce Leban] > I can legitimately argue that + in Python is not the + in mathematics > because the Python mathematical operators operate on integers and floats, > not real numbers. Therefore we should use a different word like "floatadd". > Of course not. My whole point was to be less pedantic, not more pedantic. Pragmatism should prevail over pedantry. This is why, as I've stated earlier, I know that lambda expressions aren't going to change any time soon and I'm fine with that. I consider it a bit of a wart, but whatever. I'm getting really tired of having to defend this opinion. Also, this argument makes no sense. Just because there isn't a way to represent all real numbers in a computer, doesn't mean that integer, floating point, and fractional addition become different kinds of addition. On Mon, Aug 13, 2018 at 1:09 PM, Chris Angelico wrote: > On Tue, Aug 14, 2018 at 4:00 AM, Bruce Leban wrote: > > And as to saying a lambda function is an "anonymous function": the > anonymity > > is not a property of the function. If I assign it to a name, it's no > longer > > anonymous. Really a "lambda" or "lambda function" is just a function, but > > "lambda" is a synecdoche for "function created with a lambda expression". > > True, but at that point, you get into hairy points of definitions. > Which of these functions is anonymous? > > def do_stuff(callback): ... > > do_stuff(do_stuff) > do_stuff(lambda: 42) > do_stuff(callback=lambda: 42) > > Obviously do_stuff itself has a name. When you pass it a parameter, it > can access that as "callback", which means the function has been > assigned to a name. Does it cease to be anonymous? What if you use a > keyword argument? > > Within Python, there's a fairly clear definition: if there is > something in the source code which sets the function's __name__ > attribute, it's not an anonymous function. So anonymous functions come > from: > > * Lambda expressions, always called "" > * Comprehensions/genexps, always called "" etc > * Callable objects that aren't functions (or classes, since those have > names) > * Maybe something else that I've forgotten. > > You're absolutely right that a "lambda function" isn't really a thing, > in the same way that Python doesn't have "raw strings" (only "raw > string literals", which are literals which result in perfectly > ordinary strings). But the anonymity of them is a somewhat measurable > feature, even if it isn't very important. The distinction between > "lambda functions" and "def functions" is important to style guides, > but otherwise shouldn't matter. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Mon Aug 13 15:17:23 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 14 Aug 2018 05:17:23 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On Tue, Aug 14, 2018 at 5:08 AM, Abe Dillon wrote: > The whole point of a programming language is to bridge the gap between > machine code and natural language (in Python's case English, as with most > other languages). It's to make reading and writing code easier through > abstraction, not to create ivory towers through the use of esoteric jargon. > It's not supposed to make a cool kids club for people privileged enough to > study CS in college. At least that's not my goal. The whole point of a car is to make driving easier through abstracting away the internal details of petrochemical propulsion, but if someone says "I don't want to know about 'gears' or 'brakes' or any of these technical terms", you wouldn't want them driving on the roads you're on. There is a certain level of comprehension that you can't avoid. (If you don't know anything about how to use a car, you can still ride in one, but you can't drive it; and you don't need to understand about anonymous functions in order to operate a computer, but you'll need them to program effectively.) > As someone who has taught Python professionally, I can say that there is a > strange mental block regarding lambda expressions. Pretty much every student > I've had has struggled with lambda expressions, even those who grasp > similarly complex constructs like decorators with ease. This includes > students who learned english as a second language. I can only attribute that > to the word 'lambda' being confusing as hell. As someone who currently teaches both Python AND JavaScript professionally, I can say that there is a strange mental block regarding anonymous functions, and it's nothing to do with the word "lambda". In JavaScript, anonymous functions are created with the word "function" (same word as is used for declared functions), and there are just as many points of confusion as there are with Python. ChrisA From turnbull.stephen.fw at u.tsukuba.ac.jp Mon Aug 13 15:20:16 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Tue, 14 Aug 2018 04:20:16 +0900 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> Message-ID: <23409.55792.906609.495552@turnbull.sk.tsukuba.ac.jp> Cleaning out the Ccs, presumably subscribed. Nicholas Chammas writes: > From what I?ve seen on this list in my relatively brief time here, > this forum is mostly fine and the participants generally behave > like adults. I don?t read every thread, so maybe I don?t have an > accurate picture. From what I?ve seen, there is the occasional > spat, where people just need to step away from the keyboard for a > bit and cool off, but I wouldn?t consider the environment > toxic. That seems like too strong a word. I would go further, and say that use of the word says more about those who used it than about the list. > What I feel we lack are better tools for checking bad behavior and > nudging people in the right direction, apart from having > discussions like this. I disagree. I think this is a scale problem: we have too many people posting, some of them new or infrequent, to prevent (1) people getting triggered by one word in an otherwise excellent post and going off in their replies, (2) intemperate rebuttals to the replies in (1), or (3) interminably long threads sustained by people who don't yet know when not to post. If (1) and (2) can be solved by moderation, then you pretty much have a toxic channel. The best solution to (3) is not channel-wide moderation, but killing/ muting the thread or specific posters in your MUA. If you're going to participate in channels as high-traffic as the Python lists, and still try to hold down a day job, this is one of the very few features where I'm willing to say "bite the damn bullet and get a REAL MUA!" It really improves life. If most people have muted the thread, there's little to no harm in letting those who still care continue. This also has the advantage that you don't have to wait for a thread to be of use to nobody to kill it. You can do that now! > These things would have been pretty handy in several recent and > heated discussions, including the PEP 505 one I participated in a > couple of weeks ago. PEP 505 was an example of none of the above as far as I can see, though. I think it's tough to find places where you could invoke a thread freeze or a poster ban and not get a storm of pushback. And it's kinda hard to see how killing a thread on an open PEP is useful. > How much of this is possible on a mailing list? Poster bans, whether temporary or indefinite, are possible. Thread freezing or closing are in principle possible, but they'd be really annoying to posters due to the nature of email, I suspect (posts would bounce and clutter up your inbox later, rather than having the "post reply" function disabled in the UI). Nor are they implemented in GNU Mailman, although spam-checking could probably be coerced to serve (ban messages where In-Reply-To or References contains recent IDs in the frozen/closed thread). This would require some additional scripts for efficient admin, and MUA tooling to extract References would be nice, but all that doable in an afternoon or two. > But I remember a year or two ago there was a proposal to move > python-ideas to a different format, perhaps a Discourse forum or > similar, which would provide some handy administration tools and > other UX improvements. Going back to that discussion now that Guido is less involved might get you a different answer. (He was not a fan of Discourse, and while he told me he likes Zulip at PyCon Cleveland, he also said he sees it as independent of the function of mailing lists. He also said Mailman 3's HyperKitty forum-like functionality sounds like it will be good enough for him soon enough, so he'd probably be opposed to moving to forum software on the "don't break what don't need fixing" principle. All that is almost moot now.) > Overall, I don?t think we have a people problem on this list as > much as we have an administration tooling problem. That's what @jack says, too. :-/ Sorry, that's a bit too snarky, but the fundamental problem is that *people* post too much. That's a *people* problem even though there are no problem people, and the people that are deciding what to post aren't the admins (unless you'll accept out-and-out censorship, or an editorial board if you prefer a euphemism). So I don't see an admin tooling solution here. Steve -- Associate Professor Division of Policy and Planning Science http://turnbull.sk.tsukuba.ac.jp/ Faculty of Systems and Information Email: turnbull at sk.tsukuba.ac.jp University of Tsukuba Tel: 029-853-5175 Tennodai 1-1-1, Tsukuba 305-8573 JAPAN From python at mrabarnett.plus.com Mon Aug 13 15:37:56 2018 From: python at mrabarnett.plus.com (MRAB) Date: Mon, 13 Aug 2018 20:37:56 +0100 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On 2018-08-13 20:08, Abe Dillon wrote: > [Bruce Leban] > > Lambda calculus IS computer science. > > It's a foundation of computer science. That doesn't mean it "IS" > computer science. Set theory is a foundation of computer science. It's > still it's own discipline. > [snip] The word "is" can mean, among other things, class membership or identify. Bruce was talking about class membership, not identity. From brett at python.org Mon Aug 13 15:38:44 2018 From: brett at python.org (Brett Cannon) Date: Mon, 13 Aug 2018 12:38:44 -0700 Subject: [Python-ideas] Conduct on python-ideas Message-ID: I'm starting a new thread on this to make sure it receives appropriate visibility for everyone on this list. *There are ramifications for those involved in this whole situation* as outlined at the end of this email. To review, this mailing list operates under the PSF Community Code of Conduct: https://www.python.org/psf/codeofconduct/ . That means everyone is expected to be open, considerate, and respectful. Titus and I have operated this list such that people who don't follow the CoC get a warning, then a temporary ban of a month or two, then a year-long ban, then a permanent ban (and we reserve the right to skip any of these steps as we see fit based on how bad the infraction was). Since the traffic here can get a bit heavy and thus we don't read every email, we rely on people reporting things as appropriate to python-ideas-owner@ if things have gotten out of hand. And boy did things get out of hand on the "Syntactic sugar to declare partial functions" thread. Here is what I saw play out (bolding is mine): ---------- [Abe] Words like 'partial', 'curry', 'lambda', and 'closure' are fine for text books, published papers, and technical discussion, *but I think they would (or do in the case of 'lambda') harm Python*. [Steven] *That's an extreme overreaction*. Do you mean to imply that there are people who looked at Python, loved the language, but decided to use something else because they didn't like the choice of the keyword "lambda"? If not, in what way is Python harmed? Would it be faster if the keyword was "function", or use less memory, or more expressive? Remember that to millions of programmers in the world, "function" is just as much an obscure foreign piece of jargon they have to memorise as "lambda" is to English-speakers. [Abe] Extreme? I thought it was a rather benign opinion.* I'm not exactly frothing at the mouth here. It's not like I'm declaring holy war on Python for using the word 'lambda'.* I just think it was a mistake (and thatdeath should come to all non-believers). [Steve] You've said that the choice of keyword, "lambda", has caused harm. Given the chance to clarify what you meant, *you stood by your comment that thechoice of keyword "lambda" has done real, significant, non-trivial harm* to Python (the language, or the community). Presumably you fear the same thing will happen again if we choose "partial" (otherwise, why raise the issue?). [Abe] Notice:* I never said "real, significant, non-trivial harm" anywhere* in this entire discussion. I never said anything close to that. *Stop jamming bullshit in my mouth* to suit your narrative that I'm "extremely overreacting". It's not cute. ---------- The way I read this going down is Abe thought something "would harm Python". "Harm" is a strong word to use, so Steven called it an "extreme overreaction". Now stating it like a fact is unnecessary, abrasive, and a bit of hyperbole. Abe thought we he thought and that's fine, but it isn't universally considered an overreaction; it was an opinion and Abe correctly stated it as such. Steven could have easily left out the hyperbole and framing like a statement of fact and still made the same point. Abe then reacted with more hyperbole as he disagreed with Steven's statement that he was overreacting. So now we are reacting to hyperbole with hyperbole. Steven then reacted by overstating the strength of Abe's initial intentions. That's a misunderstanding at best, entirely misleading at worst. At that point Abe crossed a line and basically yelled at Steven to "stop jamming bullshit in [his] mouth". So how should have this been handled? First, dropping all hyperbole, not stating opinions as facts, and not being so abrasive would have probably stopped all of this from happening. Had Steven just said "I think that's an overreaction; can you please clarify what harm you think happened?" then he would have gotten the answer he wanted and Abe would not have taken offense. Abe replying with his own hyperbole didn't help. Steven also didn't need to misrepresent what Abe said. Choosing to re-interpret what level of harm Abe meant was not appropriate (unless Steven got a bit sloppy and replied from memory instead of going back and reading the emails he was replying to). And finally, Abe's response was totally uncalled for. I don't care how out of line someone on this list is, you don't react like that. You come to Titus and me and we will handle it. If you need to, step back for an hour or day before replying if that's what it takes to not react in a rude manner. I shouldn't be having to explain to adults on how to communicate among strangers of different cultures, but here we are. I did an entire PyCon US keynote on why we need to treat open source as a series of kindnesses and react as such: https://youtu.be/tzFWz5fiVKU?t=49m29s . If we don't treat everything as a kindness then open source simply doesn't work and people end up walking way from open source and the Python community. So,* ramifications from all of this* ... Steven, stop stating your opinion as fact and being needlessly abrasive. Your abrasiveness in responses has pushed multiple threads to breaking points like this before and I know you have the skills to not do that if you chose to because I've seen it here and on other mailing lists. Constructive conversations never need anything abrasive in them in order to get your intentions across. Consider this a warning to scale back the tone in response to be more respectful. Abe, you're receiving a warning about how you eventually reacted. In the future please just step away from the keyboard until you can react appropriately. The way you responded to Steven is not acceptable as it isn't respectful to others on this list and there shouldn't be "vigilante responses"; if you feel someone has violated the CoC then tell us admins and we will handle it. -Brett & Titus -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Mon Aug 13 16:26:38 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 13 Aug 2018 15:26:38 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: [Chris Angelico] > > The whole point of a programming language is to bridge the gap between > > machine code and natural language (in Python's case English, as with most > > other languages). It's to make reading and writing code easier through > > abstraction, not to create ivory towers through the use of esoteric > jargon. > > It's not supposed to make a cool kids club for people privileged enough > to > > study CS in college. At least that's not my goal. > The whole point of a car is to make driving easier through abstracting > away the internal details of petrochemical propulsion, but if someone > says "I don't want to know about 'gears' or 'brakes' or any of these > technical terms", you wouldn't want them driving on the roads you're > on. There is a certain level of comprehension that you can't avoid. > (If you don't know anything about how to use a car, you can still ride > in one, but you can't drive it; and you don't need to understand about > anonymous functions in order to operate a computer, but you'll need > them to program effectively.) This was originally in response to Bruce Leban's assertion: "If using lambda as a keyword leads people to go and learn about lambda calculus that is a good thing." Are you saying that knowing "what lambda calculus is" is as important to programming in Python as knowing "what breaks are" is to driving? If so, I don't think that analogy holds water. I don't think lambda calculus is fundamental to knowing how to write a program. I don't even think anonymous functions are fundamental to writing a program. I think a programmer could go their whole life without ever knowing what a lambda expression is and still manage to write plenty of very useful code. It seems to me like the whole point of this discussion has turned into getting me to repent and profess my undying love for lambda expressions. I'm sorry to disappoint. Maybe we should split off this discussion into a thread where people can keep badgering me to come up with an objective proof that Python's lambda expressions are not the best implementation possible. Then, at least, we can stop polluting this thread with this tangent. It doesn't seem to matter how many times I try to point this out, but my original comment should be read as: "I like Steven's idea. I prefer `given` to `partial`." I'm sorry I even brought up lambda. I'm truly sorry to all those who wanted to seriously discuss alternatives to functools.partial. On Mon, Aug 13, 2018 at 2:17 PM, Chris Angelico wrote: > On Tue, Aug 14, 2018 at 5:08 AM, Abe Dillon wrote: > > The whole point of a programming language is to bridge the gap between > > machine code and natural language (in Python's case English, as with most > > other languages). It's to make reading and writing code easier through > > abstraction, not to create ivory towers through the use of esoteric > jargon. > > It's not supposed to make a cool kids club for people privileged enough > to > > study CS in college. At least that's not my goal. > > The whole point of a car is to make driving easier through abstracting > away the internal details of petrochemical propulsion, but if someone > says "I don't want to know about 'gears' or 'brakes' or any of these > technical terms", you wouldn't want them driving on the roads you're > on. There is a certain level of comprehension that you can't avoid. > (If you don't know anything about how to use a car, you can still ride > in one, but you can't drive it; and you don't need to understand about > anonymous functions in order to operate a computer, but you'll need > them to program effectively.) > > > As someone who has taught Python professionally, I can say that there is > a > > strange mental block regarding lambda expressions. Pretty much every > student > > I've had has struggled with lambda expressions, even those who grasp > > similarly complex constructs like decorators with ease. This includes > > students who learned english as a second language. I can only attribute > that > > to the word 'lambda' being confusing as hell. > > As someone who currently teaches both Python AND JavaScript > professionally, I can say that there is a strange mental block > regarding anonymous functions, and it's nothing to do with the word > "lambda". In JavaScript, anonymous functions are created with the word > "function" (same word as is used for declared functions), and there > are just as many points of confusion as there are with Python. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Mon Aug 13 16:31:32 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 14 Aug 2018 06:31:32 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: On Tue, Aug 14, 2018 at 6:26 AM, Abe Dillon wrote: > [Chris Angelico] >> >> > The whole point of a programming language is to bridge the gap between >> > machine code and natural language (in Python's case English, as with >> > most >> > other languages). It's to make reading and writing code easier through >> > abstraction, not to create ivory towers through the use of esoteric >> > jargon. >> > It's not supposed to make a cool kids club for people privileged enough >> > to >> > study CS in college. At least that's not my goal. >> The whole point of a car is to make driving easier through abstracting >> away the internal details of petrochemical propulsion, but if someone >> says "I don't want to know about 'gears' or 'brakes' or any of these >> technical terms", you wouldn't want them driving on the roads you're >> on. There is a certain level of comprehension that you can't avoid. >> (If you don't know anything about how to use a car, you can still ride >> in one, but you can't drive it; and you don't need to understand about >> anonymous functions in order to operate a computer, but you'll need >> them to program effectively.) > > > This was originally in response to Bruce Leban's assertion: "If using lambda > as a keyword leads people to go and learn about lambda calculus that is a > good thing." > > Are you saying that knowing "what lambda calculus is" is as important to > programming in Python as knowing "what breaks are" is to driving? If so, I > don't think that analogy holds water. I don't think lambda calculus is > fundamental to knowing how to write a program. I don't even think anonymous > functions are fundamental to writing a program. I think a programmer could > go their whole life without ever knowing what a lambda expression is and > still manage to write plenty of very useful code. No, lambda calculus isn't on par with brakes - but anonymous functions are, and if they're called "lambda", you just learn that. In fact, I would say that the word "lambda" is the least troublesome part of anonymous functions, callbacks, and related topics. It's the same with "partial". Actually, I didn't think of that as "partial application" but as "partial specification of parameters". If you can grok the concept that you can take a function, lock some of its parameters, and get back another function, then you should be able to learn a word to associate with it. ChrisA From abedillon at gmail.com Mon Aug 13 16:48:05 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 13 Aug 2018 15:48:05 -0500 Subject: [Python-ideas] Conduct on python-ideas In-Reply-To: References: Message-ID: I can respect that. I'll take a week off the list and try to check myself in the future. I'm sorry to everyone on python-ideas. I'm sorry Steven. On Mon, Aug 13, 2018 at 2:38 PM, Brett Cannon wrote: > I'm starting a new thread on this to make sure it receives appropriate > visibility for everyone on this list. *There are ramifications for those > involved in this whole situation* as outlined at the end of this email. > > To review, this mailing list operates under the PSF Community Code of > Conduct: https://www.python.org/psf/codeofconduct/ . That means everyone > is expected to be open, considerate, and respectful. Titus and I have > operated this list such that people who don't follow the CoC get a warning, > then a temporary ban of a month or two, then a year-long ban, then a > permanent ban (and we reserve the right to skip any of these steps as we > see fit based on how bad the infraction was). Since the traffic here can > get a bit heavy and thus we don't read every email, we rely on people > reporting things as appropriate to python-ideas-owner@ if things have > gotten out of hand. > > And boy did things get out of hand on the "Syntactic sugar to declare > partial functions" thread. Here is what I saw play out (bolding is mine): > > ---------- > [Abe] > Words like 'partial', 'curry', 'lambda', and 'closure' are fine for text > books, published papers, and technical discussion, *but I think they > would (or do in the case of 'lambda') harm Python*. > > [Steven] > *That's an extreme overreaction*. > > Do you mean to imply that there are people who looked at Python, loved > the language, but decided to use something else because they didn't like > the choice of the keyword "lambda"? > > If not, in what way is Python harmed? Would it be faster if the keyword > was "function", or use less memory, or more expressive? > > Remember that to millions of programmers in the world, "function" is > just as much an obscure foreign piece of jargon they have to memorise as > "lambda" is to English-speakers. > > [Abe] > Extreme? I thought it was a rather benign opinion.* I'm not exactly > frothing at the mouth here. It's not like I'm declaring holy war on Python > for using the word 'lambda'.* I just think it was a mistake (and > thatdeath should come to all non-believers). > > [Steve] > > You've said that the choice of keyword, "lambda", has caused harm. Given > the chance to clarify what you meant, > *you stood by your comment that thechoice of keyword "lambda" has done > real, significant, non-trivial harm* > to Python (the language, or the community). Presumably you fear the same > thing will happen again if we choose "partial" (otherwise, why raise the > issue?). > > [Abe] > Notice:* I never said "real, significant, non-trivial harm" anywhere* in > this entire discussion. I never said anything close to that. *Stop > jamming bullshit in my mouth* to suit your narrative that I'm "extremely > overreacting". It's not cute. > ---------- > > The way I read this going down is Abe thought something "would harm > Python". "Harm" is a strong word to use, so Steven called it an "extreme > overreaction". Now stating it like a fact is unnecessary, abrasive, and a > bit of hyperbole. Abe thought we he thought and that's fine, but it isn't > universally considered an overreaction; it was an opinion and Abe correctly > stated it as such. Steven could have easily left out the hyperbole and > framing like a statement of fact and still made the same point. > > Abe then reacted with more hyperbole as he disagreed with Steven's > statement that he was overreacting. So now we are reacting to hyperbole > with hyperbole. > > Steven then reacted by overstating the strength of Abe's initial > intentions. That's a misunderstanding at best, entirely misleading at worst. > > At that point Abe crossed a line and basically yelled at Steven to "stop > jamming bullshit in [his] mouth". > > So how should have this been handled? First, dropping all hyperbole, not > stating opinions as facts, and not being so abrasive would have probably > stopped all of this from happening. Had Steven just said "I think that's an > overreaction; can you please clarify what harm you think happened?" then he > would have gotten the answer he wanted and Abe would not have taken > offense. Abe replying with his own hyperbole didn't help. > > Steven also didn't need to misrepresent what Abe said. Choosing to > re-interpret what level of harm Abe meant was not appropriate (unless > Steven got a bit sloppy and replied from memory instead of going back and > reading the emails he was replying to). > > And finally, Abe's response was totally uncalled for. I don't care how out > of line someone on this list is, you don't react like that. You come to > Titus and me and we will handle it. If you need to, step back for an hour > or day before replying if that's what it takes to not react in a rude > manner. > > I shouldn't be having to explain to adults on how to communicate among > strangers of different cultures, but here we are. I did an entire PyCon US > keynote on why we need to treat open source as a series of kindnesses and > react as such: https://youtu.be/tzFWz5fiVKU?t=49m29s . If we don't treat > everything as a kindness then open source simply doesn't work and people > end up walking way from open source and the Python community. > > So,* ramifications from all of this* ... > > Steven, stop stating your opinion as fact and being needlessly abrasive. > Your abrasiveness in responses has pushed multiple threads to breaking > points like this before and I know you have the skills to not do that if > you chose to because I've seen it here and on other mailing lists. > Constructive conversations never need anything abrasive in them in order to > get your intentions across. Consider this a warning to scale back the tone > in response to be more respectful. > > Abe, you're receiving a warning about how you eventually reacted. In the > future please just step away from the keyboard until you can react > appropriately. The way you responded to Steven is not acceptable as it > isn't respectful to others on this list and there shouldn't be "vigilante > responses"; if you feel someone has violated the CoC then tell us admins > and we will handle it. > > -Brett & Titus > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Mon Aug 13 19:13:07 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 14 Aug 2018 09:13:07 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: <20180813231307.GQ22431@ando.pearwood.info> TL;DR - I accept that there've been a few cases where I could have chosen my words better, and consequently I've rubbed Abe the wrong way; sorry about that Abe, as I said earlier (and I meant it) I have no grudge against you. - The most important technical issue I wanted to get from my discussion with Abe has been solved, I now believe that I understand what harm he feels was caused by chosing the name "lambda" over some alternative. - Namely (if I have understood Abe correctly) its the lost opportunity to have a better name. - Which seems to me to be so slight a harm that I don't think it gives us any guidance at all as to whether "partial" or "given" would make a better name for this proposed feature. (So much drama for so little gain.) Even after all these years of seeing people over-react to minor perceived slights (whether real or not), I cannot believe how quickly this one has degenerated into antagonism and over-reaction, and over so little. It certainly has not been helped by people fanning the flames of argument by calling this a "toxic forum". We should assume good faith. Before flying off the handle and taking offense, we should assume misunderstanding (on either or both party), accidental poor choice of wording, or merely robust debate rather than malice. We ought to be careful about making assumptions about people's motives from their responses. Email is a notoriously bad medium for judging people's motivation. The rest that follows is detail, responding to a few specific points which I deem relevant but not essential. * * * On Sun, Aug 12, 2018 at 10:31:36PM -0500, Abe Dillon wrote: > I explained my position on lambda as fully as I care to in my response to > Niel if you care to read it. I did read it. Just because I didn't respond to it directly doesn't mean I didn't read it. You say you object to the name, but then suggest a change that is idependent of that name. You talked about the placement of the function signature, wanting to put the body of the lambda first, before the parameter list. That has nothing to do with the choice of name "lambda", which is what I thought you were objecting too as it was too jargony. Moving the parameter list to the end of the expression is idependent of the keyword "lambda". > I only think lambda harms Python in so far as > there were better alternatives that communicate their intention much better > and are more readable. That's an opinion. If you must know, i'm not > currently frothing at the mouth as I state it. Nobody has accused you of frothing at the mouth. You seem to be talking about "opportunity costs" in a sense. Its not so much that the name lambda does harm in and of itself, but that another choice could be *even better* and do *even more good*. Is that a reasonable description of your position? > My original post was agreeing with you. Supporting your own words. If you > don't agree with my position that we should avoid jargon for jargon's sake, And don't imagine for a second I'm not aware of the irony. > then what exactly did you mean when you said, "although possibly a less > jargon name would be nicer?" Can you articulate why you think it might be > nicer to use a less jargon name? I meant exactly what I said. *Possibly* a less jargon name would be nicer. Or possibly not. I was opening the issue up for further discussion, not nailing my colours to the mast as champion for the idea. > What about my saying it all of a sudden > makes it an "extreme overreaction"? Now you're quoting me out of context. It was your claim that the name "lambda" does harm to Python that I described that way. In hindsight, I wish I had left off the adjective "extreme". [...] > Notice: I never said "real, significant, non-trivial harm" anywhere in this > entire discussion. In fairness, you did say "minor" harm, so I'll accept that my emphasis on real significant etc was questionable. I don't know where the boundary between minor and trivial lies and I think people can disagree on this point. So I'll accept that here I read more into your words than were actually there. Sorry about that. [...] > [Steven D'Aprano] > > > How can we insist that 3/4 of the world learn English words to use Python > > Do you really think that 3/4 of the world learns English just to write > Python? That's not what I wrote. There's a difference between these two positions: - needing to learn to read English words to use Python; - using Python is the only reason to learn English. I said the first, not the second. > [Steven D'Aprano] > > > ...if we aren't even willing to move out of our own comfort zone to > > the extent of learning accurate jargon terms from our own profession? > > Very few of us are computer scientists by profession. That's not even where > 'lambda' comes from. In computer science, it's called an "anonymous > function". "lambda" comes from lambda calculus. Where it comes from is not really important. Words change and are co-opted in new contexts. "Lambda" is rapidly become a standard programming term, and language agnostic, e.g.: https://martinfowler.com/bliki/Lambda.html -- Steve From greg.ewing at canterbury.ac.nz Mon Aug 13 20:03:26 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Tue, 14 Aug 2018 12:03:26 +1200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: <5B721C4E.2050100@canterbury.ac.nz> Abe Dillon wrote: > [Bruce Leban] > > Lambda calculus IS computer science. > > It's a foundation of computer science. That doesn't mean it "IS" > computer science. Set theory is a foundation of computer science. It's > still it's own discipline. Lambda calculus is considered a part of computers science, because it was invented specifically for the purpose of modelling computation. Set theory wasn't. -- Greg From abedillon at gmail.com Mon Aug 13 20:38:40 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 13 Aug 2018 19:38:40 -0500 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <20180813231307.GQ22431@ando.pearwood.info> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813231307.GQ22431@ando.pearwood.info> Message-ID: [Steven D'Aprano] > - I accept that there've been a few cases where I could have > chosen my words better, and consequently I've rubbed Abe > the wrong way; sorry about that Abe, as I said earlier (and > I meant it) I have no grudge against you. Thank you. I hold no grudge against you either. I'm sorry for all the drama. [Steven D'Aprano] > - The most important technical issue I wanted to get from my > discussion with Abe has been solved, I now believe that I > understand what harm he feels was caused by chosing the name > "lambda" over some alternative. > - Namely (if I have understood Abe correctly) its the lost > opportunity to have a better name. Yes. That's pretty much it. In hindsight, I should have realized that the word "harm" carries a much more sever context in the programming community given all the "X considered harmful" articles out there. [Steven D'Aprano] > - Which seems to me to be so slight a harm that I don't think > it gives us any guidance at all as to whether "partial" or > "given" would make a better name for this proposed feature. I consider jargon for jargon's sake to be a poor reason to choose one term over a much more common term, however; I don't consider all jargon equal. I think "anonymous function" is far more descriptive than "lambda". I think you're ultimately right, however; that this doesn't guide the decision of "partial" over "given" very much because "partial" is not all that obscure. "partial function application" is fairly clear and as you said, Python wouldn't be trying to create an association from scratch. [Steven D'Aprano] > It certainly has not been helped by people fanning the flames of > argument by calling this a "toxic forum". At that point I felt like I had expressed that you came off as antagonistic toward me, had my feelings brushed off, then had multiple people ganging up on me about something I thought I had clearly articulated. I don't want to start a big fuss about it, but now both you and Stephen Turnbull have not-so-subtly referred to me indirectly like this. This time is fairly benign, but Turnbull's remark comes off as a passive-aggressive way of calling me toxic. I hope this isn't a sign of things to come where it's fine to passive-aggressively sling mud, but being direct is considered "crossing the line", because I find passive aggression far more insulting. I'm not an eight-year-old and people hiding behind the plausible deniability that even thinly veiled passive aggression affords them frustrates me. As I said early on: I'd rather resolve issues than have them continue to fester. Passive aggression does the exact opposite. [Steven D'Aprano] > We should assume good faith. Before flying off the handle and taking > offense, we should assume misunderstanding (on either or both party), > accidental poor choice of wording, or merely robust debate rather than > malice. We ought to be careful about making assumptions about people's > motives from their responses. Email is a notoriously bad medium for > judging people's motivation. > The rest that follows is detail, responding to a few specific points > which I deem relevant but not essential. Those are wise words and I'll try to adhere to them in the future. I would like to amend, that when someone signals that they feel like you're being aggressive towards them, it's a good idea to apologize. It's a simple act that can diffuse a lot of tension. [Steven D'Aprano] > > I explained my position on lambda as fully as I care to in my response to > > Niel if you care to read it. > I did read it. Just because I didn't respond to it directly doesn't mean > I didn't read it. I didn't mean that as an accusation that you hadn't read it. I'm sorry it came off that way. [Steven D'Aprano] > You say you object to the name, but then suggest a change that is > idependent of that name. Yes, I can see how that could lead to confusion. I'm sorry. I do, indeed, have two mostly separate objections to 'lambda': 1) I think it's a bad name 2) I think it's a sub-optimal form The only relevance of the form is that it sort-of illustrates a broader name-space to explore. For instance, the alternative name 'def' doesn't really make sense in the reversed order: hand = sorted(cards, key=def card: card.suit) # this kinda works, at least I think it's better than 'lambda' hand = sorted(cards, key=(card.suit def card) # this is... not as good [Steven D'Aprano] > > [Steven D'Aprano] > > > > > How can we insist that 3/4 of the world learn English words to use > Python > > > > Do you really think that 3/4 of the world learns English just to write > > Python? > That's not what I wrote. There's a difference between these two > positions: > - needing to learn to read English words to use Python; > - using Python is the only reason to learn English. > I said the first, not the second. I don't mean to come off as combative, but that is a direct quote, and I didn't try to take it out of context. If I did take it out of context, then I'm sorry. My point was that (and I may be wrong about this) I don't imagine most non-english speakers who want to write Python learning just enough English to write python. I imagine that most of them learn a broader vocabulary and thus, discussions about common English words still apply to them. It would be interesting to know either way, so maybe we should have a poll? I don't know. -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Mon Aug 13 17:58:30 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Tue, 14 Aug 2018 09:58:30 +1200 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> Message-ID: <5B71FF06.2070407@canterbury.ac.nz> Chris Angelico wrote: > No, lambda calculus isn't on par with brakes - but anonymous functions > are, and if they're called "lambda", you just learn that. It's like saying that people would find it easier to learn to drive if "brakes" were called "stoppers" or something. I don't think that's true. -- Greg From mike at selik.org Mon Aug 13 21:46:13 2018 From: mike at selik.org (Michael Selik) Date: Mon, 13 Aug 2018 18:46:13 -0700 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <5B71FF06.2070407@canterbury.ac.nz> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: On Mon, Aug 13, 2018, 5:48 PM Greg Ewing wrote: > Chris Angelico wrote: > > No, lambda calculus isn't on par with brakes - but anonymous functions > > are, and if they're called "lambda", you just learn that. > > It's like saying that people would find it easier to learn to > drive if "brakes" were called "stoppers" or something. I don't > think that's true. > There isn't much jargon involved in learning to drive and most of it is natural: left turn, right turn, blinkers, etc. Compare this with learning to sail. I still don't remember which side is starboard. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Mon Aug 13 21:48:04 2018 From: mertz at gnosis.cx (David Mertz) Date: Mon, 13 Aug 2018 21:48:04 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <5B71FF06.2070407@canterbury.ac.nz> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: Pedantically, Python's lambda isn't even the same thing as in the lambda calculus. The mathematical abstraction is always curried, and neither Python nor most languages that use the spelling 'lambda' do that. So even assuming users must learn technical vocabulary, this is an inaccurate such term. 'def' or 'func' would be less deceptive here for anonymous functions. The burden of learning the word lambda?and unlearning it's meaning in mathematical logic if you happened to have used that?it's not huge. But it's more than zero. And probably more than leaning 'function'. On Mon, Aug 13, 2018, 8:49 PM Greg Ewing wrote: > Chris Angelico wrote: > > No, lambda calculus isn't on par with brakes - but anonymous functions > > are, and if they're called "lambda", you just learn that. > > It's like saying that people would find it easier to learn to > drive if "brakes" were called "stoppers" or something. I don't > think that's true. > > -- > Greg > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From python at mrabarnett.plus.com Mon Aug 13 22:26:07 2018 From: python at mrabarnett.plus.com (MRAB) Date: Tue, 14 Aug 2018 03:26:07 +0100 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: <8fb9f93f-7c43-0de4-726d-a67f4f4dd23e@mrabarnett.plus.com> On 2018-08-14 02:46, Michael Selik wrote: > > > On Mon, Aug 13, 2018, 5:48 PM Greg Ewing > wrote: > > Chris Angelico wrote: > > No, lambda calculus isn't on par with brakes - but anonymous > functions > > are, and if they're called "lambda", you just learn that. > > It's like saying that people would find it easier to learn to > drive if "brakes" were called "stoppers" or something. I don't > think that's true. > > > There isn't much jargon involved in learning to drive and most of it is > natural: left turn, right turn, blinkers, etc. > > Compare this with learning to sail. I still don't remember which side is > starboard. > "Starboard" is the side on which was the "steerboard", the large "board" or oar used for steering the boat, a predecessor of the rudder. Most people are right-handed, so it was put on the right-hand side of the boat. Given that, it made sense to tie the boat up to a jetty on its unobstructed left-hand side, the "port" side. Starboard = right, port = left. From rosuav at gmail.com Mon Aug 13 23:59:50 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 14 Aug 2018 13:59:50 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <5B71FF06.2070407@canterbury.ac.nz> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: On Tue, Aug 14, 2018 at 7:58 AM, Greg Ewing wrote: > Chris Angelico wrote: >> >> No, lambda calculus isn't on par with brakes - but anonymous functions >> are, and if they're called "lambda", you just learn that. > > > It's like saying that people would find it easier to learn to > drive if "brakes" were called "stoppers" or something. I don't > think that's true. Reminds me of this: "So, there's some buttons on the floor. Pedals. Uhh.... That's the "go" pedal... That, I believe, is the stopper... and this... this doesn't do anything...." -- Wreck It Ralph, trying to figure a car out. I'm pretty certain he didn't do any better that way than if he'd used words like "accelerator" and "brake". In fact, this supports my assertion that it's not the terminology that bites you - it's the concepts behind it. Even if he'd known that the other pedal was called the "clutch", it wouldn't have helped him much without knowing how to use it... Whether you spell it "function(arg) {...}" or "lambda arg: ...", it's the semantics that are hardest to learn. ChrisA From jfine2358 at gmail.com Tue Aug 14 04:53:34 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 14 Aug 2018 09:53:34 +0100 Subject: [Python-ideas] Toxic forum In-Reply-To: <23409.55792.906609.495552@turnbull.sk.tsukuba.ac.jp> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> <23409.55792.906609.495552@turnbull.sk.tsukuba.ac.jp> Message-ID: Hi All Here's something that's at the core of my approach. Faced with this sort of problem, I read again https://www.python.org/psf/codeofconduct/. And then I compare my intentions, words and actions to the guidelines in this, the Python Community Code of Conduct. Only when I have, so to speak, regained my purpose and composure do I consider the conduct of others. At least, this is what I aspire to do. -- Jonathan From j.van.dorp at deonet.nl Tue Aug 14 05:01:27 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Tue, 14 Aug 2018 11:01:27 +0200 Subject: [Python-ideas] Toxic forum In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <20180813122847.24a9df01@fsol> <23409.55792.906609.495552@turnbull.sk.tsukuba.ac.jp> Message-ID: I'm perhaps the newest and most ignorant subscriber here - I daresay everyone here has superior python knowledge to me, and all my other computing knowledge is inferior to what I can do with python. (and so far, I've had no influence at all on python) However, this mailing list, generally, does not seem toxic to me at all. I haven't experienced any condescension about my lack of knowledge. While I can acknowledge that there might be superior alternatives to email, I do think the threshold of subscribing and listening in is lower than a lot of other options, like for example subreddits. I for example would have never come if it'd been one of those. 2018-08-14 10:53 GMT+02:00 Jonathan Fine : > Hi All > > Here's something that's at the core of my approach. > > Faced with this sort of problem, I read again > https://www.python.org/psf/codeofconduct/. And then I compare my > intentions, words and actions to the guidelines in this, the Python > Community Code of Conduct. Only when I have, so to speak, regained my > purpose and composure do I consider the conduct of others. > > At least, this is what I aspire to do. > > -- > Jonathan > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Tue Aug 14 06:22:13 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 14 Aug 2018 20:22:13 +1000 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> Message-ID: <20180814102213.GR22431@ando.pearwood.info> On Mon, Aug 13, 2018 at 07:46:49PM +0200, Stefan Behnel wrote: > Michel Desmoulin schrieb am 09.08.2018 um 18:59: > > I'd rather have functools.partial() to be added as a new method on > > function objects. [...] > > add_2 = add.partial(2) > > Except that this only works for functions, not for other callables. > Meaning, code that uses this for anything but its self-defined functions > will break as soon as someone passes in a callable object that is not a > function. That's an excellent point. If it were important to cover those use-cases, we could add a partial method to types, methods, builtin-functions etc. But I suspect that doing that would increase the cost of this proposed feature past the point where it is worthwhile. Do we often call functools.partial on arbitrary callable objects that we don't know in advance? (Not a rhetorical question.) I know I don't -- all the times I've called partial, I've known what the callable was, and it was always a function I created with def. But maybe others do something differently. I don't mind writing this: # only a minor inconvenience spam = func.partial(arg) eggs = functools.partial(callable, arg) given that I knew upfront that func was a function and callable was not. But if I didn't know, the utility of a partial method would be hugely reduced, and I'd just use functools.partial for everything. -- Steve From jfine2358 at gmail.com Tue Aug 14 06:28:44 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 14 Aug 2018 11:28:44 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: Message-ID: Hi I'm pleased to announce that I've completed the first draft of my page. It's viewable on gitub. https://github.com/jfine2358/py-jfine2358/blob/master/docs/none-is-special.md To quote from that page: This page arose from a thread on the python-ideas list. I thank Steve Dower, Paul Moore, Steve D'Aprano, Chris Barker, David Mertz, J?rn Heissler, Anthony Risinger, Michael Selik, Chris Angelico for their contributions and encouragement. Apologies for anyone I've missed. Comments either on python-ideas, or perhaps better, by raising an issue on github. -- Jonathan From jfine2358 at gmail.com Tue Aug 14 08:11:32 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 14 Aug 2018 13:11:32 +0100 Subject: [Python-ideas] Conduct on python-ideas In-Reply-To: References: Message-ID: Hi Everyone Brett Cannon wrote: > I shouldn't be having to explain to adults on how to communicate among > strangers of different cultures, but here we are. I did an entire PyCon US > keynote on why we need to treat open source as a series of kindnesses and > react as such: https://youtu.be/tzFWz5fiVKU?t=49m29s . If we don't treat > everything as a kindness then open source simply doesn't work and people end > up walking way from open source and the Python community. Well, I've just watched that video. Did anyone else? Recommended - it's only 30 minutes. Is that too long? Well, here's two extracts. Video at https://youtu.be/tzFWz5fiVKU?t=4450 > If I had to give guidelines on how to communicate online: > 1. Assume that you are asking *me* for a *favour*. > 2. Assume your *boss* will read what you say. > 3. Assume *your family* will read what you say. Video at https://youtu.be/tzFWz5fiVKU?t=4094 > *If this sounds biased towards maintainers, that's because it is.* > Simply based on scale, maintainers are abused much more > often than contributors. Once again, recommended. I hope you'll watch the video. -- Jonathan From chris.barker at noaa.gov Tue Aug 14 11:49:45 2018 From: chris.barker at noaa.gov (Chris Barker - NOAA Federal) Date: Tue, 14 Aug 2018 11:49:45 -0400 Subject: [Python-ideas] Syntactic sugar to declare partial functions In-Reply-To: <20180814102213.GR22431@ando.pearwood.info> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180814102213.GR22431@ando.pearwood.info> Message-ID: > > Do we often call functools.partial on arbitrary callable objects that we > don't know in advance? For my part, I don?t think I?ve ever used partial in production code. It just seems easier to simply fo it by hand with a closure ( Am I using that term right? I still don?t quite get the terminology) And if I had a callable class instance I wanted to ?customize?, I?d likely use an OO approach ? parameterize the instance, or subclass. So yeah, partial is probably used primarily with ?regular? functions. But then, I don?t know that we need any easier syntax anyway ? maybe I?d be more likely to use it, but it kind of feels like a feature that?s there so we can write more functional code for the sake of writing more functional code. If someone?s really interested in this, a search on gitHub or something to see how it?s used in the wild could be enlightening. -CHB From contact at brice.xyz Tue Aug 14 12:55:32 2018 From: contact at brice.xyz (Brice Parent) Date: Tue, 14 Aug 2018 18:55:32 +0200 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: Message-ID: Nice work, very usefull. Is it interesting enough to note that the negation of None is True? (probably just because when it's casted to bool, it becomes False). Also,? even if None is seen as the value for the lack of value, it is still hashable and can be used as a key to a dict (I'm not saying it's always good practice!): >>> def f(): ...???? pass ... >>> {None: 5, not None: 6} {None: 5, True: 6} >>> {f(): 4} {None: 4} Also, I would probably have added an example of how (and why) to use a sentinel value for when None has a meaning other than [not provided] in a function's signature. You'll see if any of these is worth integrating. - Brice Le 14/08/2018 ? 12:28, Jonathan Fine a ?crit?: > Hi > > I'm pleased to announce that I've completed the first draft of my > page. It's viewable on gitub. > https://github.com/jfine2358/py-jfine2358/blob/master/docs/none-is-special.md > > To quote from that page: > > This page arose from a thread on the python-ideas list. I thank Steve > Dower, Paul Moore, Steve D'Aprano, Chris Barker, David Mertz, J?rn > Heissler, Anthony Risinger, Michael Selik, Chris Angelico for their > contributions and encouragement. > > Apologies for anyone I've missed. Comments either on python-ideas, or > perhaps better, by raising an issue on github. > From mertz at gnosis.cx Tue Aug 14 13:25:06 2018 From: mertz at gnosis.cx (David Mertz) Date: Tue, 14 Aug 2018 13:25:06 -0400 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: Message-ID: Great work! There are a few typos, I'll try to get to a PR on those. I wonder if it's worth noting that None is a singleton, while 42 is just a value. I.e. there might be several distinct objects that happen to be the int 42, but not so with None. Of course, in CPython, small integers are cached as the same object, but larger integers are not necessarily cached. This has varied in details between Python implementations and even versions, it's not a semantic promise like None carries. Maybe that's too far in the weeds for an intro though. On Tue, Aug 14, 2018, 6:29 AM Jonathan Fine wrote: > Hi > > I'm pleased to announce that I've completed the first draft of my > page. It's viewable on gitub. > > https://github.com/jfine2358/py-jfine2358/blob/master/docs/none-is-special.md > > To quote from that page: > > This page arose from a thread on the python-ideas list. I thank Steve > Dower, Paul Moore, Steve D'Aprano, Chris Barker, David Mertz, J?rn > Heissler, Anthony Risinger, Michael Selik, Chris Angelico for their > contributions and encouragement. > > Apologies for anyone I've missed. Comments either on python-ideas, or > perhaps better, by raising an issue on github. > > -- > Jonathan > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rhodri at kynesim.co.uk Tue Aug 14 13:45:59 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Tue, 14 Aug 2018 18:45:59 +0100 Subject: [Python-ideas] Python docs: page: In what ways in None special Message-ID: (Sorry to break threading on this. In a fit of idiocy I deleted the original email before realising I wanted to reply.) First off, thanks for doing this Jonathan. Documentation is usually a thankless task, so we ought to start by thanking you! I have a few comments on both content and style, good and bad. Starting with style, I notice you tend to write in short sentences. This is generally a good thing, but sometimes you make them too short. This gets really visible when you start sentences with "And" or "But"; my old English teacher would have menaced you with a ruler for such bad grammar. You can start a sentence with a conjunction, but it adds extra emphasis that you don't usually want. The start of the "Why None?" section is a good example. It reads like: "Sometimes a value is required. But (pay careful attention to this, it's important and there will be a quiz later) we're not able to provide one." I exaggerate for effect, of course, but it would read more easily as: "Sometimes a value is required but we're not able to provide one." On 'None is a constant': Erm. I think you've got carried away with simplifying this and gone down a blind alley. None is a literal, and like any other literal can't be rebound. Either this entire section is irrelevant or you meant to explain that there is only one "NoneType" object. Constant is a bit of a loaded term in Python, and I think you've fallen foul of it here. On 'None is the default return value': I really dislike the term "falls off the bottom". I can't think of anything similarly short and expressive, but I grimaced when I saw it. The 'list gotcha' is a good example of how None is used as the default return value and why programmers should pay attention, but it doesn't deserve it's own subsection. It's a direct consequence of None being the return value. On 'None can signal failure': Here's where I think None stops being special in the document. None can signal failure. So False, 0, an empty string, a negative number or pretty much anything else. If you want to have a section on how None is used, that great, but having this in the section "How None is special" is just wrong. On 'None as a placeholder default': Ditto. It's common to use None as a placeholder for a mutable type; explaining that common gotcha here would be good. Epigraphs: If you're going to quote Sherman, you need to expand on the uniqueness of None. Not doing that just makes it look irrelevant. It's not irrelevant, it's a tigger [1] [1] Misquoting Michael Flanders from the introduction to "The Hippopotamus Song" on "At The Drop Of A Hat". -- Rhodri James *-* Kynesim Ltd From mike at selik.org Tue Aug 14 15:42:29 2018 From: mike at selik.org (Michael Selik) Date: Tue, 14 Aug 2018 12:42:29 -0700 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: The conversation about syntactic sugar for ``functools.partial`` led to a question about whether jargon like "lambda" makes the concept of an anonymous function more difficult to learn. In my own experience teaching, I find that many concepts are easier to introduce if I avoid the Python jargon until after I've explained what it does. This is supported by education research. Some light Googling found a study on the topic [0] that is consistent with my own observations. Picking good names is hard [1]. It's tempting to use terms based on the origin of the concept, historical odds and ends, or even jokes. This can help someone remember the concept when someone is familiar with the origin, history, or joke, but makes the concept more confusing and hard to remember for others. I recommend trying to buck tradition and pick terms that are as simple as possible, requiring the least context to make sense. Jargon can be useful for allowing an expert to quickly identify the context of a term [2]. Plain language phrases can easily create namespace collisions. However, someone searching for or reading about Python concepts already knows that the context is Python programming. Good comparisons can be found in other fields: * Driving -- brakes vs stoppers * Sailing -- starboard vs right-side * Medicine -- postprandial vs after-meal * Biology -- dinosaur vs direlizard In the last case, it turns out direbird might have been a better term. I'm not sure if that supports or detracts from my argument. [0] https://iubmb.onlinelibrary.wiley.com/doi/full/10.1002/bmb.20922 [1] https://martinfowler.com/bliki/TwoHardThings.html [2] https://www.nngroup.com/articles/specialized-words-specialized-audience/ On Mon, Aug 13, 2018 at 9:00 PM Chris Angelico wrote: > On Tue, Aug 14, 2018 at 7:58 AM, Greg Ewing > wrote: > > Chris Angelico wrote: > >> No, lambda calculus isn't on par with brakes - but anonymous functions > are, and if they're called "lambda", you just learn that. > > > > It's like saying that people would find it easier to learn to > > drive if "brakes" were called "stoppers" or something. I don't > > think that's true. > > Reminds me of this: > "So, there's some buttons on the floor. Pedals. Uhh.... That's the > "go" pedal... That, I believe, is the stopper... and this... this > doesn't do anything...." > -- Wreck It Ralph, trying to figure a car out. > > I'm pretty certain he didn't do any better that way than if he'd used > words like "accelerator" and "brake". In fact, this supports my > assertion that it's not the terminology that bites you - it's the > concepts behind it. Even if he'd known that the other pedal was called > the "clutch", it wouldn't have helped him much without knowing how to > use it... > > Whether you spell it "function(arg) {...}" or "lambda arg: ...", it's > the semantics that are hardest to learn. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Tue Aug 14 18:57:54 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Tue, 14 Aug 2018 15:57:54 -0700 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: Message-ID: On Tue, Aug 14, 2018 at 10:25 AM, David Mertz wrote: > Great work! There are a few typos, I'll try to get to a PR on those. > > I wonder if it's worth noting that None is a singleton, while 42 is just a > value. I.e. there might be several distinct objects that happen to be the > int 42, but not so with None. > very much worth nothing -- and I think re-wording that example. The fact that you can't assign to None is orthogonal to the fact that it's immutable. in fact, [42] is a llteral for a list with one element, the integer with the value of 42 in it. It is very much a mutable. and yet: In [7]: [42] = 34 File "", line 1 [42] = 34 SyntaxError: can't assign to literal whereas: [5].append(3) works -- at least it does not result in an error -- even though it's useless. And the reason this matters is that name binding (and rebinding) is very much a different operation than mutating -- we should not conflate those. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Tue Aug 14 19:09:58 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Tue, 14 Aug 2018 16:09:58 -0700 Subject: [Python-ideas] Python docs: page: In what ways in None special In-Reply-To: References: Message-ID: On Tue, Aug 14, 2018 at 10:45 AM, Rhodri James wrote: > On 'None is a constant': > > Erm. I think you've got carried away with simplifying this and gone down > a blind alley. None is a literal, and like any other literal can't be > rebound. no, it's not -- None is keyword, and just like any other keyword, it can't be re-bound. However, every other keyword I tried to rebind results in a generic: SyntaxError: invalid syntax (except None, True, and False) which I suppose is because while None is a keyword, it can be used pretty much anywhere any other name can be used (as opposed to say, def) Either this entire section is irrelevant or you meant to explain that there > is only one "NoneType" object. > > Constant is a bit of a loaded term in Python, and I think you've fallen > foul of it here. > yes, I think "singleton" is the word you want here, though it is a bi CS-y :-( -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 14 19:27:04 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 15 Aug 2018 09:27:04 +1000 Subject: [Python-ideas] Python docs: page: In what ways in None special In-Reply-To: References: Message-ID: On Wed, Aug 15, 2018 at 9:09 AM, Chris Barker via Python-ideas wrote: > no, it's not -- None is keyword, and just like any other keyword, it can't > be re-bound. However, every other keyword I tried to rebind results in a > generic: > > SyntaxError: invalid syntax > > (except None, True, and False) > > which I suppose is because while None is a keyword, it can be used pretty > much anywhere any other name can be used (as opposed to say, def) Yeah. That's the difference between "keywords that are syntactically special" and "keywords that represent specific values". Most keywords define syntax (you mention "def", and similarly "if", "global", "import") or are operators ("and", "if", "is not"); the ones that could theoretically be assigned to are defined in the grammar as forms of atom. atom: ('(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') >>> ... = 1 File "", line 1 SyntaxError: can't assign to Ellipsis >>> None = 2 File "", line 1 SyntaxError: can't assign to keyword >>> True = 3 File "", line 1 SyntaxError: can't assign to keyword >>> False = 4 File "", line 1 SyntaxError: can't assign to keyword Interestingly, even though the first example specifically says "Ellipsis", it's perfectly acceptable to assign to that name: >>> Ellipsis = 5 >>> print(Ellipsis) 5 Note also that the rules are slightly different in Python 2; True and False are ordinary builtins, and "..." has meaning only inside a subscript, so trying to assign to it makes as much sense as "<> = 1". The special non-assignable status of None is therefore shared by three other values; it's still special, but it's not unique. The same is true of the behaviour of "if None:" - since it's a keyword and cannot be assigned to, it will always have the same value, and since it's an immutable value, it will always have the same truthiness, and since the 'if' statement is always false, the bytecode can be optimized away. So that's also not unique to None, but is behaviour shared by other literals. (Only literals though - neither "if []:" nor "if {}:" is optimized out, at least in CPython 3.7.) ChrisA From gadgetsteve at live.co.uk Wed Aug 15 01:21:25 2018 From: gadgetsteve at live.co.uk (Steve Barnes) Date: Wed, 15 Aug 2018 05:21:25 +0000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: On 14/08/2018 20:42, Michael Selik wrote: > > Good comparisons can be found in other fields: > * Driving -- brakes vs stoppers > * Sailing -- starboard vs right-side > * Medicine -- postprandial vs after-meal > * Biology -- dinosaur vs direlizard > While NOT wanting to start another fight I feel that I must put my pedant hat on & point out that the above highlights why domain specific words are used and their specificity actually highlights important concepts, i.e.: * Brakes are used to apply breaking, (i.e. to slow the vehicle, possibly to a stop), while stoppers STOP something. * Starboard = to the right when facing the bow (front of the vessel) not "my right", "your right" or "their right" (which depends on which way you, I & they are facing). * postprandial = after Lunch (not after eating any meal or after a snack). * A dinosaur is specifically an extinct terrible (formerly considered) lizard where as a Gila Monster is definitely a scary & dangerous (dire) lizard. In all of these cases there is a specificity to the word used that is missing from the alternative offered that will, hopefully, be raised by the use of that word. Unfortunately many people, when trying to explain what the word means fail to highlight where it is different (the number of times that I have heard people "explain" port and starboard as left and right without mentioning the word bow or forward is countless). Using a slightly unfamiliar word can cause people to ask, or think about, why this is different & what the difference is while also drawing a parallel that can help the user/student to understand & remember the concept. Also, picking a label for something, and using it consistently, can vastly simplify things like manual searches (or on-line searches). The English language has, historically, always borrowed, co-opted and sometimes perverted words from other languages to allow distinct concepts to be expressed concisely - which I personally, (admittedly as a native speaker), find rather useful. -- 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. https://www.avg.com From stefan_ml at behnel.de Wed Aug 15 03:06:27 2018 From: stefan_ml at behnel.de (Stefan Behnel) Date: Wed, 15 Aug 2018 09:06:27 +0200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: Michael Selik schrieb am 14.08.2018 um 21:42: > This is supported by education research. Some light Googling found a > study on the topic [0] that is consistent with my own observations. OTx2, and no offence, but ? this is supported by research as well. People tend to search just long enough to find the link that backs their ? observations. :) Stefan From mike at selik.org Wed Aug 15 03:40:26 2018 From: mike at selik.org (Michael Selik) Date: Wed, 15 Aug 2018 00:40:26 -0700 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: On Wed, Aug 15, 2018, 12:06 AM Stefan Behnel wrote: > Michael Selik schrieb am 14.08.2018 um 21:42: > > This is supported by education research. Some light Googling found a > > study on the topic [0] that is consistent with my own observations. > > OTx2, and no offence, but ? this is supported by research as well. People > tend to search just long enough to find the link that backs their ? > observations. :) > Of course! No offense taken. I did "light Googling", not a literature review. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Wed Aug 15 04:03:14 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Wed, 15 Aug 2018 20:03:14 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: <5B73DE42.90607@canterbury.ac.nz> Steve Barnes wrote: > * Brakes are used to apply breaking, I hope they actually apply braking, not breaking. :-) > * A dinosaur is specifically an extinct terrible (formerly considered) > lizard Which technically is not a lizard. -- Greg From jfine2358 at gmail.com Wed Aug 15 04:17:25 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 15 Aug 2018 09:17:25 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B73DE42.90607@canterbury.ac.nz> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <5B73DE42.90607@canterbury.ac.nz> Message-ID: Steve Barnes and Greg Ewing wrote: >> * A dinosaur is specifically an extinct terrible (formerly considered) >> lizard > > > Which technically is not a lizard. I can't resist. Puffinus puffinus is the scientific name for (drum roll) no, not the Atlantic (or common) Puffin but (off-pitch fanfare) https://en.wikipedia.org/wiki/Manx_shearwater -- Jonathan From rhodri at kynesim.co.uk Wed Aug 15 08:38:00 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 15 Aug 2018 13:38:00 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: <8531be37-303d-2bde-5972-7cd9c43a3fec@kynesim.co.uk> On 15/08/18 06:21, Steve Barnes wrote: > The English language has, historically, always borrowed, co-opted and > sometimes perverted words from other languages to allow distinct > concepts to be expressed concisely - which I personally, (admittedly as > a native speaker), find rather useful. I think you and Michael are arguing to the same end. He was suggesting that it's easier to teach a concept by introducing the idea and then a name for it, rather like the way Python creates objects before binding them. -- Rhodri James *-* Kynesim Ltd From rhodri at kynesim.co.uk Wed Aug 15 08:40:56 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 15 Aug 2018 13:40:56 +0100 Subject: [Python-ideas] Python docs: page: In what ways in None special In-Reply-To: References: Message-ID: <11d35c9b-882e-40de-6330-330f61466a70@kynesim.co.uk> On 15/08/18 00:09, Chris Barker wrote: > On Tue, Aug 14, 2018 at 10:45 AM, Rhodri James wrote: > >> On 'None is a constant': >> >> Erm. I think you've got carried away with simplifying this and gone down >> a blind alley. None is a literal, and like any other literal can't be >> rebound. > > no, it's not -- None is keyword, and just like any other keyword, it can't > be re-bound. However, every other keyword I tried to rebind results in a > generic: It's both, really. In many ways it's only a keyword because Python doesn't otherwise have a way of creating non-rebindable names. It's purpose is to represent the singular object of NoneType, and in that sense it's a literal as much as [] or "". -- Rhodri James *-* Kynesim Ltd From greg.ewing at canterbury.ac.nz Wed Aug 15 04:49:00 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Wed, 15 Aug 2018 20:49:00 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <5B73DE42.90607@canterbury.ac.nz> Message-ID: <5B73E8FC.5050302@canterbury.ac.nz> Jonathan Fine wrote: > Puffinus puffinus is the scientific name for Puff the Magic Dragon? -- Greg From chris.barker at noaa.gov Wed Aug 15 12:02:24 2018 From: chris.barker at noaa.gov (Chris Barker - NOAA Federal) Date: Wed, 15 Aug 2018 09:02:24 -0700 Subject: [Python-ideas] Python docs: page: In what ways in None special In-Reply-To: <11d35c9b-882e-40de-6330-330f61466a70@kynesim.co.uk> References: <11d35c9b-882e-40de-6330-330f61466a70@kynesim.co.uk> Message-ID: > None is keyword, and just like any other keyword, it can't be re-bound. >> it's only a keyword because Python doesn't otherwise have a way of creating non-rebindable names. It's purpose is to represent the singular object of NoneType, and in that sense it's a literal as much as [] or "". We?re getting kind of pedantic here, but no, it?s not ?as much as? ? [] and ?? create new instances of a list or string. For the purposes of this document, however, these are pretty esoteric distinctions. What the docs should make clear is that None ( and True and False ) is a singleton? None will always refer to the SAME None object. And that can be demonstrated by showing that you can?t rebind the name None. But I think it?s misleading to say that that is the same as: 42 = ?something else? None is syntactical a name like any other ? what?s special about is that it can?t be rebound. -CHB > > -- > Rhodri James *-* Kynesim Ltd From chris.barker at noaa.gov Wed Aug 15 12:30:48 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Wed, 15 Aug 2018 09:30:48 -0700 Subject: [Python-ideas] Python docs: page: In what ways in None special In-Reply-To: References: <11d35c9b-882e-40de-6330-330f61466a70@kynesim.co.uk> Message-ID: Since I already spent a bunch of time on this, I did a PR: https://github.com/jfine2358/py-jfine2358/pull/2 further discussion should probably be in that PR / repo -CHB On Wed, Aug 15, 2018 at 9:02 AM, Chris Barker - NOAA Federal < chris.barker at noaa.gov> wrote: > > None is keyword, and just like any other keyword, it can't be re-bound. > > > >> it's only a keyword because Python doesn't otherwise have a way of > creating non-rebindable names. It's purpose is to represent the singular > object of NoneType, and in that sense it's a literal as much as [] or "". > > We?re getting kind of pedantic here, but no, it?s not ?as much as? ? [] > and ?? create new instances of a list or string. > > For the purposes of this document, however, these are pretty esoteric > distinctions. > > What the docs should make clear is that None ( and True and False ) is a > singleton? None will always refer to the SAME None object. > > And that can be demonstrated by showing that you can?t rebind the name > None. > > But I think it?s misleading to say that that is the same as: > > 42 = ?something else? > > None is syntactical a name like any other ? what?s special about is that > it can?t be rebound. > > -CHB > > > > > -- > > Rhodri James *-* Kynesim Ltd > -- 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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From python at mrabarnett.plus.com Wed Aug 15 13:27:09 2018 From: python at mrabarnett.plus.com (MRAB) Date: Wed, 15 Aug 2018 18:27:09 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <5B73DE42.90607@canterbury.ac.nz> Message-ID: <9c82e0db-8472-11a4-788d-5b564a147e8d@mrabarnett.plus.com> On 2018-08-15 09:17, Jonathan Fine wrote: > Steve Barnes and Greg Ewing wrote: > >>> * A dinosaur is specifically an extinct terrible (formerly considered) >>> lizard >> >> >> Which technically is not a lizard. > > I can't resist. Puffinus puffinus is the scientific name for > > (drum roll) > > no, not the Atlantic (or common) Puffin but > > (off-pitch fanfare) > > https://en.wikipedia.org/wiki/Manx_shearwater > While we're at it, what's the only creature that's known commonly and only by its scientific name? From jfine2358 at gmail.com Wed Aug 15 14:55:06 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 15 Aug 2018 19:55:06 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: Message-ID: Hi Thank you all, for the kind words and appreciation, and the comments and suggestions. I have time now to respond to one comment. Please note that is just my opinion, and your opinion may be different. Rhodri James prefers (https://mail.python.org/pipermail/python-ideas/2018-August/052742.html) > Sometimes a value is required but we're not able to provide one. to my > Sometimes a value is required. But we're not able to provide one. The next sentence is > In Python, we can use None to solve this problem. I chose the punctuation I did, because I wanted to state clearly the problem. Which is, roughly speaking, damned if you do, and damned if you don't. (In the US, between a rock and a hard place.) In other words, a dilemma. https://www.dictionary.com/browse/dilemma a choice between [...] undesirable alternatives. This paragraph > Sometimes a value is required. But we're not able to > provide one. In Python, we can use None to solve > this problem. is in my mind None in a nutshell. Rhodri says my version, exaggerated for effect, reads like > Sometimes a value is required. But (pay careful attention > to this, it's important and there will be a quiz later) > we're not able to provide one. Yes, Rhodri, you've understood what I'm doing. I do want the reader to pay careful attention. If they only remember one thing, this is what I want them to remember. Rhodri say that his version reads more easily. I agree. And that that is why I prefer my version! Sometimes you have to slow the reader down, so that there's time for understanding to catch up. Short sentences catch attention. Long sentences, with many clauses and a variation of ideas, go by like the scenery on a long and monotonous care journey. And little is remembered. The lesson I take from this is not that I am right and Rhodri is wrong. Or the other way round. That depends on context, taste and house style. And often, there are good reasons on both sides of the decision. So the starting point for persuading someone to change their mind might be this: Understand the forces that led them to the position they hold. Sometime before the end of the month, I'll process the remaining contributions and comments. I hope it doesn't take me more than an hour or two. I'll start by looking at github issues, then pull requests, and then python-ideas. Once again, thank you for all the comments and suggestions. And the kind words and appreciation. -- Jonathan From danilo.bellini at gmail.com Wed Aug 15 15:08:56 2018 From: danilo.bellini at gmail.com (Danilo J. S. Bellini) Date: Wed, 15 Aug 2018 16:08:56 -0300 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <0f22c3e8-4163-cfcd-d676-e0452bab668a@gmail.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: On 14 August 2018 at 16:42, Michael Selik wrote: > In my own experience teaching, I find that many concepts are easier to > introduce if I avoid the Python jargon until after I've explained what it > does. [...] > "until after" != "forever". A jargon might be just an acronym, a word or few words, meaningless for someone who doesn't know what it means [sic], but even for this person the jargon is useful: he/she can look for information about it. Teaching the other way around to let the student grasp the "mechanical procedure" before its name doesn't change anything regarding the names. You can make everyone memorize the algorithm for adding base-10 whole numbers by hand without teaching the students words like "adding" or "sum", not even the "+" symbol. But it would be a confusion if you use any other symbol or word to replace these "maths jargon" ones, and you shouldn't avoid the socially used names/symbols just because you're teaching that stuff for kids who still doesn't know them. And I'm aware of students complaining they can't remember something they've learned (or simply they didn't know someone was talking about what they know, a communication issue) because they didn't know the name (not even for searching in the web, a dictionary, whatever...). I really regret that I complained when expressions like "modus ponens" and "disjunctive syllogism" were teached to me during a class in 2004, that day I thought these stuff were so obvious that they shouldn't have a name. Until I found, later, that I needed to know these names in order to understand some stuff I was reading. These names might had been hard to memorize, but they were better than arbitrary names that no one else happens to use. Some of my worst teachers avoided the proper jargon forever, not just "until after" definitions/examples. Several classes here in Brazil tries to teach some concepts by forcing everything to be in Portuguese, like an "ideology of full translation", and sometimes the translated names are meaningless (no social context external to the class uses them). I got somewhat angry when I found that a lot of stuff I knew had other names in every useful social context, and I know who/what I should blame for that. Terminology is the first step when going into a new domain... an example, marked as "Important unit", can be found at https://www.statistics-made- easy.com/introduction-to-statistics/ *This introduction will teach you all the basic terms of statistics. It is important to understand them well before studying the unit about organizing data. The lessons are organized in a way to make the learning process as smooth as possible. Follow the logical order given here to study the lessons.* [...] It's tempting to use terms based on the origin of the concept, > historical odds and ends, or even jokes. [...] > Usually, you're not naming something new and unnamed... but sometimes the concept might have more than a single name. I think that's like irregular verbs: they're so common that they "break the patterns"; concepts that are spread/scattered everywhere might have a distinct name in each domain. Names should be useful to precisely express the concept in social contexts, but there's a context that should never be considered for that: the "teaching" one. If the concept itself isn't known by some people, why care about an alternative "non-jargon" name? A name doesn't belong to a person or a class, but to the people who can use/understand it, and I believe using proper jargon instead of alternative "simplified" names should maximize that. It's the social expressiveness towards people who already know the concepts that should be emphasized, not some other arbitrary "simplification" goal (e.g. minimize the number of characters, only use English, ...). IMHO, avoiding jargon sounds like avoiding teaching. In the case of new Python stuff, avoiding the socially standardized terminology is an act of isolation/seclusion. -- Danilo J. S. Bellini --------------- "*It is not our business to set up prohibitions, but to arrive at conventions.*" (R. Carnap) -------------- next part -------------- An HTML attachment was scrubbed... URL: From python at mrabarnett.plus.com Wed Aug 15 15:32:05 2018 From: python at mrabarnett.plus.com (MRAB) Date: Wed, 15 Aug 2018 20:32:05 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <9c82e0db-8472-11a4-788d-5b564a147e8d@mrabarnett.plus.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <5B71FF06.2070407@canterbury.ac.nz> <5B73DE42.90607@canterbury.ac.nz> <9c82e0db-8472-11a4-788d-5b564a147e8d@mrabarnett.plus.com> Message-ID: <9313ae77-44fe-f891-c22f-022eaefa30e5@mrabarnett.plus.com> On 2018-08-15 18:27, MRAB wrote: > On 2018-08-15 09:17, Jonathan Fine wrote: >> Steve Barnes and Greg Ewing wrote: >> >>>> * A dinosaur is specifically an extinct terrible (formerly considered) >>>> lizard >>> >>> >>> Which technically is not a lizard. >> >> I can't resist. Puffinus puffinus is the scientific name for >> >> (drum roll) >> >> no, not the Atlantic (or common) Puffin but >> >> (off-pitch fanfare) >> >> https://en.wikipedia.org/wiki/Manx_shearwater >> > While we're at it, what's the only creature that's known commonly and > only by its scientific name? > The answer is boa constrictor. From jacobsolinsky at gmail.com Wed Aug 15 14:52:27 2018 From: jacobsolinsky at gmail.com (Jacob Solinsky) Date: Wed, 15 Aug 2018 13:52:27 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function Message-ID: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> -Jumping to a function as opposed to calling a function When a function is jumped to, it inherits the variables in the caller?s local namespace and is free to modify them or add new local variables, unlike a normal function call, wherein the caller?s namespace is inaccesible. At present, the only way I know of to accomplish this is to bundle all variables in the caller method?s namespace as properties of the method?s instance and have the callee method modify those properties. Though it is easier to read code written this way, it resulted in a great deal of redundancy in the code I was writing. The task I was attempting to accomplish was approximately this: class Verb: def __init__(self, parameters): self.parameters = parameters def conjugate(self): #Using the parameters, chose an appropriate list of morphemes to prefix and suffix to the verb self.morphemelist = morphemelist for morpheme in self.morphemelist: morpheme.mutate() returnstring = ?' for morpheme in self.morphemelist: returnstring = returnstring + morpheme.form returnstring = returnstring class Morpheme: def __init__(self, verb, form, precedingmorpheme, succeedingmorpheme): self.verb = verb self.form = form self.precedingmorpheme = precedingmorpheme self.succeedingmorpheme = succeedingmorpheme def mutate(self): #Using the verb?s parameters and the type and form of the preceding and succeeding morpheme, mutate this morpheme?s form so that #a correct verb form is produced self.form = newform class Ban(Morpheme): def __init__(self, verb, form): super().__init__(verb, ?ban?) def mutate(self): #This morpheme has mutation logic unique to itself but with many similarities to the default morpheme?s mutation logic self.form = newform Each subclass of Morpheme has its own slightly different mutate method. Some subclasses of Morpheme needed to access and manipulate a great deal of information about the verb and their surroundings, while other subclasses? mutate methods differed little from the default. Most of the variables manipulated by the mutate method are not used by any other methods of class Morpheme and thus should not be made properties of the attached instance. What I wish I were able to do is write many little methods that modify the same set of local variables and compose them together into a complete mutate method. This would be effectively equivalent to having the ?jump to function? calls be replaced with the text in the function?s body, like a C language macrosubstitution, but without using anything like preprocessor directives. Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the syntax to jump to foo(a, b) def foo(a): return a + c def bar(a, c): return foo(a) def bazz(a, c): return foo(a)% c = 5 call = bar(1, 3) jump = bazz(1, 3) After execution, call in the above code would be 6 and jump in the above code would be 4. From abrault at mapgears.com Wed Aug 15 16:07:06 2018 From: abrault at mapgears.com (Alexandre Brault) Date: Wed, 15 Aug 2018 16:07:06 -0400 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <9313ae77-44fe-f891-c22f-022eaefa30e5@mrabarnett.plus.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <5B71FF06.2070407@canterbury.ac.nz> <5B73DE42.90607@canterbury.ac.nz> <9c82e0db-8472-11a4-788d-5b564a147e8d@mrabarnett.plus.com> <9313ae77-44fe-f891-c22f-022eaefa30e5@mrabarnett.plus.com> Message-ID: <03971805-7782-2cb2-a744-4e256cfdf4e2@mapgears.com> On 2018-08-15 03:32 PM, MRAB wrote: > On 2018-08-15 18:27, MRAB wrote: >> On 2018-08-15 09:17, Jonathan Fine wrote: >>> Steve Barnes and Greg Ewing wrote: >>> >>>>> ? * A dinosaur is specifically an extinct terrible (formerly >>>>> considered) >>>>> lizard >>>> >>>> >>>> Which technically is not a lizard. >>> >>> I can't resist. Puffinus puffinus is the scientific name for >>> >>> (drum roll) >>> >>> no, not the Atlantic (or common) Puffin but >>> >>> (off-pitch fanfare) >>> >>> https://en.wikipedia.org/wiki/Manx_shearwater >>> >> While we're at it, what's the only creature that's known commonly and >> only by its scientific name? >> > The answer is boa constrictor. > I would have guessed Tyrannosaurus Rex From jfine2358 at gmail.com Wed Aug 15 16:19:15 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 15 Aug 2018 21:19:15 +0100 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: Hi Jacob Thank you for your problem. I'll focus on your simple example (lightly edited for clarity) > Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the syntax to jump to foo(a, b) > > c = 5 > > def foo(a): > return a + c > > def bar(a, c): > return foo(a) > > def bazz(a, c): > return foo(a)% > > call = bar(1, 3) # 6, being 1 + 5 > bazz(1, 3) # 4, being 1 + 3 This may allow you to solve your verb and morpheme problem. But I hope there's an easier way. One that can be done using Python as it is now. My understanding is that you want a stack. Similar to the Python's function call stack, but with something extra. So that functions execute in an richer context. Here's an idea. Start by giving us a toy example of a calculation you'd like to do. Then the problem is: how to do this in Python. By the way, are there any existing Python libraries for this sort of thing? I hope this helps. -- Jonathan From rosuav at gmail.com Wed Aug 15 16:24:23 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 16 Aug 2018 06:24:23 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: On Thu, Aug 16, 2018 at 4:52 AM, Jacob Solinsky wrote: > -Jumping to a function as opposed to calling a function > > When a function is jumped to, it inherits the variables in the caller?s local namespace and is free to modify them or add new local variables, unlike a normal function call, wherein the caller?s namespace is inaccesible. At present, the only way I know of to accomplish this is to bundle all variables in the caller method?s namespace as properties of the method?s instance and have the callee method modify those properties. Though it is easier to read code written this way, it resulted in a great deal of redundancy in the code I was writing. > > Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the syntax to jump to foo(a, b) > > def foo(a): > return a + c > > def bar(a, c): > return foo(a) > > def bazz(a, c): > return foo(a)% > > c = 5 > > call = bar(1, 3) > > jump = bazz(1, 3) > > > After execution, call in the above code would be 6 and jump in the above code would be 4. You're trying to shed encapsulation (by having the jumped-to function operate in the "caller's" namespace), but also pass parameters to it. That's going to cause a lot of confusion. I'm sympathetic to the problem, but I don't think functions are the solution here. You want some form of code block. There've been a number of proposals along those lines, and so far, not one of them has been really implementable. Check out some of the prior theories and see if one of them will work for you. ChrisA From abedillon at gmail.com Wed Aug 15 17:40:36 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 15 Aug 2018 16:40:36 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: Jumping into functions that mutate variables in the calling scope sounds a lot like "GoTo" which is notorious for leading to code that's very hard to reason about. Your functions would implicitly require that you assign variables in the calling scope before calling the function instead of explicitly requiring them in the function's signature. That can be very confusing. A lot of times, when I find that my function call signatures have become unwieldy, it's a sign that I need to bundle a lot of related variables into an object and either define methods on that object or pass that object to functions instead of the large number of variables that it encapsulates. You just use 'self' as a sort-of back-pack that carries around what you need. It's difficult to see what you're after from your Verb and Morpheme example. They don't seem to call any functions that use variables from the caller's scope. Can you flesh that out a bit better? On Wed, Aug 15, 2018 at 3:24 PM, Chris Angelico wrote: > On Thu, Aug 16, 2018 at 4:52 AM, Jacob Solinsky > wrote: > > -Jumping to a function as opposed to calling a function > > > > When a function is jumped to, it inherits the variables in the caller?s > local namespace and is free to modify them or add new local variables, > unlike a normal function call, wherein the caller?s namespace is > inaccesible. At present, the only way I know of to accomplish this is to > bundle all variables in the caller method?s namespace as properties of the > method?s instance and have the callee method modify those properties. > Though it is easier to read code written this way, it resulted in a great > deal of redundancy in the code I was writing. > > > > > Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the > syntax to jump to foo(a, b) > > > > def foo(a): > > return a + c > > > > def bar(a, c): > > return foo(a) > > > > def bazz(a, c): > > return foo(a)% > > > > c = 5 > > > > call = bar(1, 3) > > > > jump = bazz(1, 3) > > > > > > After execution, call in the above code would be 6 and jump in the above > code would be 4. > > You're trying to shed encapsulation (by having the jumped-to function > operate in the "caller's" namespace), but also pass parameters to it. > That's going to cause a lot of confusion. > > I'm sympathetic to the problem, but I don't think functions are the > solution here. You want some form of code block. There've been a > number of proposals along those lines, and so far, not one of them has > been really implementable. Check out some of the prior theories and > see if one of them will work for you. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 15 17:58:48 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 16 Aug 2018 07:58:48 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: On Thu, Aug 16, 2018 at 7:40 AM, Abe Dillon wrote: > Jumping into functions that mutate variables in the calling scope sounds a > lot like "GoTo" which is notorious for leading to code that's very hard to > reason about. Your functions would implicitly require that you assign > variables in the calling scope before calling the function instead of > explicitly requiring them in the function's signature. That can be very > confusing. Drop the word "function" and it's no longer about a goto - it's about a block of code that can be deposited into another context. If you were to copy and paste that code, its meaning would be defined by where it is used; the idea of a "code block" is that you can do that with something that can be passed around like a function, but isn't a function. We could borrow a term from the Python grammar and call it a "suite", perhaps, but "code block" is probably the best term. As mentioned, there have been previous proposals along these lines. By the way: > It's difficult to see what you're after from your Verb and Morpheme example. You're responding to MY post, which is a response to Jacob's. Please watch your use of pronouns; it would help a lot if you weren't top posting, and were directly responding to specific people's specific comments. ChrisA From abedillon at gmail.com Wed Aug 15 18:21:54 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 15 Aug 2018 17:21:54 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: [Chris Angelico] > Drop the word "function" and it's no longer about a goto - it's about > a block of code that can be deposited into another context. The only context I've used goto is in a TI-83 scientific calculator, but in that, it was just about jumping around to different labels in code and had nothing to do with functions. Though this may not have been the "canonical" goto that Dijkstra considered harmful. [Chris Angelico] > By the way: > > It's difficult to see what you're after from your Verb and Morpheme > example. > You're responding to MY post, which is a response to Jacob's. Please > watch your use of pronouns; it would help a lot if you weren't top > posting, and were directly responding to specific people's specific > comments. Sorry, I ran into a lot of problems trying to use the Google Groups interface to post, so I've resorted to strictly using email. Unfortunately, that makes the structure of the conversation less obvious to me. I'll try to be more mindful of this in the future. On Wed, Aug 15, 2018 at 4:58 PM, Chris Angelico wrote: > On Thu, Aug 16, 2018 at 7:40 AM, Abe Dillon wrote: > > Jumping into functions that mutate variables in the calling scope sounds > a > > lot like "GoTo" which is notorious for leading to code that's very hard > to > > reason about. Your functions would implicitly require that you assign > > variables in the calling scope before calling the function instead of > > explicitly requiring them in the function's signature. That can be very > > confusing. > > Drop the word "function" and it's no longer about a goto - it's about > a block of code that can be deposited into another context. If you > were to copy and paste that code, its meaning would be defined by > where it is used; the idea of a "code block" is that you can do that > with something that can be passed around like a function, but isn't a > function. > > We could borrow a term from the Python grammar and call it a "suite", > perhaps, but "code block" is probably the best term. As mentioned, > there have been previous proposals along these lines. > > By the way: > > > It's difficult to see what you're after from your Verb and Morpheme > example. > > You're responding to MY post, which is a response to Jacob's. Please > watch your use of pronouns; it would help a lot if you weren't top > posting, and were directly responding to specific people's specific > comments. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Wed Aug 15 18:28:44 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 15 Aug 2018 17:28:44 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: Sorry for the double post, but I wanted to make sure you saw my original misplaced post: Jumping into functions that mutate variables in the calling scope sounds a lot like "GoTo" which is notorious for leading to code that's very hard to reason about. Your functions would implicitly require that you assign variables in the calling scope before calling the function instead of explicitly requiring them in the function's signature. That can be very confusing. A lot of times, when I find that my function call signatures have become unwieldy, it's a sign that I need to bundle a lot of related variables into an object and either define methods on that object or pass that object to functions instead of the large number of variables that it encapsulates. You just use 'self' as a sort-of back-pack that carries around what you need. It's difficult to see what you're after from your Verb and Morpheme example. They don't seem to call any functions that use variables from the caller's scope. Can you flesh that out a bit more to show where the problem arrises? -------------- next part -------------- An HTML attachment was scrubbed... URL: From jacobsolinsky at gmail.com Wed Aug 15 18:53:37 2018 From: jacobsolinsky at gmail.com (Jacob Solinsky) Date: Wed, 15 Aug 2018 17:53:37 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: What I had hoped to do was use a preamble code block to collect all of the most common queries called by the mutate function in the local namespace, for example C = 'bpgkdtszSZjCmnywh' M = 'mn' class Morpheme: #stuff def preamble(self): ps = self.precedingmorpheme.form ss = self.succeedingmorpheme.form ssc = re.match(f'^[{C}]', self.succedingmorpheme.form) #Whether or not the following morpheme is consonant initial ssm = re.match(f'[{M}]$', self.precedingmorpheme.form) #Whether or not the preceding morpheme is nasal final these local variables are used quite often in the mutate methods, of which there are several dozen, so storing them by default saves a lot of typing. class Ban(Morpheme): def __init__(self): super().__init__(verb, precedingmorpheme, succeedingmorpheme, form = 'ban') def mutate(self): self.preamble()% if ps[-1] == 'd': self.form = 'p' + self.form[1:] self.preceding.form = '' if ssc: self.form = self.form + 'E' if ssm: self.form = re.sub('an', 'An', self.form) What I actually ended up doing is placing these queries in the Morpheme __init__ method def __init__(self, ...): self.ps = self.precedingmorpheme.form self.ss = self.succeedingmorpheme.form self.ssc = re.match(f'^[{C}]', self.succedingmorpheme.form) #Whether or not the following morpheme is consonant initial self.ssm = re.match(f'[{M}]$', self.precedingmorpheme.form) #Whether or not the preceding morpheme is nasal final This works perfectly fine, but I found cluttering the Morpheme object instances with flags and such to be inelegant, since these flags are only used by the mutate method. Also, without using a hacky solution like making Morpheme a subclass of types.SimpleNamespace, every new flag I might want to inject has to have a default value set in the __init__ method to prevent an AttributeError from being raised. Anyways, I will look around in the mail list for discussions of Code blocks, now that I know they are called. On Wed, 15 Aug 2018, 16:41 Abe Dillon, wrote: > Jumping into functions that mutate variables in the calling scope sounds a > lot like "GoTo" which > is notorious for leading to code that's very hard to reason about. Your > functions would implicitly require that you assign variables in the calling > scope before calling the function instead of explicitly requiring them in > the function's signature. That can be very confusing. > > A lot of times, when I find that my function call signatures have become > unwieldy, it's a sign that I need to bundle a lot of related variables into > an object and either define methods on that object or pass that object to > functions instead of the large number of variables that it encapsulates. > You just use 'self' as a sort-of back-pack that carries around what you > need. > > It's difficult to see what you're after from your Verb and Morpheme > example. They don't seem to call any functions that use variables from the > caller's scope. Can you flesh that out a bit better? > > > On Wed, Aug 15, 2018 at 3:24 PM, Chris Angelico wrote: > >> On Thu, Aug 16, 2018 at 4:52 AM, Jacob Solinsky >> wrote: >> > -Jumping to a function as opposed to calling a function >> > >> > When a function is jumped to, it inherits the variables in the caller?s >> local namespace and is free to modify them or add new local variables, >> unlike a normal function call, wherein the caller?s namespace is >> inaccesible. At present, the only way I know of to accomplish this is to >> bundle all variables in the caller method?s namespace as properties of the >> method?s instance and have the callee method modify those properties. >> Though it is easier to read code written this way, it resulted in a great >> deal of redundancy in the code I was writing. >> > >> >> > Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the >> syntax to jump to foo(a, b) >> > >> > def foo(a): >> > return a + c >> > >> > def bar(a, c): >> > return foo(a) >> > >> > def bazz(a, c): >> > return foo(a)% >> > >> > c = 5 >> > >> > call = bar(1, 3) >> > >> > jump = bazz(1, 3) >> > >> > >> > After execution, call in the above code would be 6 and jump in the >> above code would be 4. >> >> You're trying to shed encapsulation (by having the jumped-to function >> operate in the "caller's" namespace), but also pass parameters to it. >> That's going to cause a lot of confusion. >> >> I'm sympathetic to the problem, but I don't think functions are the >> solution here. You want some form of code block. There've been a >> number of proposals along those lines, and so far, not one of them has >> been really implementable. Check out some of the prior theories and >> see if one of them will work for you. >> >> ChrisA >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 15 19:09:58 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 16 Aug 2018 09:09:58 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: On Thu, Aug 16, 2018 at 8:53 AM, Jacob Solinsky wrote: > What I had hoped to do was use a preamble code block to collect all of the > most common queries called by the mutate function in the local namespace, > for example > > C = 'bpgkdtszSZjCmnywh' > M = 'mn' > > > class Morpheme: > #stuff > > def preamble(self): > > ps = self.precedingmorpheme.form > ss = self.succeedingmorpheme.form > ssc = re.match(f'^[{C}]', self.succedingmorpheme.form) #Whether or not > the following morpheme is consonant initial > ssm = re.match(f'[{M}]$', self.precedingmorpheme.form) #Whether or not > the preceding morpheme is nasal final > > these local variables are used quite often in the mutate methods, of which > there are several dozen, so storing them by default saves a lot of typing. > Ahh, I see what you mean. I was thinking the other way - a single mutate function that has a part in there saying "now run the code block for this particular subclass". What would be really nice would be something like: from preamble() import * I'm fairly sure that (per se) isn't going to fly, but it would be interesting as a concept. Would need a new spelling. The quirky part of my brain is trying to figure if class namespace can be abused for this. ChrisA From mertz at gnosis.cx Wed Aug 15 20:35:35 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 15 Aug 2018 20:35:35 -0400 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: Goto considered harmful. https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR On Wed, Aug 15, 2018, 3:52 PM Jacob Solinsky wrote: > -Jumping to a function as opposed to calling a function > > When a function is jumped to, it inherits the variables in the caller?s > local namespace and is free to modify them or add new local variables, > unlike a normal function call, wherein the caller?s namespace is > inaccesible. At present, the only way I know of to accomplish this is to > bundle all variables in the caller method?s namespace as properties of the > method?s instance and have the callee method modify those properties. > Though it is easier to read code written this way, it resulted in a great > deal of redundancy in the code I was writing. The task I was attempting to > accomplish was approximately this: > > class Verb: > def __init__(self, parameters): > self.parameters = parameters > def conjugate(self): > #Using the parameters, chose an appropriate list of > morphemes to prefix and suffix to the verb > self.morphemelist = morphemelist > for morpheme in self.morphemelist: > morpheme.mutate() > returnstring = ?' > for morpheme in self.morphemelist: > returnstring = returnstring + morpheme.form > returnstring = returnstring > > class Morpheme: > def __init__(self, verb, form, precedingmorpheme, > succeedingmorpheme): > self.verb = verb > self.form = form > self.precedingmorpheme = precedingmorpheme > self.succeedingmorpheme = succeedingmorpheme > def mutate(self): > #Using the verb?s parameters and the type and form of the > preceding and succeeding morpheme, mutate this morpheme?s form so that > #a correct verb form is produced > self.form = newform > > class Ban(Morpheme): > def __init__(self, verb, form): > super().__init__(verb, ?ban?) > def mutate(self): > #This morpheme has mutation logic unique to itself but > with many similarities to the default morpheme?s mutation logic > self.form = newform > > Each subclass of Morpheme has its own slightly different mutate method. > Some subclasses of Morpheme needed to access and manipulate a great deal of > information about the verb and their surroundings, while other subclasses? > mutate methods differed little from the default. Most of the variables > manipulated by the mutate method are not used by any other methods of class > Morpheme and thus should not be made properties of the attached instance. > What I wish I were able to do is write many little methods that modify the > same set of local variables and compose them together into a complete > mutate method. This would be effectively equivalent to having the ?jump to > function? calls be replaced with the text in the function?s body, like a C > language macrosubstitution, but without using anything like preprocessor > directives. > > Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the > syntax to jump to foo(a, b) > > def foo(a): > return a + c > > def bar(a, c): > return foo(a) > > def bazz(a, c): > return foo(a)% > > c = 5 > > call = bar(1, 3) > > jump = bazz(1, 3) > > > After execution, call in the above code would be 6 and jump in the above > code would be 4. > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Wed Aug 15 20:38:34 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 15 Aug 2018 20:38:34 -0400 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: Hmm.. link broke. Is this right? https://www.google.com/url?sa=t&source=web&rct=j&url=https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR On Wed, Aug 15, 2018, 8:35 PM David Mertz wrote: > Goto considered harmful. > > > https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR > > On Wed, Aug 15, 2018, 3:52 PM Jacob Solinsky > wrote: > >> -Jumping to a function as opposed to calling a function >> >> When a function is jumped to, it inherits the variables in the caller?s >> local namespace and is free to modify them or add new local variables, >> unlike a normal function call, wherein the caller?s namespace is >> inaccesible. At present, the only way I know of to accomplish this is to >> bundle all variables in the caller method?s namespace as properties of the >> method?s instance and have the callee method modify those properties. >> Though it is easier to read code written this way, it resulted in a great >> deal of redundancy in the code I was writing. The task I was attempting to >> accomplish was approximately this: >> >> class Verb: >> def __init__(self, parameters): >> self.parameters = parameters >> def conjugate(self): >> #Using the parameters, chose an appropriate list of >> morphemes to prefix and suffix to the verb >> self.morphemelist = morphemelist >> for morpheme in self.morphemelist: >> morpheme.mutate() >> returnstring = ?' >> for morpheme in self.morphemelist: >> returnstring = returnstring + morpheme.form >> returnstring = returnstring >> >> class Morpheme: >> def __init__(self, verb, form, precedingmorpheme, >> succeedingmorpheme): >> self.verb = verb >> self.form = form >> self.precedingmorpheme = precedingmorpheme >> self.succeedingmorpheme = succeedingmorpheme >> def mutate(self): >> #Using the verb?s parameters and the type and form of the >> preceding and succeeding morpheme, mutate this morpheme?s form so that >> #a correct verb form is produced >> self.form = newform >> >> class Ban(Morpheme): >> def __init__(self, verb, form): >> super().__init__(verb, ?ban?) >> def mutate(self): >> #This morpheme has mutation logic unique to itself but >> with many similarities to the default morpheme?s mutation logic >> self.form = newform >> >> Each subclass of Morpheme has its own slightly different mutate method. >> Some subclasses of Morpheme needed to access and manipulate a great deal of >> information about the verb and their surroundings, while other subclasses? >> mutate methods differed little from the default. Most of the variables >> manipulated by the mutate method are not used by any other methods of class >> Morpheme and thus should not be made properties of the attached instance. >> What I wish I were able to do is write many little methods that modify the >> same set of local variables and compose them together into a complete >> mutate method. This would be effectively equivalent to having the ?jump to >> function? calls be replaced with the text in the function?s body, like a C >> language macrosubstitution, but without using anything like preprocessor >> directives. >> >> Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the >> syntax to jump to foo(a, b) >> >> def foo(a): >> return a + c >> >> def bar(a, c): >> return foo(a) >> >> def bazz(a, c): >> return foo(a)% >> >> c = 5 >> >> call = bar(1, 3) >> >> jump = bazz(1, 3) >> >> >> After execution, call in the above code would be 6 and jump in the above >> code would be 4. >> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ericfahlgren at gmail.com Wed Aug 15 20:38:42 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Wed, 15 Aug 2018 17:38:42 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: How about just https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf On Wed, Aug 15, 2018 at 5:38 PM David Mertz wrote: > Hmm.. link broke. Is this right? > > > https://www.google.com/url?sa=t&source=web&rct=j&url=https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR > > On Wed, Aug 15, 2018, 8:35 PM David Mertz wrote: > >> Goto considered harmful. >> >> >> https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR >> >> On Wed, Aug 15, 2018, 3:52 PM Jacob Solinsky >> wrote: >> >>> -Jumping to a function as opposed to calling a function >>> >>> When a function is jumped to, it inherits the variables in the caller?s >>> local namespace and is free to modify them or add new local variables, >>> unlike a normal function call, wherein the caller?s namespace is >>> inaccesible. At present, the only way I know of to accomplish this is to >>> bundle all variables in the caller method?s namespace as properties of the >>> method?s instance and have the callee method modify those properties. >>> Though it is easier to read code written this way, it resulted in a great >>> deal of redundancy in the code I was writing. The task I was attempting to >>> accomplish was approximately this: >>> >>> class Verb: >>> def __init__(self, parameters): >>> self.parameters = parameters >>> def conjugate(self): >>> #Using the parameters, chose an appropriate list of >>> morphemes to prefix and suffix to the verb >>> self.morphemelist = morphemelist >>> for morpheme in self.morphemelist: >>> morpheme.mutate() >>> returnstring = ?' >>> for morpheme in self.morphemelist: >>> returnstring = returnstring + morpheme.form >>> returnstring = returnstring >>> >>> class Morpheme: >>> def __init__(self, verb, form, precedingmorpheme, >>> succeedingmorpheme): >>> self.verb = verb >>> self.form = form >>> self.precedingmorpheme = precedingmorpheme >>> self.succeedingmorpheme = succeedingmorpheme >>> def mutate(self): >>> #Using the verb?s parameters and the type and form of >>> the preceding and succeeding morpheme, mutate this morpheme?s form so that >>> #a correct verb form is produced >>> self.form = newform >>> >>> class Ban(Morpheme): >>> def __init__(self, verb, form): >>> super().__init__(verb, ?ban?) >>> def mutate(self): >>> #This morpheme has mutation logic unique to itself but >>> with many similarities to the default morpheme?s mutation logic >>> self.form = newform >>> >>> Each subclass of Morpheme has its own slightly different mutate method. >>> Some subclasses of Morpheme needed to access and manipulate a great deal of >>> information about the verb and their surroundings, while other subclasses? >>> mutate methods differed little from the default. Most of the variables >>> manipulated by the mutate method are not used by any other methods of class >>> Morpheme and thus should not be made properties of the attached instance. >>> What I wish I were able to do is write many little methods that modify the >>> same set of local variables and compose them together into a complete >>> mutate method. This would be effectively equivalent to having the ?jump to >>> function? calls be replaced with the text in the function?s body, like a C >>> language macrosubstitution, but without using anything like preprocessor >>> directives. >>> >>> Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the >>> syntax to jump to foo(a, b) >>> >>> def foo(a): >>> return a + c >>> >>> def bar(a, c): >>> return foo(a) >>> >>> def bazz(a, c): >>> return foo(a)% >>> >>> c = 5 >>> >>> call = bar(1, 3) >>> >>> jump = bazz(1, 3) >>> >>> >>> After execution, call in the above code would be 6 and jump in the above >>> code would be 4. >>> >>> >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From elazarg at gmail.com Wed Aug 15 20:55:13 2018 From: elazarg at gmail.com (Elazar) Date: Wed, 15 Aug 2018 17:55:13 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: I have no opinion on the proposal, but the equation with goto is dead wrong. Yes, technically this is a goto. But so is a regular function call. Jumping to a function makes thd code _easier_ to reason about, statically, not harder. When you call an arbitrary function, you have no idea whether it will return or not. When you jump to a function, you _know_ it will not return. That's strictly more information, based solely on the syntax of the statement. Yes, if you have local functions mutating the state then jumpung to them makes the code difficult to read. *but so is calling them*, with the addition of the returning that you have to track. Jumping to functions is procedural programming. There is no reasonfor it to be "considered harmful" any more than calling funcions; indeed even less so. Elazar On Wed, Aug 15, 2018, 17:42 Eric Fahlgren wrote: > How about just > https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf > > On Wed, Aug 15, 2018 at 5:38 PM David Mertz wrote: > >> Hmm.. link broke. Is this right? >> >> >> https://www.google.com/url?sa=t&source=web&rct=j&url=https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR >> >> On Wed, Aug 15, 2018, 8:35 PM David Mertz wrote: >> >>> Goto considered harmful. >>> >>> >>> https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf&ved=2ahUKEwi8lqHYqfDcAhXImOAKHeAzDmsQFjAEegQIBhAB&usg=AOvVaw1CZug_36-PbevItYXTb7SR >>> >>> On Wed, Aug 15, 2018, 3:52 PM Jacob Solinsky >>> wrote: >>> >>>> -Jumping to a function as opposed to calling a function >>>> >>>> When a function is jumped to, it inherits the variables in the caller?s >>>> local namespace and is free to modify them or add new local variables, >>>> unlike a normal function call, wherein the caller?s namespace is >>>> inaccesible. At present, the only way I know of to accomplish this is to >>>> bundle all variables in the caller method?s namespace as properties of the >>>> method?s instance and have the callee method modify those properties. >>>> Though it is easier to read code written this way, it resulted in a great >>>> deal of redundancy in the code I was writing. The task I was attempting to >>>> accomplish was approximately this: >>>> >>>> class Verb: >>>> def __init__(self, parameters): >>>> self.parameters = parameters >>>> def conjugate(self): >>>> #Using the parameters, chose an appropriate list of >>>> morphemes to prefix and suffix to the verb >>>> self.morphemelist = morphemelist >>>> for morpheme in self.morphemelist: >>>> morpheme.mutate() >>>> returnstring = ?' >>>> for morpheme in self.morphemelist: >>>> returnstring = returnstring + morpheme.form >>>> returnstring = returnstring >>>> >>>> class Morpheme: >>>> def __init__(self, verb, form, precedingmorpheme, >>>> succeedingmorpheme): >>>> self.verb = verb >>>> self.form = form >>>> self.precedingmorpheme = precedingmorpheme >>>> self.succeedingmorpheme = succeedingmorpheme >>>> def mutate(self): >>>> #Using the verb?s parameters and the type and form of >>>> the preceding and succeeding morpheme, mutate this morpheme?s form so that >>>> #a correct verb form is produced >>>> self.form = newform >>>> >>>> class Ban(Morpheme): >>>> def __init__(self, verb, form): >>>> super().__init__(verb, ?ban?) >>>> def mutate(self): >>>> #This morpheme has mutation logic unique to itself but >>>> with many similarities to the default morpheme?s mutation logic >>>> self.form = newform >>>> >>>> Each subclass of Morpheme has its own slightly different mutate method. >>>> Some subclasses of Morpheme needed to access and manipulate a great deal of >>>> information about the verb and their surroundings, while other subclasses? >>>> mutate methods differed little from the default. Most of the variables >>>> manipulated by the mutate method are not used by any other methods of class >>>> Morpheme and thus should not be made properties of the attached instance. >>>> What I wish I were able to do is write many little methods that modify the >>>> same set of local variables and compose them together into a complete >>>> mutate method. This would be effectively equivalent to having the ?jump to >>>> function? calls be replaced with the text in the function?s body, like a C >>>> language macrosubstitution, but without using anything like preprocessor >>>> directives. >>>> >>>> Let foo(a, b) be the syntax to call foo(a, b), and foo(a, b)% be the >>>> syntax to jump to foo(a, b) >>>> >>>> def foo(a): >>>> return a + c >>>> >>>> def bar(a, c): >>>> return foo(a) >>>> >>>> def bazz(a, c): >>>> return foo(a)% >>>> >>>> c = 5 >>>> >>>> call = bar(1, 3) >>>> >>>> jump = bazz(1, 3) >>>> >>>> >>>> After execution, call in the above code would be 6 and jump in the >>>> above code would be 4. >>>> >>>> >>>> _______________________________________________ >>>> Python-ideas mailing list >>>> Python-ideas at python.org >>>> https://mail.python.org/mailman/listinfo/python-ideas >>>> Code of Conduct: http://python.org/psf/codeofconduct/ >>>> >>> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Wed Aug 15 21:20:17 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 16 Aug 2018 11:20:17 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: <20180816012017.GV22431@ando.pearwood.info> On Wed, Aug 15, 2018 at 01:52:27PM -0500, Jacob Solinsky wrote: > -Jumping to a function as opposed to calling a function > > When a function is jumped to, it inherits the variables in the > caller?s local namespace and is free to modify them or add new local > variables, unlike a normal function call, wherein the caller?s > namespace is inaccesible. I think that the standard term for what you want is *dynamic scoping*. http://wiki.c2.com/?DynamicScoping http://leafo.net/guides/dynamic-scoping-in-lua.html The most common language today that uses dynamic scoping is probably Emacs Lisp. Although dynamic scoping is very powerful, it is also harder to implement correctly (so I believe) and harder to reason about. It is generally considered that dynamic scoping is equivalent to the exclusive use of global variables (all functions see the same variables, no matter where they are defined), so the use of dynamic scoping gives up the benefits of local variables. (See also "Global variables considered harmful".) > At present, the only way I know of to > accomplish this is to bundle all variables in the caller method?s > namespace as properties of the method?s instance and have the callee > method modify those properties. This would generally be considered a severe violation of the Law of Demeter, one of the most important principles for reducing coupling between software components: https://www2.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/LawOfDemeter.htm http://www.ccs.neu.edu/home/lieber/LoD.html but also one of the most misunderstood. (Anyone who tells you that the LoD is "never use more than one dot" is wrong.) As far as I am concerned, reducing coupling between software components is the single most important design principle there is. But what do we do when the problem you are trying to solve inherently has a lot of coupling between data components? I think that computer science doesn't have a lot to say about such hard problems, apart from "avoid them". > Though it is easier to read code > written this way, it resulted in a great deal of redundancy in the > code I was writing. The task I was attempting to accomplish was > approximately this: What you quoted was not a description of the task, but a concrete implementation of one possible solution to the task. You are describing *how* you want to do it, but you haven't described what *it* is. This is not the place for it, but generally you should describe the functional requirements, not the implementation. You have Nouns, and Verbs, but what do you want to do with them? What is the high-level behaviour? If you focus on implementation too early, you may blind yourself to simpler solutions that accomplish the same end using a completely different means. A light-hearted example: "How do I turn the temperature of my refridgerator up? I need to boil some water, but the temperature control of the fridge only goes up to about 10?C (50?F)." "Why don't you use the stove or microwave oven?" "Because... that is to say... I... okay." Since I don't understand your functional requirements, I don't know whether you are dealing with a situation which inherently requires high coupling, or if you are missing a solution which would avoid the need for global variables or dynamic scoping. [...] > Each subclass of Morpheme has its own slightly different mutate > method. Some subclasses of Morpheme needed to access and manipulate a > great deal of information about the verb and their surroundings, This suggests to me that a solution might be to generate and pass around some sort of *context object* for each word you operate on. The obvious problems with this include: - you have to generate that context object for every word, whether it will use it or not; - in principle, the amount of context needed could be unbounded; one word may only need information from the previous word, while another word in a long run-on sentence may need information from half a page back. > while > other subclasses? mutate methods differed little from the default. > Most of the variables manipulated by the mutate method are not used by > any other methods of class Morpheme and thus should not be made > properties of the attached instance. What I wish I were able to do is > write many little methods that modify the same set of local variables > and compose them together into a complete mutate method. Closures are the exact equivalent of classes. If you have a solution (however clumsy) that works with classes, you should be able to re-write it in terms of closures. Whether that solution is less clumsy remains to be seen! So you can have something like this: def environment(): a = 1 b = 2 # define some closures def change1(): nonlocal a a += 1 def change2(): nonlocal a, b a += 2 b += 3 def inspect(): nonlocal a, b print(a, b) return (change1, change2, inspect) With those three closures, I can modify and inspect the variables defined by environment. Whether this technique simplifies your problem, I don't know. But if it is, it is surely easier than (1) convincing the core devs to add a new function call rule to Python, and (2) waiting for it to be implemented and released (which cannot be before version 3.8). (And yes, I agree that both the class-based and closure-based solution requires a lot of boilerplate, which is a bad thing.) -- Steve From greg.ewing at canterbury.ac.nz Wed Aug 15 21:31:04 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 16 Aug 2018 13:31:04 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <03971805-7782-2cb2-a744-4e256cfdf4e2@mapgears.com> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <5B71FF06.2070407@canterbury.ac.nz> <5B73DE42.90607@canterbury.ac.nz> <9c82e0db-8472-11a4-788d-5b564a147e8d@mrabarnett.plus.com> <9313ae77-44fe-f891-c22f-022eaefa30e5@mrabarnett.plus.com> <03971805-7782-2cb2-a744-4e256cfdf4e2@mapgears.com> Message-ID: <5B74D3D8.5010405@canterbury.ac.nz> Alexandre Brault wrote: > On 2018-08-15 03:32 PM, MRAB wrote: > >>On 2018-08-15 18:27, MRAB wrote: > >>>While we're at it, what's the only creature that's known commonly and >>>only by its scientific name? > > I would have guessed Tyrannosaurus Rex I would have thought pretty much any dinosaur. -- Greg From abedillon at gmail.com Wed Aug 15 21:36:25 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 15 Aug 2018 20:36:25 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: [Jacob Solinsky] > these local variables are used quite often in the mutate methods, of which > there are several dozen, so storing them by default saves a lot of typing. There are several things you can do to alleviate the typing problem: 1) Get an IDE that has auto-complete. I recommend PyCharm Community Edition, but there are several. 2) Use better naming: there are many shorter synonyms for "preceding" and "succeding" and the word "morpheme" is redundant. 3) define as much as you can in the higher scopes: C = re.compile("^[bpgkdtszSZjCmnywh]").match M = re.compile("^[mn]$").match class Morpheme: @property def pf(self): return self.pre.form @property def sf(self): return self.suc.form @property def precm(self): return C(self.pf) @property def sucmm(self): return M(self.sf) ... I think what would help most of all is reorganizing your code. As I understand it, a morpheme is the "smallest grammatical unit in a language" so maybe it makes more sense to make the morpheme class fairly simple and not have a morpheme have any inherent awareness of its preceding or succeeding morphemes. That seems like the job of a larger construct that would deal with sequences of morphemes. The way you have it right now, the morpheme seems to play a double role a linked-list and a gramatical unit. [Jacob Solinsky] > I found cluttering the Morpheme object instances with flags and such to be > inelegant, since these flags are only used by the mutate method. > That may be an indicator that you're trying to do too much with the morpheme class. [Jacob Solinsky] > Also, without using a hacky solution like making Morpheme a subclass of > types.SimpleNamespace, every new flag I might want to inject has to have a > default value set in the __init__ method to prevent an AttributeError from > being raised. Yes, you typically want to define all your object attributes in __init__ otherwise your objects become fragile and can break if you don't call the right methods in the right order. It's generally considered a bad idea to define instance attributes anywhere else unless it's something like a "private" helper method that gets called inside __init__. [Jacob Solinsky] > Anyways, I will look around in the mail list for discussions of Code > blocks, now that I know they are called. Don't take this the wrong way, but it might be better to acquaint yourself with the set of tools already available before looking for new ones. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Wed Aug 15 21:34:58 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 16 Aug 2018 11:34:58 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: <20180816013458.GW22431@ando.pearwood.info> On Wed, Aug 15, 2018 at 08:35:35PM -0400, David Mertz wrote: > Goto considered harmful. Fortunately this proposal has nothing to do with goto. Elazar is correct that its a kind of subroutine call, just like an ordinary function call, except the scoping rules are different. And for the record, not everyone agrees that Dijkstra is correct about goto. Certainly unstructured code is harmful, but we use restricted forms of goto all the time, we just don't call it by that name: - loops - continue - break - if...else - function calls - exception handling Just like goto, these are all jumps which change the execution order of your code. And some people defend limited, careful use of explicit goto, including Donald Knuth. -- Steve From mertz at gnosis.cx Wed Aug 15 21:58:28 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 15 Aug 2018 21:58:28 -0400 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180816013458.GW22431@ando.pearwood.info> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> Message-ID: When did you last read the Dijkstra paper. It's short and he explains very well why exactly all the constructs you mention are unlike Goto. This isn't a proposal to subroutines, it's a proposal for subroutines in which all lexically scoped variables are implicitly nonlocal. That's basically Goto, certainly course enough to suffer all of Dijkstra's complaints. Yes, technically this could be called dynamic scope instead. But notwithstanding the use in elisp, that's pretty widely regarded as a bad ideas (even by the emacs developers who regret that early decision). On Wed, Aug 15, 2018, 9:41 PM Steven D'Aprano wrote: > On Wed, Aug 15, 2018 at 08:35:35PM -0400, David Mertz wrote: > > > Goto considered harmful. > > Fortunately this proposal has nothing to do with goto. > > Elazar is correct that its a kind of subroutine call, just like an > ordinary function call, except the scoping rules are different. > > And for the record, not everyone agrees that Dijkstra is correct about > goto. Certainly unstructured code is harmful, but we use restricted > forms of goto all the time, we just don't call it by that name: > > - loops > - continue > - break > - if...else > - function calls > - exception handling > > Just like goto, these are all jumps which change the execution order of > your code. And some people defend limited, careful use of explicit goto, > including Donald Knuth. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Thu Aug 16 02:00:18 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Thu, 16 Aug 2018 08:00:18 +0200 Subject: [Python-ideas] Hi! Message-ID: Hi, Please let me briefly introduce myself. I'm Marko and live in Zurich, Switzerland. I learned Python and Django during an intership in 2007 and followed its development ever since. I did research in computer vision (at ETH Zurich) and now I work at Parquery AG (Zurich, Switzerland) where we implement most of our infra-structure in Python 3. Cheers, Marko -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Thu Aug 16 02:06:38 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Thu, 16 Aug 2018 08:06:38 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions Message-ID: Hi, I would be very interested to bring design-by-contract into python 3. I find design-by-contract particularly interesting and indispensable for larger projects and automatic generation of unit tests. I looked at some of the packages found on pypi and also we rolled our own solution (https://github.com/Parquery/icontract/). I also looked into https://www.python.org/dev/peps/pep-0316/. However, all the current solutions seem quite clunky to me. The decorators involve an unnecessary computational overhead and the implementation of icontract became quite tricky once we wanted to get the default values of the decorated function. Could somebody update me on the state of the discussion on this matter? I'm very grateful for any feedback on this! -------------- next part -------------- An HTML attachment was scrubbed... URL: From elazarg at gmail.com Thu Aug 16 03:18:55 2018 From: elazarg at gmail.com (Elazar) Date: Thu, 16 Aug 2018 00:18:55 -0700 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: You might also be interested in pep-563 . although it is not intended for design by contract, it can help (syntactically). Elazar On Wed, Aug 15, 2018 at 11:07 PM Marko Ristin-Kaufmann < marko.ristin at gmail.com> wrote: > Hi, > > I would be very interested to bring design-by-contract into python 3. I > find design-by-contract particularly interesting and indispensable for > larger projects and automatic generation of unit tests. > > I looked at some of the packages found on pypi and also we rolled our own > solution (https://github.com/Parquery/icontract/). I also looked into > https://www.python.org/dev/peps/pep-0316/. > > However, all the current solutions seem quite clunky to me. The decorators > involve an unnecessary computational overhead and the implementation of > icontract became quite tricky once we wanted to get the default values of > the decorated function. > > Could somebody update me on the state of the discussion on this matter? > > I'm very grateful for any feedback on this! > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Thu Aug 16 04:28:43 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 16 Aug 2018 18:28:43 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> Message-ID: <20180816082843.GX22431@ando.pearwood.info> On Wed, Aug 15, 2018 at 09:58:28PM -0400, David Mertz wrote: > When did you last read the Dijkstra paper. It's short and he explains very > well why exactly all the constructs you mention are unlike Goto. Of course I've read it, and no he does not. He only mentions if...else and looping. He doesn't mention break, continue, exceptions (I don't think exceptions had even been invented in 1968). I think that if Dijkstra were still alive, he would probably chose to understate or dismiss the similarities between goto and break/continue. Others might choose to focus on the similarities rather than the differences, e.g. "continue" is just a goto to the start of the loop, "break" is goto the end of the loop. But this isn't a debate over the pros and cons of goto. Goto is not relevant. This proposal is for dynamic scoping, not a way to change execution order or jump from one part of code to another. > This isn't a proposal to subroutines, it's a proposal for subroutines in > which all lexically scoped variables are implicitly nonlocal. Language fail :-) "This isn't a proposal for subroutines, it's a proposal for subroutines" :-) I've read the proposal differently, for dynamic scoping, not lexical scoping plus implicit nonlocal. It may be that you could get similar results from either, but they are fundamentally different. Python already has a kind of dynamic "scoping" (of sorts) which you probably use every day and never think twice about it. When an exception occurs, the scope of the exception handlers is the runtime call stack, not the lexical scope. There's nothing *inherently* bad about dynamic resolution of FOO, for any value of FOO (be it inheritence and method resolution, attribute lookup, scoping, or exception handling). It has its pros and cons, of course. I'd even allow that if overused or misused, dynamic scoping will be hard to reason about. (I believe it was Guy Steele who proved that dynamic scoping is equivalent to a single global scope, but of course that only applies when *all* functions are *always* dynamically scoped.) Just as we allow global variables for those odd cases where they are needed (or even just because it is more convienent), so there's a case for allowing dynamic scoping. Especially when the alternatives (classes, closures) are clumsy, difficult to get right, full of duplicated code and boilerplate. I wouldn't want every function call to use dynamic scoping, but there are times where I have really wanted to access the caller's environment, not the environment where my function was defined. We ought to give this concept a fair shake, not just dismiss it on the basis of platitudes "X considered harmful", especially when X isn't even relevant. > That's basically Goto Its nothing like goto, except to the (small) degree that any jump to a subroutine is a goto. > certainly course enough to suffer all of Dijkstra's > complaints. > > Yes, technically this could be called dynamic scope instead. But > notwithstanding the use in elisp, that's pretty widely regarded as a bad > ideas (even by the emacs developers who regret that early decision). Richard Stallman doesn't. I'm sure you can still find thousands of Python developers who regret that it uses significant whitespace and no braces. I know you can find Python developers who hate "lambda", and I know some who don't understand comprehensions and regret their inclusion in the language. Just about every proposal for new syntax is objected to, sometimes vehemently enough to drive Guido into "permanent vacation" (retirement) from his position of BDFL :-( So yes, I'm sure that some Emacs developers think dynamic scoping is a mistake, just as some Python developers think FOO is a mistake, for just about any value of FOO you can think of. -- Steve From contact at brice.xyz Thu Aug 16 04:31:28 2018 From: contact at brice.xyz (Brice Parent) Date: Thu, 16 Aug 2018 10:31:28 +0200 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: <4b3ad41b-fbff-d53b-94c9-ef8f12dfa888@brice.xyz> If I understand well the need (I'm unsure I've had it myself), it would be easier to be able to import the function in the active context, like this: def foo(a): ??? return a + c def bar(a, c): ??? return foo(a) def bazz(a, c): ??? import __file__.foo ??? return foo(a) c = 5 call = bar(1, 3)? # -> 6 jump = bazz(1, 3)? # -> 4 bazz would be equivalent to: def bazz(a, c): ??? def foo(a): ??????? return a + c ??? return foo(a) I'm not saying the syntax is the one that should be used (__file__ possibly not existing may be a problem), not even saying that we should have this. I'm just showing a way to do the same thing with an easier (to me) syntax. - Brice From jfine2358 at gmail.com Thu Aug 16 05:40:03 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 10:40:03 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: Hi Marko Thank you for introducing yourself, and clearly stating your question. That helps us all. You asked: > Could somebody update me on the state of the discussion on this matter? I think bring the existing PEP up to date would be a good starting point. Its content hasn't been changed since 2003 (except for PEP-wide admin changes. (Recall that Python 3.0 was released in 2008.) https://www.python.org/dev/peps/pep-0316/ https://github.com/python/peps/commits/master/pep-0316.txt In fact, revising the PEP might be enough to answer your question. What do you think, Marko? Experts: is there a process for revising old PEPs, such as this one? Or at least a precedent we could follow (or adapt)? -- Jonathan From p.f.moore at gmail.com Thu Aug 16 06:23:10 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 16 Aug 2018 11:23:10 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: On Thu, 16 Aug 2018 at 10:41, Jonathan Fine wrote: > > Hi Marko > > Thank you for introducing yourself, and clearly stating your question. > That helps us all. You asked: > > > Could somebody update me on the state of the discussion on this matter? > > I think bring the existing PEP up to date would be a good starting > point. Its content hasn't been changed since 2003 (except for PEP-wide > admin changes. (Recall that Python 3.0 was released in 2008.) > > https://www.python.org/dev/peps/pep-0316/ > https://github.com/python/peps/commits/master/pep-0316.txt > > In fact, revising the PEP might be enough to answer your question. > What do you think, Marko? > > Experts: is there a process for revising old PEPs, such as this one? > Or at least a precedent we could follow (or adapt)? I'm not aware of a formal process, but I'd have thought the following steps would be a reasonable approach: 1. Review the PEP, and research the discussions that happened at the time, particularly of interest is why the PEP was deferred. 2. Consider what (if anything) has changed since the original deferral (which could simply be "time has moved on, people's views may have changed" but ideally would include a bit more in the way of concrete motivation). 3. Contact the original PEP author and ask if he is interested in reopening the discussion, collaborating on a revision, or handing the PEP over. 4. Start up a discussion here, pointing out the original PEP and summarising the previous debate and why you want to restart the discussion. If you're hoping to change the details of the original PEP, summarise your changes and why you feel they are an improvement over the original. To answer the OP's question more directly: > Could somebody update me on the state of the discussion on this matter? As far as I am aware, there has been no discussion on this subject since the PEP 316 discussions which ended up in its deferral. Elazar mentioned PEP 563, and there *may* have been mention of design by contract uses in the discussions on that PEP, but you'd have to search the mailing list archives to confirm that one way or another. Hence the suggestions that if you want to restart discussion, reviving PEP 316 is likely the best approach. Paul From rhodri at kynesim.co.uk Thu Aug 16 07:30:08 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Thu, 16 Aug 2018 12:30:08 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: Message-ID: <2d32f9fa-0b41-e63d-81ad-5f659fc05871@kynesim.co.uk> On 15/08/18 19:55, Jonathan Fine wrote: > Rhodri says my version, exaggerated for effect, reads like >> Sometimes a value is required. But (pay careful attention >> to this, it's important and there will be a quiz later) >> we're not able to provide one. > Yes, Rhodri, you've understood what I'm doing. I do want the reader to > pay careful attention. If they only remember one thing, this is what I > want them to remember. I think you've missed your target. What people are going to remember from this construction is that sometimes we aren't able to provide a value. Oh, and you said something afterwards, was it about None? I tend to be prolix and I know it. I appreciate people who can communicate effectively in short sentences. For the most part that's what you do admirably. This one, however, is too short, and the conjunction waves a big red flag to indicate it. -- Rhodri James *-* Kynesim Ltd From mistersheik at gmail.com Thu Aug 16 08:39:20 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 16 Aug 2018 05:39:20 -0700 (PDT) Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: <20180723183006.GA25280@carrot.tutnicht.de> References: <20180723183006.GA25280@carrot.tutnicht.de> Message-ID: <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> Is None a builtin? In [1]: from keyword import kwlist In [3]: 'Ellipsis' in kwlist Out[3]: False In [4]: 'None' in kwlist Out[4]: True Maybe we should change This type has a single value. There is a single object with this value. This object is accessed through the built-in name None. It is used to signify the absence of a value in many situations, e.g., it is returned from functions that don?t explicitly return anything. Its truth value is false. to This type has a single value. There is a single object with this value. This object is accessed through the keyword None. It is used to signify the absence of a value in many situations, e.g., it is returned from functions that don?t explicitly return anything. Its truth value is false. Best, Neil On Monday, July 23, 2018 at 2:31:21 PM UTC-4, J?rn Heissler wrote: > > On Mon, Jul 23, 2018 at 10:03:10 +0100, Jonathan Fine wrote: > > I thought, a page on how None is special would be nice. > > I've not found such a page on the web. We do have > > === > > https://docs.python.org/3/library/constants.html > > Hi, > > there's also > > https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy > > None > > This type has a single value. There is a single object with this > value. This object is accessed through the built-in name None. It is > used to signify the absence of a value in many situations, e.g., it > is returned from functions that don?t explicitly return anything. > Its truth value is false. > > > Cheers > J?rn Heissler > _______________________________________________ > Python-ideas mailing list > Python... at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 16 09:04:03 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 14:04:03 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> Message-ID: Hi Neil Thank you for your post, regarding https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy. You've suggested changing "built-in name None" to "keyword None". I think that's a good change. And similar changes might be welcome elsewhere in the docs, perhaps also for True and False. And I think there's more. The page says > None > This type has a single value. There is a single object with this value. [...] I think it better to write > NoneType > This type has a single value, `None`. The keyword `None` always gives the value `None`. I think the best way forward here is to raise an issue on https://bugs.python.org/. Would you be willing to do this? If you need it, there's help available at https://devguide.python.org/triaging/. Once again, thank you for your close attention to detail. -- Jonathan From rhodri at kynesim.co.uk Thu Aug 16 09:14:38 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Thu, 16 Aug 2018 14:14:38 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> Message-ID: <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> On 16/08/18 14:04, Jonathan Fine wrote: > And I think there's more. The page says >> None >> This type has a single value. There is a single object with this value. [...] > I think it better to write >> NoneType >> This type has a single value, `None`. The keyword `None` always gives the value `None`. I disagree. That original text looks like it has been very carefully written to be (almost) true. What you are proposing to replace it with is less true and confusing to boot. -- Rhodri James *-* Kynesim Ltd From jfine2358 at gmail.com Thu Aug 16 09:41:05 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 14:41:05 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> Message-ID: Hi Rhodri Thank you for your message. You wrote: > I disagree. That original text looks like it has been very carefully > written to be (almost) true. What you are proposing to replace it with is > less true and confusing to boot. The decision is neither your's nor mine. It is for the Python docs maintainers. I will respect their decision, even if I don't agree with it. I intend, in my page (on why None is special) to continue to quote accurately, and without criticism, the current Python docs. One intention of my post is to move the particular docs discussion from python-ideas and to bugs.python.org. I think that is a better place for it. They're the people who can decide and do (or not do) something about it. -- with best regards Jonathan From p.f.moore at gmail.com Thu Aug 16 09:44:47 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 16 Aug 2018 14:44:47 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> Message-ID: On Thu, 16 Aug 2018 at 14:26, Rhodri James wrote: > > On 16/08/18 14:04, Jonathan Fine wrote: > > And I think there's more. The page says > >> None > >> This type has a single value. There is a single object with this value. [...] > > I think it better to write > >> NoneType > >> This type has a single value, `None`. The keyword `None` always gives the value `None`. > > I disagree. That original text looks like it has been very carefully > written to be (almost) true. What you are proposing to replace it with > is less true and confusing to boot. I agree that the original is better. I think the important thing (which doesn't come across when quoting text in email) is the typography. ``` None This type has a single value. There is a single object with this value. This object is accessed through the built-in name None. [...] ``` The initial "None" is on a line by itself, and is in "normal text" font, outdented from the following text. As it's in a section called "The standard type hierarchy", this reads to me as referring to a type, informally named as "None". It's not referring to the Python keyword None, which is formatted differently (monospace with a grey background). Conversely, the "None" in the phrase "the built-in name None" *is* formatted to indicate that it's the Python keyword. The typography makes it quite clear (to me) that there are two different *concepts* being discussed here, and furthermore, the wording clearly implies that neither of these concepts is precisely equivalent to the "single value" of the None type. It's easy when discussion wording in a plain-text medium like email to ignore the impact of formatting on how the meaning of a piece of text is conveyed. In this case, I think that the details are subtle enough that the typography is critical to getting the message across. One thing that *isn't* conveyed by the description here is the distinction between `None` and `Ellipsis`. The two relevant sections say This object is accessed through the built-in name None This object is accessed through the literal ... or the built-in name Ellipsis But you can't assign to (the name) None, and yet you can to (the name) Ellipsis. It might be better to say "the keyword None" in the section on None, to make that distinction. But that's the only change I'd make. Paul PS I should say that I would not expect any of the fine distinctions I've drawn in the above to be obvious to non-native speakers of English. That's a very different problem to handle, and one that is orders of magnitude harder than the comparatively simple task of trying to distinguish between None the type, the keyword and the value :-) From jfine2358 at gmail.com Thu Aug 16 10:28:28 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 15:28:28 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> Message-ID: Hi Paul Thank you for your comments. I think different people experience things in different ways, based on who they are. What their background, training, experience are. One person's precision is another's pedantry. An aside. Babbage and Tennyson: https://www.uh.edu/engines/epi879.htm You wrote > in a section called "The standard type hierarchy", > this reads to me as referring to a type, informally > named as "None". When I read the same text, I don't see an informal name. I see a false statement. By the way, here's why I see a false statement: >>> type(int), type(dict), type(str) (, , ) >>> type(None), type(type(None)) (, ) My (pure mathematics research) background leads me to dislike precise statements that are not true. That's the way I am. Rhodri James doesn't like sentences that begin with 'But'. An aside. Reading further in https://docs.python.org/3/reference/datamodel.html, I see three times "This type has a single value." The informal names are None, NotImplemented and Ellipsis. And there are only two Booleans. I'd like to take this to bugs.python.org, if only to provide another route to discovering this (very useful) conversation. Perhaps one day, we'll have here harmony between informality and precision. Perhaps every popular computer language has this as a goal. -- with best regards Jonathan From rhodri at kynesim.co.uk Thu Aug 16 10:57:32 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Thu, 16 Aug 2018 15:57:32 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> Message-ID: <675ab6a6-cd85-d8ca-7233-74078b80a7fd@kynesim.co.uk> On 16/08/18 14:41, Jonathan Fine wrote: > Hi Rhodri > > Thank you for your message. You wrote: > >> I disagree. That original text looks like it has been very carefully >> written to be (almost) true. What you are proposing to replace it with is >> less true and confusing to boot. > The decision is neither your's nor mine. It is for the Python docs > maintainers. I will respect their decision, even if I don't agree with > it. By that logic, no discussion on this list is worth having. -- Rhodri James *-* Kynesim Ltd From p.f.moore at gmail.com Thu Aug 16 11:09:56 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 16 Aug 2018 16:09:56 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> Message-ID: On Thu, 16 Aug 2018 at 15:28, Jonathan Fine wrote: > I'd like to take this to bugs.python.org, if only to provide another > route to discovering this (very useful) conversation. That's perfectly OK, and entirely your choice. However, if you do so, I'd hope that you present the dissenting views from this list when you raise the question on b.p.o. Otherwise, you're in effect expecting all the participants here to repeat their comments on bpo, if they want their opinions to be heard, which makes this discussion somewhat irrelevant. My understanding was that a discussion here is intended to attempt to reach a broad consensus, which could *then* be presented to bpo as a proposal. But that's just my view, and if you prefer not to take that approach then that's fine. Either way, I'll probably say no more on this topic, as it appears that people have their opinions and there's not much movement towards a shared agreement. I don't have the time or inclination to participate on bpo as well, so if you do move the conversation to that forum, I'll not get involved. Regards, Paul From jfine2358 at gmail.com Thu Aug 16 11:18:59 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 16:18:59 +0100 Subject: [Python-ideas] Python docs page: In what ways is None special In-Reply-To: References: <20180723183006.GA25280@carrot.tutnicht.de> <6b44df2a-a4e3-4f8f-9ed6-e755d2c14aab@googlegroups.com> <640164f5-3ef4-d71e-82a1-098454cca897@kynesim.co.uk> Message-ID: Hi Paul We wrote >> I'd like to take this to bugs.python.org, if only to provide another >> route to discovering this (very useful) conversation. > > That's perfectly OK, and entirely your choice. However, if you do so, > I'd hope that you present the dissenting views from this list when you > raise the question on b.p.o. This reinforces my intention to present matters fairly, referencing this thread. I'll post once more to this thread, after I've created the bug. That might not be for a few days. And thank you for the courteous and respectful disagreement. -- Jonathan From chris.barker at noaa.gov Thu Aug 16 12:34:57 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Thu, 16 Aug 2018 09:34:57 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180816082843.GX22431@ando.pearwood.info> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: On Thu, Aug 16, 2018 at 1:28 AM, Steven D'Aprano wrote: > there > are times where I have really wanted to access the caller's environment, > not the environment where my function was defined. > what am I missing? can't you get that by passing locals() in to a function? A bit clunky, sure, but everyone seems to agree that this a fairly rarely used approach. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 16 13:33:05 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 18:33:05 +0100 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: Hi Chris Steve and you wrote: >> there >> are times where I have really wanted to access the caller's environment, >> not the environment where my function was defined. > what am I missing? can't you get that by passing locals() in to a function? I think this will fail when values are changed. According to https://docs.python.org/3/library/functions.html#locals > The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. I suspect that Jacob, the original poster, wants to change state, and also to read changed state. Jacob, could you confirm or correct, that you want the called function to be able to change state in caller (or perhaps even further up the stack). To finish, here's an interactive example of changing the value of locals(). >>> def f(a=1): loc = locals(); yield loc; yield a >>> it = f() >>> ctx = next(it) >>> ctx {'a': 1} ## This surprised me. >>> >>> >>> def f(a=1): loc = locals(); yield locals(); yield a >>> it = f() >>> ctx = next(it) >>> ctx {'a': 1, 'loc': {...}} >>> ctx['a'] = 3 >>> ctx['loc']['a'] = 5 >>> next(it) ## Is it 1 or 3 or 5? 1 ## The value of 'a' hasn't changed. -- Jonathan From jacobsolinsky at gmail.com Thu Aug 16 13:47:57 2018 From: jacobsolinsky at gmail.com (Jacob Solinsky) Date: Thu, 16 Aug 2018 12:47:57 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: On Thu, 16 Aug 2018, 12:44 Jacob Solinsky, wrote: > I wanted the called, jumped to function to change state in the caller. > From what I tried to do, passing locals() cannot accomplish this. I have > made it happen in other languages though. > In the R language, one can do this > > foo = function(){ > localenv = environment() > eval(bar, environment = localenv) > > The above code captures the environment of the calling function and > executes the called function as if the calling function's local environment > was the global environment. bar doesn't have to be a function, it can be > any valid R expression captured with the expr() function, and everything in > R is an expression thus allowing for the full usage code blocks. Outside of > lisp-like languages this feat seems to usually be impossible though. > > > On Thu, 16 Aug 2018, 12:34 Jonathan Fine, wrote: > >> Hi Chris >> >> Steve and you wrote: >> >> >> there >> >> are times where I have really wanted to access the caller's >> environment, >> >> not the environment where my function was defined. >> >> > what am I missing? can't you get that by passing locals() in to a >> function? >> >> I think this will fail when values are changed. According to >> https://docs.python.org/3/library/functions.html#locals >> > The contents of this dictionary should not be modified; changes may not >> affect the values of local and free variables used by the interpreter. >> >> I suspect that Jacob, the original poster, wants to change state, and >> also to read changed state. Jacob, could you confirm or correct, that >> you want the called function to be able to change state in caller (or >> perhaps even further up the stack). >> >> To finish, here's an interactive example of changing the value of >> locals(). >> >> >>> def f(a=1): loc = locals(); yield loc; yield a >> >>> it = f() >> >>> ctx = next(it) >> >>> ctx >> {'a': 1} ## This surprised me. >> >>> >> >>> >> >>> def f(a=1): loc = locals(); yield locals(); yield a >> >>> it = f() >> >>> ctx = next(it) >> >>> ctx >> {'a': 1, 'loc': {...}} >> >>> ctx['a'] = 3 >> >>> ctx['loc']['a'] = 5 >> >>> next(it) ## Is it 1 or 3 or 5? >> 1 ## The value of 'a' hasn't changed. >> >> -- >> Jonathan >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Thu Aug 16 13:49:22 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Thu, 16 Aug 2018 19:49:22 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: Hi Jonathan and Paul, Thank you very much for your suggestions! I will try to contact the author of the PEP. Let me clarify a bit a potential misunderstanding. Please mind that contracts are not tied to individual variables, but to expressions. Think of it as defining a lambda which takes as input all the arguments of the function (and a result variable in case of post-conditions) which always needs to evaluate to True. Cheers, Marko Le jeu. 16 ao?t 2018 ? 12:24, Paul Moore a ?crit : > On Thu, 16 Aug 2018 at 10:41, Jonathan Fine wrote: > > > > Hi Marko > > > > Thank you for introducing yourself, and clearly stating your question. > > That helps us all. You asked: > > > > > Could somebody update me on the state of the discussion on this matter? > > > > I think bring the existing PEP up to date would be a good starting > > point. Its content hasn't been changed since 2003 (except for PEP-wide > > admin changes. (Recall that Python 3.0 was released in 2008.) > > > > https://www.python.org/dev/peps/pep-0316/ > > https://github.com/python/peps/commits/master/pep-0316.txt > > > > In fact, revising the PEP might be enough to answer your question. > > What do you think, Marko? > > > > Experts: is there a process for revising old PEPs, such as this one? > > Or at least a precedent we could follow (or adapt)? > > I'm not aware of a formal process, but I'd have thought the following > steps would be a reasonable approach: > > 1. Review the PEP, and research the discussions that happened at the > time, particularly of interest is why the PEP was deferred. > 2. Consider what (if anything) has changed since the original deferral > (which could simply be "time has moved on, people's views may have > changed" but ideally would include a bit more in the way of concrete > motivation). > 3. Contact the original PEP author and ask if he is interested in > reopening the discussion, collaborating on a revision, or handing the > PEP over. > 4. Start up a discussion here, pointing out the original PEP and > summarising the previous debate and why you want to restart the > discussion. If you're hoping to change the details of the original > PEP, summarise your changes and why you feel they are an improvement > over the original. > > To answer the OP's question more directly: > > > Could somebody update me on the state of the discussion on this matter? > > As far as I am aware, there has been no discussion on this subject > since the PEP 316 discussions which ended up in its deferral. Elazar > mentioned PEP 563, and there *may* have been mention of design by > contract uses in the discussions on that PEP, but you'd have to search > the mailing list archives to confirm that one way or another. > > Hence the suggestions that if you want to restart discussion, reviving > PEP 316 is likely the best approach. > > Paul > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 16 14:00:13 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 16 Aug 2018 19:00:13 +0100 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: Hi Jacob I really like your previous post. I find it really helps me understand what you want. You wrote > I wanted the called, jumped to function to change state in the caller. > From what I tried to do, passing locals() cannot accomplish this. I have > made it happen in other languages though. > In the R language, one can do this > foo = function(){ > localenv = environment() > eval(bar, environment = localenv) > The above code captures the environment of the calling function and > executes the called function as if the calling function's local environment > was the global environment. So in a nutshell, you'd like to be able to write code like this, but in Python? > bar doesn't have to be a function, it can be any > valid R expression captured with the expr() function, and everything in R is > an expression thus allowing for the full usage code blocks. This Python can already do. Any Python expression can be turned into a function, simply by prefixing it with 'lambda:'. > Outside of > lisp-like languages this feat seems to usually be impossible though. I'm an Emacs user, so I know Lisp. But R is new to me. But this URL tells me that R is based on Lisp. https://www.i-programmer.info/programming/other-languages/1706-a-programmers-guide-to-r.html And, in my view, this makes your problem immediately much more important for the Python community. Because both Python and R are major languages in the area of Data Science. Thank you so much for your previous post, and to all the others whose posts have contributed to this clarification. -- best regards Jonathan From turnbull.stephen.fw at u.tsukuba.ac.jp Thu Aug 16 14:00:21 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Fri, 17 Aug 2018 03:00:21 +0900 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180816012017.GV22431@ando.pearwood.info> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816012017.GV22431@ando.pearwood.info> Message-ID: <23413.48053.728301.379925@turnbull.sk.tsukuba.ac.jp> tl;dr A pedantic note on dynamic binding. Steven D'Aprano writes: > The most common language today that uses dynamic scoping is probably > Emacs Lisp. AFAIK all Common-Lisp-ish languages implement dynamic scoping: anything defvar'd is dynamically-scoped. > Although dynamic scoping is very powerful, it is also harder > to implement correctly (so I believe) In fact, lexical scoping is harder to do correctly because you need to know what you're doing (determine whether a name is in the lexical scope). (Old) Emacs Lisp-style dynamic scoping (everything is dynamically scoped) is (conceptually) easy to implement correctly (but inefficiently!) simply by using a stack of bindings and doing all accesses by searching that stack top to bottom for a relevant binding. It's a pain in the butt to use *correctly* because every such binding can affect anything else in your program and any libraries you import. That's why Common Lisp and modern Emacs Lisp are lexically-scoped.[1] It's not that much harder to implement the dynamic scoping of defvars; you just have to add a check for the symbol being a defvar at binding time, and if not put it in the local namespace. It's true (as you write later in the thread) that Richard Stallman is still enamoured of dynamic scoping. The nicest thing I can say about Richard is that he has enormous capacity to hold huge complex structures in his head. The next nicest thing I can say about Richard is that he's an anomoly. If his enthusiasm for dynamic scoping is correct, it's a "stopped clock right twice a day" phenomenon. What's good for Richard may be *convenient* for the rest of us when hacking up one-offs, but I firmly believe that if *we* want to write reliable, nearly correct software for complex systems, dynamic scoping should be used sparingly at most. After 2 decades of maintaining Emacsen, I'd go so far as to say that Python's "global" and "nonlocal" declarations are distinctly preferable to Lisp's "defvar" and "special" declarations where Python's much more restricted constructs can do the job. > It is generally considered that dynamic scoping is equivalent to > the exclusive use of global variables That depends on your definition of "equivalent" and "global". At least psychologically, they can be very different regardless of the definition of "variable". In (old) Emacs Lisp, defun, lambda, and let all appear to define local variables, but they don't. They define local bindings of global variables, which affect any function called recursively from the function that does the binding that uses those variables as globals. And in any Lisp, it is in principle[2] impossible to write a correct program using dynamic scope if you import another module, because even if you've checked that module and there are no free occurrances of a given name at write-time, the module could be updated to use a free variable by that name before you run it and you will shadow its expected binding at run-time. To be safe, you need to implement lexical scope! In languages where "global" names are bound to memory locations at compile time, like C, or in Python where "global" means module scope, you don't have this problem. Sure, in C you can declare a variable "extern" or in Python you can import a name from another module, but that solves the problem: without an *explicit* declaration of that kind you know you can't affect another module. The point, of course, is not so much the "in principle" hazard, but rather the need to determine what the scope of a given binding *could* be and to check large extents of source code for bugs due to unexpected shadow bindings of free variables in order to be sure your program is correct, and that there is no restriction in principle on how large that extent might be. Steve Footnotes: [1] Technically, I think Emacs still defaults to dynamic scope and you have to turn lexical scope on with a pragma. [2] Again, technically, you can use dynamic scope safely in Common Lisp by interning your dynamic variables in a package, and so restricting their scope to your module plus any other modules that deliberate import those names. From turnbull.stephen.fw at u.tsukuba.ac.jp Thu Aug 16 14:01:40 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Fri, 17 Aug 2018 03:01:40 +0900 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> Message-ID: <23413.48132.585356.992144@turnbull.sk.tsukuba.ac.jp> Jacob Solinsky writes: > What I had hoped to do was use a preamble code block to collect all of the > most common queries called by the mutate function in the local namespace, > for example > > C = 'bpgkdtszSZjCmnywh' > M = 'mn' > > > class Morpheme: > #stuff > > def preamble(self): > > ps = self.precedingmorpheme.form > ss = self.succeedingmorpheme.form > ssc = re.match(f'^[{C}]', self.succedingmorpheme.form) #Whether or not > the following morpheme is consonant initial > ssm = re.match(f'[{M}]$', self.precedingmorpheme.form) #Whether or not > the preceding morpheme is nasal final > > these local variables are used quite often in the mutate methods, of which > there are several dozen, so storing them by default saves a lot of > typing. What you're asking for is basically a "Ruby block", AFAICS. This has been requested many times, but most of the senior Pythonistas consider that it leads to a very high risk of unreadable and/or buggy code at no gain in power (there are several ways to efficiently accomplish what you want to do, you just don't like them[1]), and few cases where it's more readable/less buggy. I think if you search "ruby block site:mail.python.org" you'll probably bring up the threads. You won't find a lot of encouraging discussion, I'm afraid. What I would do in your case is class Morpheme: class Preamble: def __init__(self, m): # "m" for "morpheme" self.ps = m.precedingmorpheme.form self.ss = m.succeedingmorpheme.form self.ssc = re.match(f'^[{C}]', m.succedingmorpheme.form) self.ssm = re.match(f'[{M}]$', m.precedingmorpheme.form) def mutate(): p = self.Preamble(self) # use p.ps, p.ss, etc It's a little less efficient, of course, because of overhead managing the Preamble objects. Another possibility would be to use properties, so that instead of *storing* these temporary variables on the Morpheme, they would be computed on the fly: class Morpheme: @property def ps(self): return self.precedingmorpheme.form @property def ss(self): return self.succeedingmorpheme.form @property def ssc(self): return re.match(f'^[{C}]', self.succeedingmorpheme.form) @property def ssm(self): return re.match(f'[{M}]$', self.precedingmorpheme.form) and so on. Then you can access them with "self.ps" etc in the mutate method. This might be considered elegant (although verbose in the Morpheme definition) if these properties are usually used only once per mutate call, and "expensive" properties like ssc and ssm are never called more than once. (If they are called multiple times, it's easy to create a cache.) Of course property accesses do add method call overhead, but they look nicer than method call syntax. On the other hand, if "many" properties are expensive, and "most" mutate methods use only a few of these, you could save runtime this way, since the expensive methods are called only as-needed. I don't understand the "need default value in __init__" issue, since "inject" implied to me that you initialize before use. But if that's a problem for ordinary attributes, I presume it'll be more annoying with properties because you have to write a method for it. So I don't know if this is helpful at all. Footnotes: [1] "I don't like it" is a sufficient reason to propose a change. I'm simply saying you have the *power* to do what you want. From steve at pearwood.info Thu Aug 16 14:34:22 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 17 Aug 2018 04:34:22 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <4b3ad41b-fbff-d53b-94c9-ef8f12dfa888@brice.xyz> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <4b3ad41b-fbff-d53b-94c9-ef8f12dfa888@brice.xyz> Message-ID: <20180816183422.GY22431@ando.pearwood.info> On Thu, Aug 16, 2018 at 10:31:28AM +0200, Brice Parent wrote: > If I understand well the need (I'm unsure I've had it myself), it would > be easier to be able to import the function in the active context, like > this: > > def foo(a): > ??? return a + c > > def bar(a, c): > ??? return foo(a) > > def bazz(a, c): > ??? import __file__.foo > ??? return foo(a) [...] > I'm not saying the syntax is the one that should be used (__file__ > possibly not existing may be a problem), not even saying that we should > have this. I'm just showing a way to do the same thing with an easier > (to me) syntax. The problem isn't that __file__ doesn't exist, it is that import DOES exist and does something completely unsuitable: def bazz(a, c): # Make the *name* foo a local foo = globals()['__file__'].foo # (roughly) return foo(a) But this doesn't change the scoping rules used when calling foo. It still runs using lexical scope, which means the a+c line in foo() still refers to the global variable c. What we would need is a completely different command, not "import", perhaps "load": def bazz(a, c): foo = load('foo') return foo(a) which would be equivalent to this pseudocode: def bazz(a, c): get the source code of foo (hopefully still available!) foo = compile(source code as inner function) call foo or possibly: def bazz(a, c): make a copy of foo and its bytecode change all(?) the LOAD_GLOBAL bytecode to LOAD_DEREF call the modified copy of foo Both implementations seem clunky, fragile and likely to be slow to me. -- Steve From steve at pearwood.info Thu Aug 16 14:51:19 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 17 Aug 2018 04:51:19 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: <20180816185119.GZ22431@ando.pearwood.info> On Thu, Aug 16, 2018 at 09:34:57AM -0700, Chris Barker wrote: > On Thu, Aug 16, 2018 at 1:28 AM, Steven D'Aprano > wrote: > > > there > > are times where I have really wanted to access the caller's environment, > > not the environment where my function was defined. > > > > what am I missing? can't you get that by passing locals() in to a function? I want to pull in the caller's environment, not require the caller to push their environment in to me. Most of the time I just want read-access to the environment, but if I need to modify it, and the OP needs to do that, modifying locals() is unreliable. In general, it just silently fails, because locals() returns a copy of the local namespace. def spam(d): d['a'] = 'spam' def eggs(): a = 'ham' spam(locals()) print(a) Running that under CPython prints "ham", not "spam". (To be precise, writing to locals() works when you are in the module scope, or a class body, but not a function body. That's a CPython implementation detail; IronPython and Jython may behave differently.) -- Steve From chris.barker at noaa.gov Thu Aug 16 15:32:54 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Thu, 16 Aug 2018 12:32:54 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: On Thu, Aug 16, 2018 at 10:33 AM, Jonathan Fine wrote: > >> there > >> are times where I have really wanted to access the caller's environment, > >> not the environment where my function was defined. > > > what am I missing? can't you get that by passing locals() in to a > function? > > I think this will fail when values are changed. According to > https://docs.python.org/3/library/functions.html#locals > > The contents of this dictionary should not be modified; changes may not > affect the values of local and free variables used by the interpreter. > and: """ locals() Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks. """ it a dictionary *representing* the current local symbol table, so not the actual symbol table -- which surprised me, I thought that is was -- and sometimes it appears to be -- see later example: > To finish, here's an interactive example of changing the value of locals(). > > >>> def f(a=1): loc = locals(); yield loc; yield a > >>> it = f() > >>> ctx = next(it) > >>> ctx > {'a': 1} ## This surprised me. > me too I would have thought "loc" would be in there. > >>> def f(a=1): loc = locals(); yield locals(); yield a > >>> it = f() > >>> ctx = next(it) > >>> ctx > {'a': 1, 'loc': {...}} > now "loc is there" > >>> ctx['a'] = 3 > >>> ctx['loc']['a'] = 5 > >>> next(it) ## Is it 1 or 3 or 5? > 1 ## The value of 'a' hasn't changed. hmm -- made me think that generators are doing something different here -- and indeed they are. If you use regular functions: In [30]: def local_modifying(loc): ...: """ ...: adds a "fred" key to the dict passed in ...: """ ...: print("locals passed in:", loc) ...: loc['fred'] = 5 ...: print("locals after adding", loc) ...: In [31]: def test_locals(): ...: """ ...: a simple local namespace to use ...: """ ...: a = 1 ...: b = 2 ...: local_modifying(locals()) ...: # does "fred" exist? ...: print(locals()) ...: # and we can access it the usual way ...: print("fred:", fred) ...: In [32]: test_locals() locals passed in: {'b': 2, 'a': 1} locals after adding {'b': 2, 'a': 1, 'fred': 5} {'b': 2, 'a': 1, 'fred': 5} fred: 5 It seems you CAN modify the locals dict passed in, and the change will show up in the enclosing scope. But it sounds like that is not guaranteed by the language. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Thu Aug 16 15:35:55 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Thu, 16 Aug 2018 12:35:55 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: one more thought: given that: > > The contents of this dictionary should not be modified; changes may not >> affect the values of local and free variables used by the interpreter. >> > > and: > """ > locals() > > Update and return a dictionary representing the current local symbol table. > I wonder why locals doesn't return a Mapping Proxy, or other read-only mapping object? If it's not guaranteed to be THE locals dict, and changes *may* not affect the real one (but may), a read-only object seems like much safer idea. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Thu Aug 16 15:37:32 2018 From: rosuav at gmail.com (Chris Angelico) Date: Fri, 17 Aug 2018 05:37:32 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: On Fri, Aug 17, 2018 at 5:32 AM, Chris Barker via Python-ideas wrote: > hmm -- made me think that generators are doing something different here -- > and indeed they are. If you use regular functions: > > In [30]: def local_modifying(loc): > ...: """ > ...: adds a "fred" key to the dict passed in > ...: """ > ...: print("locals passed in:", loc) > ...: loc['fred'] = 5 > ...: print("locals after adding", loc) > ...: > > In [31]: def test_locals(): > ...: """ > ...: a simple local namespace to use > ...: """ > ...: a = 1 > ...: b = 2 > ...: local_modifying(locals()) > ...: # does "fred" exist? > ...: print(locals()) > ...: # and we can access it the usual way > ...: print("fred:", fred) > ...: > In [32]: test_locals() > locals passed in: {'b': 2, 'a': 1} > locals after adding {'b': 2, 'a': 1, 'fred': 5} > {'b': 2, 'a': 1, 'fred': 5} > fred: 5 > > It seems you CAN modify the locals dict passed in, and the change will show > up in the enclosing scope. > > But it sounds like that is not guaranteed by the language. I've no idea what interpreter you're using, but it doesn't work for me. >>> test_locals() locals passed in: {'a': 1, 'b': 2} locals after adding {'a': 1, 'b': 2, 'fred': 5} {'a': 1, 'b': 2, 'fred': 5} Traceback (most recent call last): File "", line 1, in File "", line 11, in test_locals NameError: name 'fred' is not defined You've changed a cached dictionary but haven't actually created a local. ChrisA From jacobsolinsky at gmail.com Thu Aug 16 17:37:19 2018 From: jacobsolinsky at gmail.com (Jacob Solinsky) Date: Thu, 16 Aug 2018 16:37:19 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: So when getx is executed inside a let form, if it tries to read/write the value of X it interacts with the X entry in the let form's symbol table before moving to find X in the global environment, right? That is similar to what I was trying to accomplish in python, but with the local symbol table of the calling function rather than a let form. I think the way a "jump to" function rather than a "call function" would be implemented would be by removing the prologue and epilogue of the function's compiled code. Something vaguely like this: def foo(a,b): c = bar(d =3)% return c+2 def bar(d) a += 2 e = 4 return a + b + d +e foo(7, 2) Here would be the symbol table Scope Foo __________ a: fp - 1 b: fp - 2 d: fp - 3 e: fp - 5 c: fp - 4 The interpreter would have to recognize that bar was being jumped to rather than called and thus inject bar's arguments and variable declarations and return value (if assigned to) into foo's stack frame. The translation of the above code would be this (I apologize for the strange pseudoassembly, I don't know any of those languages on a more than cursory level. The below code is obviously very slow, each variable read from the memory and written to memory at every step, with no storage of local variables in registers.) The "return c+2" statement is changed from a return into a c += 2 assignment in the calling function. PUSH fp, returnregister # preserve old value in return register PUSH -1(fp), 7 # load a PUSH -2(fp), 2 # load b PUSH -3(fp), 3 # load d PUSH -4(fp), 0 # initialize c ADDI -1(fp), -1(fp), 2 # a += 2 PUSH -5(fp), 4 # load e ADD -4(fp), -1(fp), -2(fp) # c = a + b + d + e ADD -4(fp), -4(fp), -5(fp) # c = a + d + d + e continued ADDI returnregister, -4(fp), 2 # return c + 2 On Thu, 16 Aug 2018, 14:44 Jonathan Fine, wrote: > Hi Jacob > > I'm finding the python-ideas list a bit noisy, so I'm sending this > off-list. > > I've found > > > https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html > > https://www.gnu.org/software/emacs/manual/html_node/elisp/Variable-Scoping.html > > Please confirm that this is at least close to what you want, to be > able to program your problem efficiently. > > Meanwhile, I'm thinking about how your algorithm might be expressed in > Python. > > -- > Jonathan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Fri Aug 17 02:47:11 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Fri, 17 Aug 2018 15:47:11 +0900 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: <23414.28527.570531.784525@turnbull.sk.tsukuba.ac.jp> Jacob Solinsky writes: > I think the way a "jump to" function rather than a "call function" would be > implemented would be by removing the prologue and epilogue of the > function's compiled code. Something vaguely like this: First, let me apologize for pointing you at Ruby blocks. They don't quite do what I thought they did; they're more like Python's "nonlocal" than Lisp's "dynamic scope". I'm pretty sure you would need something else added to Python. (But see below.) If you're not a Ruby programmer and don't necessarily want to be one, I'd say wait for someone who is to say I'm wrong before pushing them. Second, it seems to me that the kind of "DRY" you're looking for is just as well implemented by a macro facility. You might want to look at MacroPy. tl;dr here I'm not very experienced with Ruby, so I'll post the snippets that convinced me that Ruby's blocks don't DTRT. Maybe somebody else can correct my code to get the job done, in which case you might have a reason to advocate blocks for Python. Steve Code: The problem is that blocks have nonlocal access (as defined in Python 3) to the scope in which they are defined, not somehow imposing dynamic access on that scope. def preamble # assign local variables end def mutate preamble do # do stuff with preamble's locals end end doesn't work because the block can see mutate's locals but not preamble's. So I think def mutate def worker yield # do stuff with mutate's locals end worker do # assign local variables end end works (untested), but it's just a complicated way to write def mutate # assign local variables # do stuff with mutate's locals end while def worker yield # do stuff with mutate's locals end def mutate worker do # assign local variables end end does not work: worker can't access the local variables of mutate because they're a scope it can't see. -- Associate Professor Division of Policy and Planning Science http://turnbull.sk.tsukuba.ac.jp/ Faculty of Systems and Information Email: turnbull at sk.tsukuba.ac.jp University of Tsukuba Tel: 029-853-5175 Tennodai 1-1-1, Tsukuba 305-8573 JAPAN From contact at brice.xyz Fri Aug 17 04:41:04 2018 From: contact at brice.xyz (Brice Parent) Date: Fri, 17 Aug 2018 10:41:04 +0200 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180816183422.GY22431@ando.pearwood.info> References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <4b3ad41b-fbff-d53b-94c9-ef8f12dfa888@brice.xyz> <20180816183422.GY22431@ando.pearwood.info> Message-ID: <317ae6d6-c4a1-51f1-3593-d2499e91d552@brice.xyz> Le 16/08/2018 ? 20:34, Steven D'Aprano a ?crit?: > On Thu, Aug 16, 2018 at 10:31:28AM +0200, Brice Parent wrote: > >> If I understand well the need (I'm unsure I've had it myself), it would >> be easier to be able to import the function in the active context, like >> this: >> >> def foo(a): >> ??? return a + c >> >> def bar(a, c): >> ??? return foo(a) >> >> def bazz(a, c): >> ??? import __file__.foo >> ??? return foo(a) > [...] >> I'm not saying the syntax is the one that should be used (__file__ >> possibly not existing may be a problem), not even saying that we should >> have this. I'm just showing a way to do the same thing with an easier >> (to me) syntax. > The problem isn't that __file__ doesn't exist, it is that import DOES > exist and does something completely unsuitable: > > [...] That's what I was trying to say: I'm not proposing a syntax or any specific solution. It was more about graphically explaining that I found more explicit (that word again...) to import (or copy, or insert) the target function inside the active scope than to have it done when you call the function itself. From jfine2358 at gmail.com Fri Aug 17 04:51:30 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Fri, 17 Aug 2018 09:51:30 +0100 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: Jacob Solinsky wrote: > So when getx is executed inside a let form, if it tries to read/write the > value of X it interacts with the X entry in the let form's symbol table > before moving to find X in the global environment, right? The context for this is two (very useful) URLs I sent him off list: https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html https://www.gnu.org/software/emacs/manual/html_node/elisp/Variable-Scoping.html -- Jonathan From chris.barker at noaa.gov Fri Aug 17 15:46:24 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Fri, 17 Aug 2018 12:46:24 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: On Thu, Aug 16, 2018 at 12:37 PM, Chris Angelico wrote: > > I've no idea what interpreter you're using, but it doesn't work for me. > That was in iPython, with python3.6.2 -- I wouldn't have expected it to be different in this case though -- really odd. OK -- tired again, and it indeed it failed -- so I'm really confused. You can see my console output -- it did indeed work at least once. > You've changed a cached dictionary but haven't actually created a local > which still makes me wonder WHY locals() returns a writable dict... -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 17 16:24:54 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 17 Aug 2018 15:24:54 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: Jacob, can you please describe in greater detail *what* you're trying to accomplish with your morpheme code? Not *how* you wish to accomplish it, but *what* the code is supposed to do? I've looked into other projects that try to model morphemes and similar language constructs to get a better idea of the problem space (NLTK , TextBlob , PyGlot , etc.) and it looks like machine learning is often employed for morpheme-related tasks. It may be that the rules for identifying and manipulating morphemes are inherently so complex that they don't lend themselves to elegant codification. That's usually the case for fields in which people turn to machine learning. It may also be a case where functional decomposition would help. The examples you've given aren't really sufficient to understand the problem. It could be a legitimate deficiency in Python's feature set, or it may be that Python already has features that could serve you better, or it may be that the problem is inherently difficult to codify in an elegant way. Without a concrete use-case, it's nearly impossible to justify adding a new feature to Python. This discussion is unlikely to lead to any meaningful action otherwise. On Thu, Aug 16, 2018 at 4:37 PM, Jacob Solinsky wrote: > So when getx is executed inside a let form, if it tries to read/write the > value of X it interacts with the X entry in the let form's symbol table > before moving to find X in the global environment, right? That is similar > to what I was trying to accomplish in python, but with the local symbol > table of the calling function rather than a let form. > > I think the way a "jump to" function rather than a "call function" would > be implemented would be by removing the prologue and epilogue of the > function's compiled code. Something vaguely like this: > > def foo(a,b): > c = bar(d =3)% > return c+2 > > def bar(d) > a += 2 > e = 4 > return a + b + d +e > > foo(7, 2) > > Here would be the symbol table > > Scope Foo > __________ > a: fp - 1 > b: fp - 2 > d: fp - 3 > e: fp - 5 > c: fp - 4 > > The interpreter would have to recognize that bar was being jumped to > rather than called and thus inject bar's arguments and variable > declarations and return value (if assigned to) into foo's stack frame. > > The translation of the above code would be this (I apologize for the > strange pseudoassembly, I don't know any of those languages on a more than > cursory level. The below code is obviously very slow, each variable read > from the memory and written to memory at every step, with no storage of > local variables in registers.) The "return c+2" statement is changed from a > return into a c += 2 assignment in the calling function. > > PUSH fp, returnregister # preserve old value in return register > PUSH -1(fp), 7 # load a > PUSH -2(fp), 2 # load b > PUSH -3(fp), 3 # load d > PUSH -4(fp), 0 # initialize c > ADDI -1(fp), -1(fp), 2 # a += 2 > PUSH -5(fp), 4 # load e > ADD -4(fp), -1(fp), -2(fp) # c = a + b + d + e > ADD -4(fp), -4(fp), -5(fp) # c = a + d + d + e continued > ADDI returnregister, -4(fp), 2 # return c + 2 > > > > > > > > > > > > On Thu, 16 Aug 2018, 14:44 Jonathan Fine, wrote: > >> Hi Jacob >> >> I'm finding the python-ideas list a bit noisy, so I'm sending this >> off-list. >> >> I've found >> >> https://www.gnu.org/software/emacs/manual/html_node/elisp/ >> Dynamic-Binding.html >> https://www.gnu.org/software/emacs/manual/html_node/elisp/ >> Variable-Scoping.html >> >> Please confirm that this is at least close to what you want, to be >> able to program your problem efficiently. >> >> Meanwhile, I'm thinking about how your algorithm might be expressed in >> Python. >> >> -- >> Jonathan >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jacobsolinsky at gmail.com Fri Aug 17 17:13:53 2018 From: jacobsolinsky at gmail.com (Jacob Solinsky) Date: Fri, 17 Aug 2018 16:13:53 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: The code does the following 2 things: A Verb class assembles the necessary morphemes in order in accordance with the verb's subject, object, mode, grmamatical order, tense and polarity. If all of the morphemes' default forms were mashed together at this point a valid Ojibwe verb form would not be produced The code in the mutate methods of each morphene transforms a sequence like gi-bizindaw-in-si-in-w-in-m-ban into gi-bizindoo--si-n-oo-n-inini-mwaa-ban gibizindoosinoonininimwaaban A third piece of code creates thousands of verb instances and populates a web form to show every conjugated form of a given verb, though that is not important here. The mutation of each morpheme is dependent on the type and form of the preceding and following morpheme, occasionally requiring even more information from the parent verb. As most morphemes' mutation method are unique, the subclasses of Morpheme for the most part override the Morphems superclass's mutate implementation. However, it would reduce my code's current redundancy if I could place something like a macro expansion at the beginning of each mutate method's internal code, as there is a piece of code used to set up each mutate method's local variable space that I copied and pasted many times. The code I wrote already functions fine, it is just that while I was writing I was thinking to myself how convenient it would be if I could "jump to" functions, and now I understand that the best way to do that would just be to macro expand an often repeated segment of code. On Fri, 17 Aug 2018, 15:24 Abe Dillon, wrote: > Jacob, can you please describe in greater detail *what* you're trying to > accomplish with your morpheme code? Not *how* you wish to accomplish it, > but *what* the code is supposed to do? > > I've looked into other projects that try to model morphemes and similar > language constructs to get a better idea of the problem space (NLTK > , TextBlob > , PyGlot > , > etc.) and it looks like machine learning is often employed for > morpheme-related tasks. It may be that the rules for identifying and > manipulating morphemes are inherently so complex that they don't lend > themselves to elegant codification. That's usually the case for fields in > which people turn to machine learning. > > It may also be a case where functional decomposition would help. The > examples you've given aren't really sufficient to understand the problem. > It could be a legitimate deficiency in Python's feature set, or it may be > that Python already has features that could serve you better, or it may be > that the problem is inherently difficult to codify in an elegant way. > > Without a concrete use-case, it's nearly impossible to justify adding a > new feature to Python. This discussion is unlikely to lead to any > meaningful action otherwise. > > On Thu, Aug 16, 2018 at 4:37 PM, Jacob Solinsky > wrote: > >> So when getx is executed inside a let form, if it tries to read/write the >> value of X it interacts with the X entry in the let form's symbol table >> before moving to find X in the global environment, right? That is similar >> to what I was trying to accomplish in python, but with the local symbol >> table of the calling function rather than a let form. >> >> I think the way a "jump to" function rather than a "call function" would >> be implemented would be by removing the prologue and epilogue of the >> function's compiled code. Something vaguely like this: >> >> def foo(a,b): >> c = bar(d =3)% >> return c+2 >> >> def bar(d) >> a += 2 >> e = 4 >> return a + b + d +e >> >> foo(7, 2) >> >> Here would be the symbol table >> >> Scope Foo >> __________ >> a: fp - 1 >> b: fp - 2 >> d: fp - 3 >> e: fp - 5 >> c: fp - 4 >> >> The interpreter would have to recognize that bar was being jumped to >> rather than called and thus inject bar's arguments and variable >> declarations and return value (if assigned to) into foo's stack frame. >> >> The translation of the above code would be this (I apologize for the >> strange pseudoassembly, I don't know any of those languages on a more than >> cursory level. The below code is obviously very slow, each variable read >> from the memory and written to memory at every step, with no storage of >> local variables in registers.) The "return c+2" statement is changed from a >> return into a c += 2 assignment in the calling function. >> >> PUSH fp, returnregister # preserve old value in return register >> PUSH -1(fp), 7 # load a >> PUSH -2(fp), 2 # load b >> PUSH -3(fp), 3 # load d >> PUSH -4(fp), 0 # initialize c >> ADDI -1(fp), -1(fp), 2 # a += 2 >> PUSH -5(fp), 4 # load e >> ADD -4(fp), -1(fp), -2(fp) # c = a + b + d + e >> ADD -4(fp), -4(fp), -5(fp) # c = a + d + d + e continued >> ADDI returnregister, -4(fp), 2 # return c + 2 >> >> >> >> >> >> >> >> >> >> >> >> On Thu, 16 Aug 2018, 14:44 Jonathan Fine, wrote: >> >>> Hi Jacob >>> >>> I'm finding the python-ideas list a bit noisy, so I'm sending this >>> off-list. >>> >>> I've found >>> >>> >>> https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html >>> >>> https://www.gnu.org/software/emacs/manual/html_node/elisp/Variable-Scoping.html >>> >>> Please confirm that this is at least close to what you want, to be >>> able to program your problem efficiently. >>> >>> Meanwhile, I'm thinking about how your algorithm might be expressed in >>> Python. >>> >>> -- >>> Jonathan >>> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 17 18:16:39 2018 From: chris.barker at noaa.gov (Chris Barker - NOAA Federal) Date: Fri, 17 Aug 2018 18:16:39 -0400 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: By the way? really kludgy, doesn?t exec() do what you want here: Note The default *locals* act as described for function locals() below: modifications to the default *locals* dictionary should not be attempted. Pass an explicit *locals*dictionary if you need to see effects of the code on *locals* after function exec() returns. Though great still may not effect the current local namespace. But I?d be really surprised if there were no way to modify the local namespace ? you can mess with pretty much anything else in Python. -CHB Sent from my iPhone On Aug 17, 2018, at 12:46 PM, Chris Barker wrote: On Thu, Aug 16, 2018 at 12:37 PM, Chris Angelico wrote: > > I've no idea what interpreter you're using, but it doesn't work for me. > That was in iPython, with python3.6.2 -- I wouldn't have expected it to be different in this case though -- really odd. OK -- tired again, and it indeed it failed -- so I'm really confused. You can see my console output -- it did indeed work at least once. > You've changed a cached dictionary but haven't actually created a local > which still makes me wonder WHY locals() returns a writable dict... -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 17 18:36:07 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 17 Aug 2018 17:36:07 -0500 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: Is "Ban" a class of morphemes or just a single morpheme? I would think subclasses of Morpheme would be "Bound" and "Unbound" then there might be subclasses of Bound and so on. [Jacob Solinsky] > now I understand that the best way to do that would just be to macro > expand an often repeated segment of code. This is also referred to as "functional decomposition" (if I understand you correctly). You can usually write a method as a sequence of steps you need to take, then implement those steps in re-usable helper functions with descriptive names. My guess is that you'd want the morpheme class to be fairly simple and leave a bunch of the joining logic to the Verb. I would make a morpheme object's "morph" method take in some context (perhaps previous and next morpheme and stress or something) and output a morphed version of the morpheme without changing any internal state. That way, the "ban" morpheme is always the "ban" morpheme no matter what. It might also be easier to use dictionaries to look up morphemes based on tense and other context. There are a lot of ways that data-structures and coding practices can clean up code. On Fri, Aug 17, 2018 at 4:13 PM, Jacob Solinsky wrote: > The code does the following 2 things: > A Verb class assembles the necessary morphemes in order in accordance with > the verb's subject, object, mode, grmamatical order, tense and polarity. > > If all of the morphemes' default forms were mashed together at this point > a valid Ojibwe verb form would not be produced > > The code in the mutate methods of each morphene transforms a sequence like > gi-bizindaw-in-si-in-w-in-m-ban > into > gi-bizindoo--si-n-oo-n-inini-mwaa-ban > gibizindoosinoonininimwaaban > > A third piece of code creates thousands of verb instances and populates a > web form to show every conjugated form of a given verb, though that is not > important here. > > The mutation of each morpheme is dependent on the type and form of the > preceding and following morpheme, occasionally requiring even more > information from the parent verb. > As most morphemes' mutation method are unique, the subclasses of Morpheme > for the most part override the Morphems superclass's mutate implementation. > However, it would reduce my code's current redundancy if I could place > something like a macro expansion at the beginning of each mutate method's > internal code, as there is a piece of code used to set up each mutate > method's local variable space that I copied and pasted many times. > > The code I wrote already functions fine, it is just that while I was > writing I was thinking to myself how convenient it would be if I could > "jump to" functions, and now I understand that the best way to do that > would just be to macro expand an often repeated segment of code. > > On Fri, 17 Aug 2018, 15:24 Abe Dillon, wrote: > >> Jacob, can you please describe in greater detail *what* you're trying to >> accomplish with your morpheme code? Not *how* you wish to accomplish it, >> but *what* the code is supposed to do? >> >> I've looked into other projects that try to model morphemes and similar >> language constructs to get a better idea of the problem space (NLTK >> , TextBlob >> , PyGlot >> , >> etc.) and it looks like machine learning is often employed for >> morpheme-related tasks. It may be that the rules for identifying and >> manipulating morphemes are inherently so complex that they don't lend >> themselves to elegant codification. That's usually the case for fields in >> which people turn to machine learning. >> >> It may also be a case where functional decomposition would help. The >> examples you've given aren't really sufficient to understand the problem. >> It could be a legitimate deficiency in Python's feature set, or it may be >> that Python already has features that could serve you better, or it may be >> that the problem is inherently difficult to codify in an elegant way. >> >> Without a concrete use-case, it's nearly impossible to justify adding a >> new feature to Python. This discussion is unlikely to lead to any >> meaningful action otherwise. >> >> On Thu, Aug 16, 2018 at 4:37 PM, Jacob Solinsky >> wrote: >> >>> So when getx is executed inside a let form, if it tries to read/write >>> the value of X it interacts with the X entry in the let form's symbol table >>> before moving to find X in the global environment, right? That is similar >>> to what I was trying to accomplish in python, but with the local symbol >>> table of the calling function rather than a let form. >>> >>> I think the way a "jump to" function rather than a "call function" would >>> be implemented would be by removing the prologue and epilogue of the >>> function's compiled code. Something vaguely like this: >>> >>> def foo(a,b): >>> c = bar(d =3)% >>> return c+2 >>> >>> def bar(d) >>> a += 2 >>> e = 4 >>> return a + b + d +e >>> >>> foo(7, 2) >>> >>> Here would be the symbol table >>> >>> Scope Foo >>> __________ >>> a: fp - 1 >>> b: fp - 2 >>> d: fp - 3 >>> e: fp - 5 >>> c: fp - 4 >>> >>> The interpreter would have to recognize that bar was being jumped to >>> rather than called and thus inject bar's arguments and variable >>> declarations and return value (if assigned to) into foo's stack frame. >>> >>> The translation of the above code would be this (I apologize for the >>> strange pseudoassembly, I don't know any of those languages on a more than >>> cursory level. The below code is obviously very slow, each variable read >>> from the memory and written to memory at every step, with no storage of >>> local variables in registers.) The "return c+2" statement is changed from a >>> return into a c += 2 assignment in the calling function. >>> >>> PUSH fp, returnregister # preserve old value in return register >>> PUSH -1(fp), 7 # load a >>> PUSH -2(fp), 2 # load b >>> PUSH -3(fp), 3 # load d >>> PUSH -4(fp), 0 # initialize c >>> ADDI -1(fp), -1(fp), 2 # a += 2 >>> PUSH -5(fp), 4 # load e >>> ADD -4(fp), -1(fp), -2(fp) # c = a + b + d + e >>> ADD -4(fp), -4(fp), -5(fp) # c = a + d + d + e continued >>> ADDI returnregister, -4(fp), 2 # return c + 2 >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> On Thu, 16 Aug 2018, 14:44 Jonathan Fine, wrote: >>> >>>> Hi Jacob >>>> >>>> I'm finding the python-ideas list a bit noisy, so I'm sending this >>>> off-list. >>>> >>>> I've found >>>> >>>> https://www.gnu.org/software/emacs/manual/html_node/elisp/ >>>> Dynamic-Binding.html >>>> https://www.gnu.org/software/emacs/manual/html_node/elisp/ >>>> Variable-Scoping.html >>>> >>>> Please confirm that this is at least close to what you want, to be >>>> able to program your problem efficiently. >>>> >>>> Meanwhile, I'm thinking about how your algorithm might be expressed in >>>> Python. >>>> >>>> -- >>>> Jonathan >>>> >>> >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Fri Aug 17 20:59:16 2018 From: abedillon at gmail.com (Abe Dillon) Date: Fri, 17 Aug 2018 19:59:16 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: [Michael Selik] > The conversation about syntactic sugar for ``functools.partial`` led to a > question about whether jargon like "lambda" makes the concept of an > anonymous function more difficult to learn. To clarify: The original statement by Steven D'Aprano, "although possibly a less jargon name would be nicer..." indicated to me that he thought there might be situations where less jargon terms are preferable to jargon terms. The argument I tried to make is, "yes I believe there are cases where a less jargon identifier is preferable and that I believe 'lambda' is an example of a missed opportunity to use a less jargon (maybe 'esoteric' is a better word here?), more descriptive name." Subjectively, I don't like lambda expressions. I find the word 'lambda' to be an eye-sore in an otherwise very elegant language. That being said: I believe subjective valuations are rarely devoid of subtle, underlying motivators that are at least grounded in logic if not objective. It's just hard to put your finger on it most of the time. I often try to root out those motivators for why I feel the way I do and articulate them as best I can. At the end of the day, though; I can't always provide a completely objective, logical proof for why I feel the way I do. For instance: when the iPhone was introduced, a lot of people praised it's subjectively "slick" user interface. I believe that perception of slickness is partly because the iPhone emulated physical interfaces very well so it leveraged people's intuition about the physical world. It was delightfully intuitive. I believe that part of my distaste for lambda is that it's an esoteric word that doesn't convey any meaning to someone who's never heard of a 'lambda expression' (which was the case for me when I first encountered it). Even after I had heard of a lambda expression, the fact that the word had little other connection to anything relevant in my brain meant that I had to mentally translate it every time I read for a couple of years. [Steven Barnes] > While NOT wanting to start another fight I feel that I must put my > pedant hat on & point out that the above highlights why domain specific > words are used and their specificity actually highlights important > concepts, i.e.: > * Brakes are used to apply breaking, (i.e. to slow the vehicle, > possibly to a stop), while stoppers STOP something. I don't think this is comparable to calling a car's brakes, "stoppers" for several reasons. 1) What we call something usually relates to how humans communicate to other humans about that thing, not how we actually use the tool. I'm not against the idea of jargon. It clearly serves a useful purpose for humans to communicate to other humans both concisely and with precision. When I tell someone at work that a service went down and they say, "I'll take a look at the logs", I know they're not talking about lengths of cut or fallen tree. I'm glad humans are so good at deducing context that we don't have to constantly disambiguate everything. I also understand that this practice of overloading words sometimes leads to strange results like "currying". Maybe calling it "signature reduction" would have been too unwieldy and/or caused confusion with the word "reduce" which is often used in the same context. None of that has to do with how I interact with a car. Few brake pedals say "brake" on them. I don't have to use the word "brake" to slow down my car. Few of the interfaces in my car even have words. There's no lever that says "high beams". There's no dashboard indicator that says "high beams". I don't have to use the phrase "high beams" to turn on my high beams. At the same time, I don't need to use or know the word "ternary" to read or write a ternary expression in Python. I don't think that was a mistake or a missed opportunity to force people to look up the word "ternary". Sometimes in highly specific contexts, we deal with nuanced concepts like the difference between a parameter and an argument. So we use jargon to distinguish between them. That's not as much of problem in a programming language. The constructs in Python have to have an exact meaning by default. Clearly defining and separating name-spaces is an inescapable fact of life in programming. There's no chance of Python accidentally misinterpreting which "log" you're talking about. There's no potential for a "who's on first" gag . 2) Cars tend to actually use pretty sensible naming schemes. A windshield shields you from the wind. A windshield wiper wipes the windshield. Windshield wiper fluid is fluid that helps the windshield wiper wipe the windshield, etc. If they called windshield wiper solution "epsilon", it wouldn't cause more crashes or anything, it would just be more confusing than it needs to be. 3) It's not like calling 'brakes' 'stoppers'. It's more like calling an expression that makes a function by some random greek letter. I don't see much need for a metaphor. [Steven Barnes] > * postprandial = after Lunch (not after eating any meal or after a snack). Not according to Google , Merriam-Webster , Oxford , or Wikipedia . [Steven Barnes] > In all of these cases there is a specificity to the word used that is > missing from the alternative offered that will, hopefully, be raised by > the use of that word. Unfortunately many people, when trying to explain > what the word means fail to highlight where it is different (the number > of times that I have heard people "explain" port and starboard as left > and right without mentioning the word bow or forward is countless). I understand the potential benefit of jargon as stated above, but even this isn't always true. Sometimes jargon is created that is counterintuitive and then it just sticks because changing it would be a huge hassle. In electrical engineering, current is supposed to be the "flow of positive charge", but charge conventions were established before we knew how atoms work and learned that positively charged particles don't often move in circuits. Dinosaurs are another good example. Sometimes jargon is a mistake. [Steven Barnes] > Using a slightly unfamiliar word can cause people to ask, or think > about, why this is different & what the difference is while also drawing > a parallel that can help the user/student to understand & remember the > concept. It depends on if it's easy to tie said word into a broader understanding. It's easy for me to remember that "agua" means "water" in Spanish because it's very similar to a words that relate to water in english like "aquifer". I have trouble remembering that "izquierda" means "left" because I don't know any word like it. I have to pause and think about it every time without fail! Similarly, I can guess that "anonymous function" means a function without a name, but it took me a while to get used to "lambda" because it was just dangling there with no other connection to its context. Even when I learned about lambda calculus it didn't help much because the "lambda" was an arbitrary choice. There wasn't any way for me to tie it into a richer context. [Steven Barnes] > Also, picking a label for something, and using it consistently, can > vastly simplify things like manual searches (or on-line searches). Yes, Steven D'Aprano mentioned this and it's a fair point. I think it'd have to be pretty horrendous jargon to justify "create [an] association from scratch" as Steven put it. I've since gone back on my original push for "partial" over "given" because I don't think it meets that criteria. I think that "lambda" is a different case because there already existed several better alternatives in other languages and, in the case of "def", in Python itself. [Chris Angelico] > Whether you spell it "function(arg) {...}" or "lambda arg: ...", it's > the semantics that are hardest to learn. Naming and semantics are essentially orthogonal. Sure callbacks and the like can require some painful mental gymnastics, but that's independent of choosing "function" or "lambda". When I talk about students having more trouble learning lambdas than I expect, I'm specifically talking about lambdas, as in: >>> func = lambda x: x*x Even students that seemed to quickly grasp functions as first-class objects would stumble on basic lambda expressions. Not as much trouble as callbacks and other, more complex concepts, but more trouble than regular function definition. Anyway, the question should be "Is it always best to use jargon in the implementation of Python features? If so, how do you figure? If not, when and why should it be avoided?" On Wed, Aug 15, 2018 at 12:21 AM, Steve Barnes wrote: > > > On 14/08/2018 20:42, Michael Selik wrote: > > > > Good comparisons can be found in other fields: > > * Driving -- brakes vs stoppers > > * Sailing -- starboard vs right-side > > * Medicine -- postprandial vs after-meal > > * Biology -- dinosaur vs direlizard > > > While NOT wanting to start another fight I feel that I must put my > pedant hat on & point out that the above highlights why domain specific > words are used and their specificity actually highlights important > concepts, i.e.: > > * Brakes are used to apply breaking, (i.e. to slow the vehicle, > possibly to a stop), while stoppers STOP something. > * Starboard = to the right when facing the bow (front of the vessel) > not "my right", "your right" or "their right" (which depends on which > way you, I & they are facing). > * postprandial = after Lunch (not after eating any meal or after a > snack). > * A dinosaur is specifically an extinct terrible (formerly considered) > lizard where as a Gila Monster is definitely a scary & dangerous (dire) > lizard. > > In all of these cases there is a specificity to the word used that is > missing from the alternative offered that will, hopefully, be raised by > the use of that word. Unfortunately many people, when trying to explain > what the word means fail to highlight where it is different (the number > of times that I have heard people "explain" port and starboard as left > and right without mentioning the word bow or forward is countless). > > Using a slightly unfamiliar word can cause people to ask, or think > about, why this is different & what the difference is while also drawing > a parallel that can help the user/student to understand & remember the > concept. > > Also, picking a label for something, and using it consistently, can > vastly simplify things like manual searches (or on-line searches). > > The English language has, historically, always borrowed, co-opted and > sometimes perverted words from other languages to allow distinct > concepts to be expressed concisely - which I personally, (admittedly as > a native speaker), find rather useful. > > -- > 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. > https://www.avg.com > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Sat Aug 18 03:30:11 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sat, 18 Aug 2018 08:30:11 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: Summary: Discussion of the words 'jargon' and 'chatter'. Recommend that we > learn better how to find a compromise (strike a balance) between precision and simplicity. This thread is, in part, about the meaning, use and usefulness of words. And 'jargon' is what we are talking about. What is the meaning and use of 'jargon'? According to https://www.etymonline.com/word/jargon (discovered https://en.wikipedia.org/wiki/Jargon) === jargon (n.) mid-14c., "unintelligible talk, gibberish; chattering, jabbering," from Old French jargon "a chattering" (of birds), also "language, speech," especially "idle talk; thieves' Latin" (12c.). Ultimately of echoic origin (compare Latin garrire "to chatter"). >From 1640s as "mixed speech, pigin;" 1650s as "phraseology peculiar to a sect or profession," hence "mode of speech full of unfamiliar terms." Middle English also had it as a verb, jargounen "to chatter" (late 14c.), from French. === And according to https://www.etymonline.com/word/chatter === chatter (v.) early 13c., chateren "to twitter, make quick, shrill sounds" (of birds), "to gossip, talk idly or thoughtlessly" (of persons), earlier cheateren, chiteren, of echoic origin. Compare Dutch koeteren "jabber," Danish kvidre "twitter, chirp." Of teeth, "make a rattling noise from cold or fright," mid-15c. === Ordinary words can acquire a specialised technical meaning. For example === https://en.wikipedia.org/wiki/Machining_vibrations Machining vibrations, also called chatter, correspond to the relative movement between the workpiece and the cutting tool. The vibrations result in waves on the machined surface. This affects typical machining processes, such as turning, milling and drilling, and atypical machining processes, such as grinding. === Sometimes, machining vibrations make a ch-ch-ch-ch chattering sound. My opinions are that the correct technical phrase is 'machining vibrations', which is good for learned articles. But 'chatter' is better in the workshop. As in 'lubricate the drill bit to reduce chatter'. And here's another example === https://en.wikipedia.org/wiki/Chatter_(signals_intelligence) Chatter is a signals intelligence term, referring to the volume (quantity) of intercepted communications. Intelligence officials, not having better metrics, monitor the volume of communication, to or from suspected parties such as terrorists or spies, to determine whether there is cause for alarm. === Back to 'jargon'. === https://en.wikipedia.org/wiki/Jargon Accessibility issues With the rise of the self-advocacy movement within the disability movement, jargonised language has been much objected to by advocates and self-advocates. Jargon is largely present in every day language, in newspapers, government documents, and official forms. Several advocacy organisations work on influencing public agents to offer accessible information in different formats. [...] There is a balance to be struck, as excessive removal of technical terminology from a document leads to an equally undesirable outcome?dumbing down. === I think this last quote gets to the heart of the matter we're discussing. I suggest we learn better how to find a compromise (strike a balance) between precision and simplicity. -- Jonathan -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Sat Aug 18 05:34:45 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sat, 18 Aug 2018 10:34:45 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English Message-ID: Summary: I look at the phrase 'strike a balance' in different languages, and rewrite some wikipedia text on accessibility. I found in https://en.wikipedia.org/wiki/Jargon#Accessibility_issues === There is a balance to be struck, as excessive removal of technical terminology from a document leads to an equally undesirable outcome?dumbing down. === Aside: Found while writing https://mail.python.org/pipermail/python-ideas/2018-August/052819.html. I wondered how the phrase 'strike a balance' would translate into other languages (which is an accessibility issue). Using google translate I did round-tripping and other loops. (Simply curiosity driven, no agenda.) === en: strike a balance fr: trouver un ?quilibre en: find a balance de: finde ein Gleichgewicht arabic: ?????? ??? ??????? en: Find balance fi: Etsi tasapaino en: Find the balance de: Finde das Gleichgewicht === en: strike a balance al: t? krijoj? nj? ekuilib?r en: create a balance basque: oreka sortu en: create balance === >From this I found that 'balance' was the key to the phrase. And that the verb could variously be 'strike', 'find' or 'create'. There may be other verbs. The work 'strike' by itself often means 'stoppage' or 'industrial action'. Is this a hazard? So what's good, when English is the reader's second (or third) language? Surely, here, it's best not to use the word 'strike'. (In English 'strike out' means 'remove', not 'find'.) To try this out, let's rewrite: === There is a balance to be struck, as excessive removal of technical terminology from a document leads to an equally undesirable outcome?dumbing down. == How about === There is a balance to be found [or made] ... === Or we could use 'balance' as a verb (rather than as a noun). === It can be hard to balance removal of technical terminology against retaining essential meaning. === Or even not use the word 'balance' === Harmony between removal of technical terminology and retaining essential meaning can be hard. === Which is the best way to write the sentence, for a second-language English speaker? English is my first (and by far best) language. So I lack the experience, to make a good judgement. However, as an English speaker, I prefer the last > Harmony between removal of technical terminology and retaining essential meaning can be hard. By the way: the rewriting has changed the meaning. For this, how about > Removal of technical terminology may also remove essential meaning. -- Jonathan -------------- next part -------------- An HTML attachment was scrubbed... URL: From gadgetsteve at live.co.uk Sat Aug 18 05:48:07 2018 From: gadgetsteve at live.co.uk (Steve Barnes) Date: Sat, 18 Aug 2018 09:48:07 +0000 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: On 18/08/2018 10:34, Jonathan Fine wrote: > Summary: I look at the phrase 'strike a balance' in different languages, > and rewrite some wikipedia text on accessibility. > > I found in https://en.wikipedia.org/wiki/Jargon#Accessibility_issues > === > There is a balance to be struck, as excessive removal of technical > terminology from a document leads to an equally undesirable > outcome?dumbing down. > === > > Aside: Found while > writinghttps://mail.python.org/pipermail/python-ideas/2018-August/052819.html. > > I wondered how the phrase 'strike a balance' would translate into other > languages (which is an accessibility issue). > > Using google translate I did round-tripping and other loops. (Simply > curiosity driven, no agenda.) > === > en: strike a balance > fr: trouver un ?quilibre > en: find a balance > de:?finde ein Gleichgewicht > arabic:??????? ??? ??????? > en: Find balance > fi:?Etsi tasapaino > en: Find the balance > de: Finde das Gleichgewicht > === > en:?strike a balance > al: t? krijoj? nj? ekuilib?r > en:?create a balance > basque:?oreka sortu > en:?create balance > === > > From this I found that 'balance' was the key to the phrase. And that > the verb could variously be 'strike', 'find' or 'create'. There may be > other verbs. The work 'strike' by itself often means 'stoppage' or > 'industrial action'. Is this a hazard? > > So what's good, when English is the reader's second (or third) language? > Surely, here, it's best not to use the word 'strike'. (In English > 'strike out' means 'remove', not 'find'.) > > To try this out, let's rewrite: > === > There is a balance to be struck, as excessive removal of technical > terminology from a document leads to an equally undesirable > outcome?dumbing down. > == > > How about > === > There is a balance to be found [or made] ... > === > > Or we could use 'balance' as a verb (rather than as a noun). > === > It can be hard to balance removal of technical terminology against > retaining essential meaning. > === > > Or even not use the word 'balance' > === > Harmony between removal of technical terminology and retaining essential > meaning can be hard. > === > > Which is the best way to write the sentence, for a second-language > English speaker? English is my first (and by far best) language. So I > lack the experience, to make a good judgement. > > However, as an English speaker, I prefer the last > > Harmony between removal of technical terminology and retaining > essential meaning can be hard. > > By the way: the rewriting has changed the meaning. For this, how about > > Removal of technical terminology may also remove essential meaning. > > -- > Jonathan > Jonathan, It is interesting that you picked up on "strike a balance" which has been a standard English phrase for a very long time rather than the much more resent, (and itself a form of jargon), "dumbing down". The other point is that the use of Jargon is often as a form of shorthand so as to avoid excessive verbosity, (or long windedness). So I would be tempted to go with something like: "The removal of technical terminology needs to be moderated to account for the risk of loss of the essential meaning or the meaning being lost due to excessive length. Where such terminology is widely accepted within a given specialisation it should be considered acceptable but should, ideally, be defined on first usage or with a cross reference to a definition." -- 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. https://www.avg.com From mike at selik.org Sat Aug 18 13:47:00 2018 From: mike at selik.org (Michael Selik) Date: Sat, 18 Aug 2018 10:47:00 -0700 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: On Sat, Aug 18, 2018 at 2:48 AM Steve Barnes wrote: > "The removal of technical terminology needs to be moderated to account > for the risk of loss of the essential meaning or the meaning being lost > due to excessive length. Where such terminology is widely accepted > within a given specialisation it should be considered acceptable but > should, ideally, be defined on first usage or with a cross reference to > a definition." > If I may: While simplifying terms, we should try to keep the nuance that more esoteric jargon can provide. Staying concise is also important. -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Sun Aug 19 10:39:28 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Sun, 19 Aug 2018 23:39:28 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> tl;dr I don't think so, not very much. There are bigger fish to fry. I would appreciate comments on the last paragraph (before the footnotes), which can be read standalone. If opinion is at all favorable, I'll raise it with the PSF. Jonathan Fine writes: > Summary: Discussion of the words 'jargon' and 'chatter'. Recommend > that we learn better how to find a compromise (strike a balance) > between precision and simplicity. I'm not a big fan of asking that everybody put such effort into documentation for code they're developing. IMHO, where available users should just buy books by professional writers written to their level, rather than imposing this burden on the software development project. Developers themselves should be asked to write concise, precise documentation. I don't think it's at all a good idea to burden them with "accessibility" issues. It's hard enough to write good notes for yourself a year hence! Tutorial writers, OK, they should be cautioned to avoid jargon, but if they aren't already judicious about using jargon, maybe they shouldn't be writing tutorials at all? What about documentation patches from users (including developers who didn't write the docs being edited)? In general, I favor restricting these to correcting bugs, missing information, and extremely convoluted syntax. If the docs use jargon (by which I mean "informal technical terms, often local to the project") which is intelligible to long-time users but may be off-putting to newcomers and infrequent users (of the documentation, not the software!), I think it is better to provide a glossary.[1] The problem with editing inline is that there are direct costs and a missed opportunity. The direct costs include the potential for introducing imprecision and outright documentation bugs, and code churn (increasing the cost of reading diffs). The missed opportunity is that a good glossary will also serve users who graduate to "informal write-only documentation" including archives of mailing lists and group chats, and the issue tracker. I'm not sure about the "conventional" accessibility issues (ie, excluding newcomers, non-native speakers, and translators). As a developer/maintainer I have had a small amount of contact with users with perceptual and motor disabilities, but have never heard them complain[2] about jargon. (Small sample, but before we presume they would benefit from simplified docs, we should consult experts.) Serving non-native-speakers is a tough call. On the one hand, they would be best served by good translations and glossaries of English jargon in their native language. You don't need to speak English at all to write good programs in programming languages based on English keywords, and the concepts are easier to understand, and precision easier to obtain, if you're not fighting with a second language. For many of my students, the first language is Chinese, the second Japanese, and the third English. English keywords and the occasional concept denoted by jargon don't faze them. The problem is more following simple directions about inserting punctuation, misspelled words, and so on -- the closest literal translations often are poor semantic matches, and so all English is awkward for them. But I can understand half (well, 10% ;-) of what their sempai are saying in Chinese, because of the keywords and borrowed jargon -- and so can the kohai. Jargon isn't a problem; it's just another symbol for an unfamiliar concept that they need to learn. On the other, we're not doing a good job of encouraging translators. There are a lot of volunteers in the translation community, and (like programmers) an important reward is getting their product into the distribution. (This is *not* a complaint about the Python maintainers. The costs of infrastructure and maintaining synchronization of translations with the original documentation are still quite high.) I suppose there must be corporations who are doing translations for their Python-based products, and we can do a better job of getting them to contribute them upstream (although we currently have the problem of "where is upstream?" since we don't distribute translations ourselves). Finally, before getting the project into the hairy maintenance issues that go with distributing translations, I suggest the PSF could buy the high-quality tutorial books and textbooks (and maybe dictionaries as well) for translators. Very cheap, but the symbolism that "somebody noticed, and they care!" is a big reward for many contributors. Another possibility would be complimentary tickets (and/or travel grants) to PyCon. From past experience I gather that many translators are more focused on their natural language than on the projects whose documentation they translate, so it's probably not worth sending them to big international PyCons to be lionized by the core developers and PSF board members. On the other hand going to a local PyCon might be attractive, especially if they got complimentary tickets to some of the parties, where they would be introduced to keynote speakers and the like, and would be lionized by the people they're writing for. Not to mention getting feedback. Steve Footnotes: [1] The convention in academic and textbook writing of providing definitions (and expansions of abbreviations and acronyms) at first use is a good one, but the glossary is essential in technical documentation because users frequently dip into the middle of a document for a specific entry rather than reading linearly. [2] In fact, users with disabilities rarely complain in my experience. They just point out their issues without attitude. From kirillbalunov at gmail.com Sun Aug 19 10:43:12 2018 From: kirillbalunov at gmail.com (Kirill Balunov) Date: Sun, 19 Aug 2018 17:43:12 +0300 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: ??, 16 ???. 2018 ?. ? 22:37, Chris Barker via Python-ideas < python-ideas at python.org>: > > I wonder why locals doesn't return a Mapping Proxy, or other read-only > mapping object? > > If it's not guaranteed to be THE locals dict, and changes *may* not affect > the real one (but may), a read-only object seems like much safer idea. > > -CHB > > I have the same feeling and already have asked the same question before https://mail.python.org/pipermail/python-list/2018-February/731241.html. The main take away was that it is the CPython implementation detail and that `MappingProxy` type was introduced only in 3.3. I still do not find these arguments convincing. On the other hand with the current status quo - `locals` returns `dict` inside a function, we have only advantages: a) `locals` always returns a dict and is consistent in all places. (To be consistent is always good.) b) This type of question occurs every 6 months (there is always a topic to talk about at ML). c) When someone encounters this behavior first time, he thinks that he found a bug <- There was no error but nothing happened (gives an opportunity to study the internal details of the CPython implementation, the average level increases. Everyone also tries to find a way, something like "I believe, there must be a way, because Python is so dynamic" which theoretically allows you to make even more new discoveries.). d) This is considered by some as a way not to leak the CPython implementation details. (Here I have no comments, let it be on the conscience of others.) e) It leaves a room for a future changes (In fact, in some situations I would like to have this possibility). But if seriously, I think that the present situation is pretty weird especially when there is already the `MappingProxy` type. When it's not allowed and does not work (I'm only talking about the functions), it's better to raise early, instead of be silent until the last. With kind regards, -gdg -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Sun Aug 19 10:50:08 2018 From: rosuav at gmail.com (Chris Angelico) Date: Mon, 20 Aug 2018 00:50:08 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: On Mon, Aug 20, 2018 at 12:43 AM, Kirill Balunov wrote: > > ??, 16 ???. 2018 ?. ? 22:37, Chris Barker via Python-ideas > : >> >> >> I wonder why locals doesn't return a Mapping Proxy, or other read-only >> mapping object? >> >> If it's not guaranteed to be THE locals dict, and changes *may* not affect >> the real one (but may), a read-only object seems like much safer idea. >> >> -CHB >> > > I have the same feeling and already have asked the same question before > https://mail.python.org/pipermail/python-list/2018-February/731241.html. The > main take away was that it is the CPython implementation detail and that > `MappingProxy` type was introduced only in 3.3. I still do not find these > arguments convincing. On the other hand with the current status quo - > `locals` returns `dict` inside a function, we have only advantages: > > a) `locals` always returns a dict and is consistent in all places. (To be > consistent is always good.) > > b) This type of question occurs every 6 months (there is always a topic to > talk about at ML). > > c) When someone encounters this behavior first time, he thinks that he found > a bug <- There was no error but nothing happened (gives an opportunity to > study the internal details of the CPython implementation, the average level > increases. Everyone also tries to find a way, something like "I believe, > there must be a way, because Python is so dynamic" which theoretically > allows you to make even more new discoveries.). > > d) This is considered by some as a way not to leak the CPython > implementation details. (Here I have no comments, let it be on the > conscience of others.) > > e) It leaves a room for a future changes (In fact, in some situations I > would like to have this possibility). Related to (e) is that there is room for other implementations to permit changes to locals(), and furthermore, a fully-compliant Python implementation may use an actual dictionary for locals, and simply return that. (That CPython doesn't is an implementation detail for the sake of performance.) Requiring that it be a proxy would impose unnecessary cost on the implementation, without benefiting any compliant use. ChrisA From kirillbalunov at gmail.com Sun Aug 19 11:18:56 2018 From: kirillbalunov at gmail.com (Kirill Balunov) Date: Sun, 19 Aug 2018 18:18:56 +0300 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <18D9F6CB-50E8-415F-899A-1E3D9A42BC89@gmail.com> <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: ??, 19 ???. 2018 ?. ? 17:51, Chris Angelico : > On Mon, Aug 20, 2018 at 12:43 AM, Kirill Balunov > wrote: > > > [...] > > I have the same feeling and already have asked the same question before > > https://mail.python.org/pipermail/python-list/2018-February/731241.html. > The > > main take away was that it is the CPython implementation detail and that > > `MappingProxy` type was introduced only in 3.3. I still do not find these > > arguments convincing. On the other hand with the current status quo - > > `locals` returns `dict` inside a function, we have only advantages: > > > > a) `locals` always returns a dict and is consistent in all places. (To be > > consistent is always good.) > > > > b) This type of question occurs every 6 months (there is always a topic > to > > talk about at ML). > > > > c) When someone encounters this behavior first time, he thinks that he > found > > a bug <- There was no error but nothing happened (gives an opportunity to > > study the internal details of the CPython implementation, the average > level > > increases. Everyone also tries to find a way, something like "I believe, > > there must be a way, because Python is so dynamic" which theoretically > > allows you to make even more new discoveries.). > > > > d) This is considered by some as a way not to leak the CPython > > implementation details. (Here I have no comments, let it be on the > > conscience of others.) > > > > e) It leaves a room for a future changes (In fact, in some situations I > > would like to have this possibility). > > Related to (e) is that there is room for other implementations to > permit changes to locals(), and furthermore, a fully-compliant Python > implementation may use an actual dictionary for locals, and simply > return that. (That CPython doesn't is an implementation detail for the > sake of performance.) Requiring that it be a proxy would impose > unnecessary cost on the implementation, without benefiting any > compliant use. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ Let me disagree with you. While CPython is only one of the implementations of the Python language, it is the most common one and defacto is considered as a standard. Therefore, all the others, to be compliant, try to replicate all subtleties and features of the basic implementation - CPython. And even more so, I do not believe that anyone will rely or use such a feature. I'm not saying that this change should be a part of the Python language specification. I just said that this is already implied by the implementation of CPython3 and if you make it more clear with `MappingProxy` type it will be a net win in my eyes. With kind regards, -gdg -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Sun Aug 19 11:38:44 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sun, 19 Aug 2018 16:38:44 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> Message-ID: Hi Stephen Thank you for your message. I'll respond just to a few of your comments. HOW MUCH EFFORT ON DOCS ========================== Myself and you wrote: >> Summary: Discussion of the words 'jargon' and 'chatter'. Recommend >> that we learn better how to find a compromise (strike a balance) >> between precision and simplicity. > I'm not a big fan of asking that everybody put such effort into > documentation for code they're developing. IMHO, where available users > should just buy books by professional writers written to their level, > rather than imposing this burden on the software development project. Sections 6 and 7 (out of 31) in devguide for the Python project are on this. === https://devguide.python.org/docquality/ https://devguide.python.org/documenting/ === This is about 6.5%, of the devguide, by section count. There are at present 108 open documentation issues (out of about 6,000). This is about 2%. I'm proposing for example that we review, and if possible improve, these two sections in the devguide. This review would be evidence based. Not everyone need be involved in this. I suggest that doing this now would, over 3 years, significantly improve our Python documentation. AN EXAMPLE - super() ================== By chance, I wanted today to read about and then use super(). I found === https://docs.python.org/3/library/functions.html#super For practical suggestions on how to design cooperative classes using super(), see guide to using super(). === To my surprise, I found that this links, not to another part of the docs, but to === https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ === This excellent blog post is not, of course, indexed for the docs search. THE GLOSSARY ============= You wrote: > The missed opportunity is that a good glossary will also serve users > who graduate to "informal write-only documentation" including archives > of mailing lists and group chats, and the issue tracker. Five days ago, I raised an issue (one of the 108 open issues), to improve search in the glossary. And thanks to Ammar Askar, there's already a patch and pull request. This delights me. https://bugs.python.org/issue34398 https://github.com/python/cpython/pull/8773 TRANSLATION ============ You wrote: > Serving non-native-speakers is a tough call. On the one hand, they > would be best served by good translations and glossaries of English > jargon in their native language. There's already prior art on this. See: PEP 545 -- Python Documentation Translations https://www.python.org/dev/peps/pep-0545/ One of the alternatives in PEP 545 is === Simplified English It would be possible to introduce a "simplified English" version like wikipedia did, as discussed on python-dev, targeting English learners and children. === I think this would be a good idea, particularly for the tutorial (and other beginner materials, such as the glossary). -- with best regards Jonathan From jfine2358 at gmail.com Sun Aug 19 12:11:41 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sun, 19 Aug 2018 17:11:41 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> Message-ID: Hi Stephen I've just been reading the (excellent) discussion, started by Victor Stinner [Python-Dev] Translated Python documentation https://mail.python.org/pipermail/python-dev/2017-February/147416.html # Start of thread. You wrote, and asked for comments on: > Finally, before getting the project into the hairy maintenance issues > that go with distributing translations, I suggest the PSF could buy > the high-quality tutorial books and textbooks (and maybe dictionaries > as well) for translators. Very cheap, but the symbolism that > "somebody noticed, and they care!" is a big reward for many > contributors. I very much more prefer Victor's suggestion (I give the whole message): === https://mail.python.org/pipermail/python-dev/2017-February/147485.html IHMO translating the *whole* Python documentation at once by a professional translator can be very expensive, no somthing that the PSF would affort. Which language would you pick? Depending on what? We already have motivated translators for free who only ask us for the permission to make tiny changes to make their life simpler and make the doc more visible. I'm in favor of allowing them to translate and make the translated doc official ;-) IMHO a better usage of the PSF funding would be to organize some local sprints to translate the Python documentation. Such sprints are fun, cheap, and can be a nice opportunity to recruit free and motivated translators. We are looking for people involved to translate the doc the doc is updated, not only translate the doc once and go away. Right? === -- Jonathan From j.van.dorp at deonet.nl Mon Aug 20 02:35:09 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Mon, 20 Aug 2018 08:35:09 +0200 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: I would consider conciseness and accuracy most important. Using jargon but linking to accurate explanations would, in my not exactly humble opinion, be the best way to go about it. -------------- next part -------------- An HTML attachment was scrubbed... URL: From degrevesim at gmail.com Mon Aug 20 03:19:18 2018 From: degrevesim at gmail.com (Simon De Greve) Date: Mon, 20 Aug 2018 09:19:18 +0200 Subject: [Python-ideas] Asynchronous friendly iterables Message-ID: Hello everyone, I'm quite new working with asyncio and thus maybe missing some things about it, but wouldn't it be quite easier to have some iterables to support async for loops "natively", since asyncio is now part of the Stdlib? I've tried to work with asyncio while using discord.py, and has some struggle with an "async for" loop on a dictionary, so I had to implement a new dict subclass that would just reimplement items(), keys() and values() functions. I think that it would be a cool improvement to implement some of those in some standard way. There's some code I wrote on a CodeReview thread but I still haven't got any feedback on it. Here's the link of the thread : https://codereview.stackexchange.com/questions/197551/asynchronous-dictionary-in-python Regards, -------------- next part -------------- An HTML attachment was scrubbed... URL: From njs at pobox.com Mon Aug 20 03:29:49 2018 From: njs at pobox.com (Nathaniel Smith) Date: Mon, 20 Aug 2018 00:29:49 -0700 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: On Mon, Aug 20, 2018 at 12:19 AM, Simon De Greve wrote: > Hello everyone, > > I'm quite new working with asyncio and thus maybe missing some things about > it, but wouldn't it be quite easier to have some iterables to support async > for loops "natively", since asyncio is now part of the Stdlib? > > I've tried to work with asyncio while using discord.py, and has some > struggle with an "async for" loop on a dictionary, so I had to implement a > new dict subclass that would just reimplement items(), keys() and values() > functions. > > I think that it would be a cool improvement to implement some of those in > some standard way. There's some code I wrote on a CodeReview thread but I > still haven't got any feedback on it. > > Here's the link of the thread : > https://codereview.stackexchange.com/questions/197551/asynchronous-dictionary-in-python You can do this, but I don't see what it accomplishes... Are you aware that you can use regular 'for' loops inside 'async def' functions? -n -- Nathaniel J. Smith -- https://vorpus.org From degrevesim at gmail.com Mon Aug 20 03:34:42 2018 From: degrevesim at gmail.com (Simon De Greve) Date: Mon, 20 Aug 2018 09:34:42 +0200 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: Do you mean that for loops inside an "async def" statements are always executed as 'async for' loops? That's what I wanted to acheive by writing the AsyncDict class (c.f. the CodeReview link). As I said, I'm pretty new to Asyncio and thus may be missing some immportant feature of the lib (which is apparently the case here). Le lun. 20 ao?t 2018 ? 09:29, Nathaniel Smith a ?crit : > On Mon, Aug 20, 2018 at 12:19 AM, Simon De Greve > wrote: > > Hello everyone, > > > > I'm quite new working with asyncio and thus maybe missing some things > about > > it, but wouldn't it be quite easier to have some iterables to support > async > > for loops "natively", since asyncio is now part of the Stdlib? > > > > I've tried to work with asyncio while using discord.py, and has some > > struggle with an "async for" loop on a dictionary, so I had to implement > a > > new dict subclass that would just reimplement items(), keys() and > values() > > functions. > > > > I think that it would be a cool improvement to implement some of those in > > some standard way. There's some code I wrote on a CodeReview thread but I > > still haven't got any feedback on it. > > > > Here's the link of the thread : > > > https://codereview.stackexchange.com/questions/197551/asynchronous-dictionary-in-python > > You can do this, but I don't see what it accomplishes... > > Are you aware that you can use regular 'for' loops inside 'async def' > functions? > > -n > > -- > Nathaniel J. Smith -- https://vorpus.org > -------------- next part -------------- An HTML attachment was scrubbed... URL: From njs at pobox.com Mon Aug 20 03:47:39 2018 From: njs at pobox.com (Nathaniel Smith) Date: Mon, 20 Aug 2018 00:47:39 -0700 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: On Mon, Aug 20, 2018 at 12:34 AM, Simon De Greve wrote: > Do you mean that for loops inside an "async def" statements are always > executed as 'async for' loops? That's what I wanted to acheive by writing > the AsyncDict class (c.f. the CodeReview link). The only difference between an 'async for' and a regular 'for' is that the former works on async iterables, and the latter works on regular iterables. So "executed as 'async for'" doesn't really mean anything, I think? If you have an async iterable, use 'async for', and if you have a regular iterable, use 'for'. -n -- Nathaniel J. Smith -- https://vorpus.org From rosuav at gmail.com Mon Aug 20 03:49:04 2018 From: rosuav at gmail.com (Chris Angelico) Date: Mon, 20 Aug 2018 17:49:04 +1000 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: On Mon, Aug 20, 2018 at 5:34 PM, Simon De Greve wrote: > Do you mean that for loops inside an "async def" statements are always > executed as 'async for' loops? That's what I wanted to acheive by writing > the AsyncDict class (c.f. the CodeReview link). The point of an 'async for' loop is that grabbing the next value can block the async function - it's a yield point. If you don't need that, you can use a regular 'for' loop. ChrisA From turnbull.stephen.fw at u.tsukuba.ac.jp Mon Aug 20 04:54:25 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Mon, 20 Aug 2018 17:54:25 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> Message-ID: <23418.33217.203777.793534@turnbull.sk.tsukuba.ac.jp> Jonathan Fine writes: > One of the alternatives in PEP 545 is > === > Simplified English > It would be possible to introduce a "simplified English" version like > wikipedia did, as discussed on python-dev, targeting English learners > and children. > === As a *translation*, it's a very worthwhile experiment, if someone wants to do it. From turnbull.stephen.fw at u.tsukuba.ac.jp Mon Aug 20 04:55:59 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Mon, 20 Aug 2018 17:55:59 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180810070958.GM22431@ando.pearwood.info> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> <23417.33056.874196.815862@turnbull.sk.tsukuba.ac.jp> Message-ID: <23418.33311.578580.149806@turnbull.sk.tsukuba.ac.jp> Jonathan Fine writes: > I very much more prefer Victor's suggestion [of providing > translations in the distribution and giving translators commit > bits, AIUI]. I think we can do both. My suggestion is very cheap, and requires no change to release management, or even action by release managers and committers: the PSF board could announce the policy tomorrow and start cutting checks next Monday, and python-dev wouldn't notice. (I'm not suggesting overnight rollout is a good idea, and practically speaking the board can't act that fast, of course. The point is that there's potential encouragement for translators, improved documentation for users, at zero cost to the code developers and release managers.) The suggestion of providing official translations in the distribution has been made before, and resisted by the maintainers and committers. I don't oppose the idea myself, I simply observe that resistance and the explanations offered, and assume there is good reason for it. Steve From jpic at yourlabs.org Mon Aug 20 07:13:48 2018 From: jpic at yourlabs.org (Jamesie Pic) Date: Mon, 20 Aug 2018 13:13:48 +0200 Subject: [Python-ideas] Redefining method In-Reply-To: References: Message-ID: Sorry if my message offended anyone (noted that the "Toxic Forum" post came not long after mine). What I meant is that I cannot defend such an idea before extensively using it. I just don't know how to do it this way. Have a great day -------------- next part -------------- An HTML attachment was scrubbed... URL: From rhodri at kynesim.co.uk Mon Aug 20 09:03:08 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Mon, 20 Aug 2018 14:03:08 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: On 18/08/18 01:59, Abe Dillon wrote: > The argument I tried to make is, "yes I believe there are cases where a > less jargon identifier is preferable and that I believe 'lambda' is an > example of a missed opportunity to use a less jargon (maybe 'esoteric' is a > better word here?), more descriptive name." While I don't entirely disagree with you, if I had been responsible for inventing that bit of Python I would probably have gone with "lambda" too. It had been part of my vocabulary as a computer scientist long before I met it in a programming language. Whether it's a *good* choice or not... possibly reusing "def" would fit people's expectations better, or perhaps it would have caused more confusion. Who can tell? Jargon becomes jargon because it's useful to enough people, for occasionally rather odd definitions of "useful". In the case of lambda, it's shorter than "inline function definition" and lambda calculus at least shows up on most CompSci courses. Once it settles into a group, you use it because other members of the group will understand what you mean and might not understand if you rephrase it. > For instance: when the iPhone was introduced, a lot of people praised > it's subjectively "slick" user interface. I believe that perception of > slickness is partly because the iPhone emulated physical interfaces > very well so it leveraged people's intuition about the physical world. > It was delightfully intuitive. One of the things Apple have always been very good at is thinking hard about user interfaces. What made the iPhone so good was that they emulated the right physical interfaces, so flipping a page when you're reading rather than pressing a button. -- Rhodri James *-* Kynesim Ltd From jsbueno at python.org.br Mon Aug 20 09:53:17 2018 From: jsbueno at python.org.br (Joao S. O. Bueno) Date: Mon, 20 Aug 2018 10:53:17 -0300 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: On Mon, 20 Aug 2018 at 04:49, Chris Angelico wrote: > > On Mon, Aug 20, 2018 at 5:34 PM, Simon De Greve wrote: > > Do you mean that for loops inside an "async def" statements are always > > executed as 'async for' loops? That's what I wanted to acheive by writing > > the AsyncDict class (c.f. the CodeReview link). > > The point of an 'async for' loop is that grabbing the next value can > block the async function - it's a yield point. If you don't need that, > you can use a regular 'for' loop. Maybe it is worth to further clarify that iterating on dicts and lists is _not_ blocking at all. That would only be the case if to retrieve its own keys the dictionary would have to perform some I/O access or heavy computation - which, besides been of very little value in practice, would only be possible in a specialized class anyway. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ From dmoisset at machinalis.com Mon Aug 20 09:55:31 2018 From: dmoisset at machinalis.com (Daniel Moisset) Date: Mon, 20 Aug 2018 14:55:31 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: I think that annotations were suggested because you could write an expression there without getting evaluated. I've thought about this problem many times in the past (as a Python dev with a long history working in Eiffel too).... For me one of the crucial issue that is hard to translate into the python model is that the assertions (say, a function precondition) are not conceptually part of the function itself, but the interface of the class. The "natural" python ways of attaching these assertions somehow to the function object do not work when you also use inheritance, because when you override a method the new function object clobbers the previous one. I've experimented at some point on how to put them in classes (and doing metaclass or __getattribute__ tricks) but nothing convinced me). In general, the way that python puts method call and inheritance semantic in a specific layout of runtime objects (which in general is really clever) seems to be a bit alien to the DbC idea where the asbtraction/interface of the class is conceptually separate and has independent information wrt to the runtime objects. On 16 August 2018 at 18:49, Marko Ristin-Kaufmann wrote: > Hi Jonathan and Paul, > Thank you very much for your suggestions! I will try to contact the author > of the PEP. > > Let me clarify a bit a potential misunderstanding. Please mind that > contracts are not tied to individual variables, but to expressions. Think > of it as defining a lambda which takes as input all the arguments of the > function (and a result variable in case of post-conditions) which always > needs to evaluate to True. > > Cheers, > Marko > > Le jeu. 16 ao?t 2018 ? 12:24, Paul Moore a ?crit : > >> On Thu, 16 Aug 2018 at 10:41, Jonathan Fine wrote: >> > >> > Hi Marko >> > >> > Thank you for introducing yourself, and clearly stating your question. >> > That helps us all. You asked: >> > >> > > Could somebody update me on the state of the discussion on this >> matter? >> > >> > I think bring the existing PEP up to date would be a good starting >> > point. Its content hasn't been changed since 2003 (except for PEP-wide >> > admin changes. (Recall that Python 3.0 was released in 2008.) >> > >> > https://www.python.org/dev/peps/pep-0316/ >> > https://github.com/python/peps/commits/master/pep-0316.txt >> > >> > In fact, revising the PEP might be enough to answer your question. >> > What do you think, Marko? >> > >> > Experts: is there a process for revising old PEPs, such as this one? >> > Or at least a precedent we could follow (or adapt)? >> >> I'm not aware of a formal process, but I'd have thought the following >> steps would be a reasonable approach: >> >> 1. Review the PEP, and research the discussions that happened at the >> time, particularly of interest is why the PEP was deferred. >> 2. Consider what (if anything) has changed since the original deferral >> (which could simply be "time has moved on, people's views may have >> changed" but ideally would include a bit more in the way of concrete >> motivation). >> 3. Contact the original PEP author and ask if he is interested in >> reopening the discussion, collaborating on a revision, or handing the >> PEP over. >> 4. Start up a discussion here, pointing out the original PEP and >> summarising the previous debate and why you want to restart the >> discussion. If you're hoping to change the details of the original >> PEP, summarise your changes and why you feel they are an improvement >> over the original. >> >> To answer the OP's question more directly: >> >> > Could somebody update me on the state of the discussion on this matter? >> >> As far as I am aware, there has been no discussion on this subject >> since the PEP 316 discussions which ended up in its deferral. Elazar >> mentioned PEP 563, and there *may* have been mention of design by >> contract uses in the discussions on that PEP, but you'd have to search >> the mailing list archives to confirm that one way or another. >> >> Hence the suggestions that if you want to restart discussion, reviving >> PEP 316 is likely the best approach. >> >> Paul >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- Daniel Moisset Technical Leader A: 1 Fore St, EC2Y 9DT London P: +44 7398 827139 <+44+7398+827139> M: dmoisset at machinalis.com | S: dmoisset -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Mon Aug 20 10:21:37 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 21 Aug 2018 00:21:37 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> Message-ID: <20180820142137.GC22431@ando.pearwood.info> On Sun, Aug 19, 2018 at 06:18:56PM +0300, Kirill Balunov wrote: [...] > > > e) It leaves a room for a future changes (In fact, in some situations I > > > would like to have this possibility). [Chris] > > Related to (e) is that there is room for other implementations to > > permit changes to locals(), and furthermore, a fully-compliant Python > > implementation may use an actual dictionary for locals, and simply > > return that. (That CPython doesn't is an implementation detail for the > > sake of performance.) Requiring that it be a proxy would impose > > unnecessary cost on the implementation, without benefiting any > > compliant use. I would like to see CPython locals() return a mapping object which raises a warning when you mutate it. * Currently, assignments to locals() simply do the wrong thing (modify the dict but fail to modify the local namespace) silently; such errors should never pass silently. * It should be a warning, not an error, since there are use-cases for modifying the local dict without caring about the namespace; in those cases we can simply silence the warning or ignore it. * Introducing a warning makes it clear that this is not a de facto language standard, but a mere implementation detail subject to change if somebody comes up with a better optimization for locals. - Other implementations should be permitted to use local namespaces which are read/write (that's a Quality Of Implementation issue). - Given that uses of locals() inside a function are already restricted and presumably uncommon, the extra cost of a warning is unlikely to be meaningful. [Kirill] > Let me disagree with you. While CPython is only one of the implementations > of the Python language, it is the most common one and defacto is considered > as a standard. Not in this case. If CPython intended this to be the language behaviour, it should specify that limitation instead of merely giving a doc warning that changes "may not" affect the local variables. In fact, the warning in the docs is too strong. Modifying locals() inside a class or module scope is allowed, and works fine. It is only functions which is problematic. > Therefore, all the others, to be compliant, try to replicate > all subtleties and features of the basic implementation - CPython. Implementations are expected to obey the documented behaviour (unless given special dispensation to break the rules, which I think has happened once or twice with MicroPython). For behaviour which isn't dpcumented, it is true that implementations *often* try to copy CPython, but that's not mandatory and there are exceptions. PyPy is probably the alternate implementation which tries the hardest to duplicate CPython, but even PyPy has differences: http://doc.pypy.org/en/latest/cpython_differences.html including a few things which the PyPy developers believe is a bug in CPython. This list of differences between Jython and CPython is terribly out of date, but I haven't found anything more recent: http://www.jython.org/archive/21/docs/differences.html > And even > more so, I do not believe that anyone will rely or use such a feature. Users of CPython frequently rely on CPython implementation details. Why do you think Jython and IronPython users will be different? -- Steve From rosuav at gmail.com Mon Aug 20 10:37:11 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 21 Aug 2018 00:37:11 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180820142137.GC22431@ando.pearwood.info> References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> <20180820142137.GC22431@ando.pearwood.info> Message-ID: On Tue, Aug 21, 2018 at 12:21 AM, Steven D'Aprano wrote: > On Sun, Aug 19, 2018 at 06:18:56PM +0300, Kirill Balunov wrote: > > [...] >> > > e) It leaves a room for a future changes (In fact, in some situations I >> > > would like to have this possibility). > > [Chris] >> > Related to (e) is that there is room for other implementations to >> > permit changes to locals(), and furthermore, a fully-compliant Python >> > implementation may use an actual dictionary for locals, and simply >> > return that. (That CPython doesn't is an implementation detail for the >> > sake of performance.) Requiring that it be a proxy would impose >> > unnecessary cost on the implementation, without benefiting any >> > compliant use. > > I would like to see CPython locals() return a mapping object which > raises a warning when you mutate it. That, I can get behind. Requiring it to be a proxy would IMO be a bad idea; but the warning here would be a CPython implementation detail. OTOH, warnings are easy to miss. But on the gripping hand, if more of Python and CPython raised warnings when odd things or implementation-specific things were done, it would encourage people to develop with warnings active. ChrisA From jfine2358 at gmail.com Mon Aug 20 11:18:58 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Mon, 20 Aug 2018 16:18:58 +0100 Subject: [Python-ideas] Documentation of locals() Message-ID: Summary: There's prior art in bug.python.org relating to off-thread topic discussion of locals(). Suggest work on closing open documentation issues relating to locals(). In the thread === Jump to function as an an alternative to call function https://mail.python.org/pipermail/python-ideas/2018-August/052761.html === there was post === https://mail.python.org/pipermail/python-ideas/2018-August/052807.html I wonder why locals doesn't return a Mapping Proxy, or other read-only mapping object? === and a discussion resulted. There's prior art on bugs.python.org, which can be found by searching for 'locals()' in the issue title. (Search for 'locals' gives more results.) One of the items is (created 2013 and still open): === Documentation of globals() and locals() should be improved https://bugs.python.org/issue19737 === In this issue Terry Read writes === https://bugs.python.org/msg204769 In my opinion, vague ideas like this one should go to python-ideas first. === I suggest that those that have time, energy and interest focus on closing the open locals() documentation issues. Such documentation would, I think, provide an excellent starting point for any proposals to change behaviour. There are 13 open issues with 'locals' in the title. -- Jonathan From jfine2358 at gmail.com Mon Aug 20 11:23:02 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Mon, 20 Aug 2018 16:23:02 +0100 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> <20180820142137.GC22431@ando.pearwood.info> Message-ID: Hi I've created new thread === Documentation of locals() https://mail.python.org/pipermail/python-ideas/2018-August/052843.html Summary: There's prior art in bug.python.org relating to off-thread topic discussion of locals(). Suggest work on closing open documentation issues relating to locals(). [...] I suggest that those that have time, energy and interest focus on closing the open locals() documentation issues. Such documentation would, I think, provide an excellent starting point for any proposals to change behaviour. There are 13 open issues with 'locals' in the title. === Perhaps the discussion of locals() here could be moved to the new thread. -- Jonathan From degrevesim at gmail.com Mon Aug 20 11:42:46 2018 From: degrevesim at gmail.com (Simon De Greve) Date: Mon, 20 Aug 2018 17:42:46 +0200 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: Ok, as I thought I was missing something quite important in the process. Thanks to everybody in here. Le lun. 20 ao?t 2018 ? 15:53, Joao S. O. Bueno a ?crit : > On Mon, 20 Aug 2018 at 04:49, Chris Angelico wrote: > > > > On Mon, Aug 20, 2018 at 5:34 PM, Simon De Greve > wrote: > > > Do you mean that for loops inside an "async def" statements are always > > > executed as 'async for' loops? That's what I wanted to acheive by > writing > > > the AsyncDict class (c.f. the CodeReview link). > > > > The point of an 'async for' loop is that grabbing the next value can > > block the async function - it's a yield point. If you don't need that, > > you can use a regular 'for' loop. > > Maybe it is worth to further clarify that iterating on dicts and lists > is _not_ blocking at all. > That would only be the case if to retrieve its own keys the dictionary > would have > to perform some I/O access or heavy computation - which, besides been of > very > little value in practice, would only be possible in a specialized class > anyway. > > > > > > ChrisA > > _______________________________________________ > > Python-ideas mailing list > > Python-ideas at python.org > > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Mon Aug 20 12:07:20 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Mon, 20 Aug 2018 09:07:20 -0700 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: > > > Summary: I look at the phrase 'strike a balance' in different languages, > > It is interesting that you picked up on "strike a balance" which has > been a standard English phrase for a very long time rather than the much > more resent, (and itself a form of jargon), "dumbing down". > > The other point is that the use of Jargon is often as a form of > shorthand so as to avoid excessive verbosity, (or long windedness). > We are (maybe) mingling two issues here -- there is an important distinction between idiomatic expressions ("striking a balance", "dumbing down") and technical terms (jargon). If you want to make it easier for non-native english speakers to understand -- minimal use of idiomatic expressions is a good idea. They really don't serve much real purpose, other than making the prose more colorful and friendly (to those that understand it). Sometimes a bit of brevity is gained, but not much. Technical jargon, on the other hand, can be very helpful for precision and compactness. (side note -- are all domain-specific technical term "jargon"? I tend to see "jargon" as having a negative connotation -- specifically that it isn't required for technical specificity. That is, "jargon" is language that is unnecessarily domain specific) I think it's pretty important to use the common domain specific terms in introductory texts -- how else will folks learn them? So I make a distinction between *using* a technical term, and *introducing* a technical term. In fact, in my PR on Jonathan's doc on None, I deliberately introduced the term "Singleton" -- not because it was necessary to understand the idea at hand, but because people are likely to encounter the term elsewhere. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Mon Aug 20 12:16:02 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Mon, 20 Aug 2018 09:16:02 -0700 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180820142137.GC22431@ando.pearwood.info> References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> <20180820142137.GC22431@ando.pearwood.info> Message-ID: On Mon, Aug 20, 2018 at 7:21 AM, Steven D'Aprano wrote: > * Introducing a warning makes it clear that this is not a de facto > language standard, but a mere implementation detail subject to > change if somebody comes up with a better optimization for locals. > defacto standards are sub-optimum -- the docs say "may not" -- that seems really sketchy to me. Even if there is no change to the implementation of cPython, I'd like to see the behavior clearly defined -- if I pass a object returned by "locals()" to a function, and that function modifies that object -- will, or will not, the local namespace be altered? Saying it "may" be altered is kind of crazy! Does that mean the same code will have a different effect if run in two different (compliant) implementations of Python? That sure seems like a bad idea... > more so, I do not believe that anyone will rely or use such a feature. > well, this thread exists because someone wanted to do something like that -- i.e. manipulate the calling namespace from within a function. I suggested that passing locals() in might work -- it didn't work (in cPython), but if it HAD worked in whatever implementation the OP is using, then, yes, someone would now be relying on that feature. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Mon Aug 20 13:26:05 2018 From: abedillon at gmail.com (Abe Dillon) Date: Mon, 20 Aug 2018 12:26:05 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: Responding out of order. [Rhodri James] > > For instance: when the iPhone was introduced, a lot of people praised > > it's subjectively "slick" user interface. I believe that perception of > > slickness is partly because the iPhone emulated physical interfaces > > very well so it leveraged people's intuition about the physical world. > > It was delightfully intuitive. > One of the things Apple have always been very good at is thinking hard > about user interfaces. What made the iPhone so good was that they emulated > the right physical interfaces, so flipping a page when you're reading > rather than pressing a button. Yes, that's exactly what I was trying to say. An important point that I think keeps getting lost in this conversation is that Python's grammar, syntax, and standard lib are it's user interface. There are very different constraints on Python's UI than there are when humans have to communicate directly with other humans. I have no problem using words like "closure" or "lambda expression" or "ternary expression" when communicating with other humans about programming language features, but jargon doesn't often make sense as part of Python's UI itself. Again, we don't use the word "ternary" in Python's ternary expressions. [Rhodri James] > Jargon becomes jargon because it's useful to enough people, for > occasionally rather odd definitions of "useful". In the case of lambda, > it's shorter than "inline function definition" Yes, again: I understand the utility of jargon. I don't think "anonymous function" would be an improvement over "lambda" because, while it is fairly descriptive, it sacrifices too much brevity. However; the word "anonymous" is redundant. You can tell the function is anonymous by virtue of the fact that it doesn't have a name. "function" is only two characters longer than "lambda" and is actually descriptive, but it probably would have caused backwards compatibility issues (same with "func" or "fun"). "def" would have been even shorter than "lambda". [Rhodri James] > and lambda calculus at least shows up on most CompSci courses. I suppose if by "courses" you mean "course plans", I highly doubt that the majority of CS classes cover lambda calc, though; I couldn't say for sure because I, like many programmers, didn't take CS in college. There are many disciplines that get by on basic algorithms, data-structures, and a pinch of theory. [Rhodri James] > Once it settles into a group, you use it because other members of the > group will understand what you mean and might not understand if you > rephrase it. If the group you're referring to are Computer Scientists, then I don't see why they would be confused by a syntax that omits the word "lambda" since very few languages use the word "lambda" to denote a lambda expression. [Rhodri James] > While I don't entirely disagree with you, if I had been responsible for > inventing that bit of Python I would probably have gone with "lambda" too. > It had been part of my vocabulary as a computer scientist long before I met > it in a programming language. Whether it's a *good* choice or not... > possibly reusing "def" would fit people's expectations better, or perhaps > it would have caused more confusion. Who can tell? I don't see how "def" could cause more confusion than "lambda". Those who don't know what "lambda" refers to would at least have some notion of what "def" means, and those who have studied and know what lambda calculus is should also have very little trouble. I don't expect it would confuse someone well versed in computer science any more than a check-engine light would throw off an expert mechanic. They can at least google "python anonymous function" or "python lambda expression" and get results that tell you how to write a lambda expression in Python. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Mon Aug 20 14:16:51 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 21 Aug 2018 04:16:51 +1000 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> <20180820142137.GC22431@ando.pearwood.info> Message-ID: On Tue, Aug 21, 2018 at 2:16 AM, Chris Barker via Python-ideas wrote: > On Mon, Aug 20, 2018 at 7:21 AM, Steven D'Aprano > wrote: >> >> * Introducing a warning makes it clear that this is not a de facto >> language standard, but a mere implementation detail subject to >> change if somebody comes up with a better optimization for locals. > > > defacto standards are sub-optimum -- the docs say "may not" -- that seems > really sketchy to me. > > Even if there is no change to the implementation of cPython, I'd like to see > the behavior clearly defined -- if I pass a object returned by "locals()" to > a function, and that function modifies that object -- will, or will not, the > local namespace be altered? Saying it "may" be altered is kind of crazy! > Does that mean the same code will have a different effect if run in two > different (compliant) implementations of Python? That sure seems like a bad > idea... If you do the wrong thing, a compliant Python is allowed to do one of two things. It's no different from anything else that's been defined as the wrong thing - opening a file and then dropping it on the floor (might close it promptly, might not), testing integers by identity ("x is 5"), etc, etc. The language is well-enough-defined that you can be confident that locals()["x"]=1 will EITHER change x to 1 OR have no significant effect. If you truly want to mandate that every Python implementation absolutely perfectly imitate CPython, what is the point of other implementations? Or a language spec? They'd just be refactorings of CPython. ChrisA From rhodri at kynesim.co.uk Mon Aug 20 14:24:53 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Mon, 20 Aug 2018 19:24:53 +0100 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> <20180820142137.GC22431@ando.pearwood.info> Message-ID: On 20/08/18 17:16, Chris Barker via Python-ideas wrote: > On Mon, Aug 20, 2018 at 7:21 AM, Steven D'Aprano > wrote: > >> * Introducing a warning makes it clear that this is not a de facto >> language standard, but a mere implementation detail subject to >> change if somebody comes up with a better optimization for locals. >> > defacto standards are sub-optimum -- the docs say "may not" -- that seems > really sketchy to me. On the contrary, it is well defined in international standards usage. "May" and "may not" indicate that behaviour is optional, so shouldn't be relied on. -- Rhodri James *-* Kynesim Ltd From barry at barrys-emacs.org Mon Aug 20 16:58:00 2018 From: barry at barrys-emacs.org (Barry) Date: Mon, 20 Aug 2018 21:58:00 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: <8834C1B2-FC9C-4592-A1D2-7679FA322DB0@barrys-emacs.org> > On 20 Aug 2018, at 07:35, Jacco van Dorp wrote: > > I would consider conciseness and accuracy most important. Using jargon but linking to accurate explanations would, in my not exactly humble opinion, be the best way to go about it. +1 my thoughts exactly. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ From barry at barrys-emacs.org Mon Aug 20 17:13:26 2018 From: barry at barrys-emacs.org (Barry Scott) Date: Mon, 20 Aug 2018 22:13:26 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> > On 20 Aug 2018, at 17:07, Chris Barker via Python-ideas wrote: > > > Summary: I look at the phrase 'strike a balance' in different languages, > > It is interesting that you picked up on "strike a balance" which has > been a standard English phrase for a very long time rather than the much > more resent, (and itself a form of jargon), "dumbing down". > > The other point is that the use of Jargon is often as a form of > shorthand so as to avoid excessive verbosity, (or long windedness). > > We are (maybe) mingling two issues here -- there is an important distinction between idiomatic expressions ("striking a balance", "dumbing down") and technical terms (jargon). > > If you want to make it easier for non-native english speakers to understand -- minimal use of idiomatic expressions is a good idea. They really don't serve much real purpose, other than making the prose more colorful and friendly (to those that understand it). Sometimes a bit of brevity is gained, but not much. The technical writing course I went on as an engineer years ago recommenced "Controlled English" in documentation. Its good for none english speakers and the lack of colloquial expression means English speaks are not miss lead. As you say this is nothing to do with jargon. > > Technical jargon, on the other hand, can be very helpful for precision and compactness. It also means you will understand other people doing the same activity. Be they musicians or programmers. > > (side note -- are all domain-specific technical term "jargon"? I tend to see "jargon" as having a negative connotation -- specifically that it isn't required for technical specificity. That is, "jargon" is language that is unnecessarily domain specific) I found this definition: "Jargon. A special language belonging exclusively to a group, often a profession. Engineers, lawyers, doctors, tax analysts, and the like all use jargon to exchange complex information efficiently. Jargon is often unintelligible to those outside the group that uses it." Not all group members remember to avoid jargon when talking to people outside the group. If you are on the outside looking in at the people that will not explain in plain english you could well consider jargon as a bad thing. > > I think it's pretty important to use the common domain specific terms in introductory texts -- how else will folks learn them? So I make a distinction between *using* a technical term, and *introducing* a technical term. Yes. > > In fact, in my PR on Jonathan's doc on None, I deliberately introduced the term "Singleton" -- not because it was necessary to understand the idea at hand, but because people are likely to encounter the term elsewhere. Barry > > -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 at noaa.gov _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Mon Aug 20 20:16:54 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 21 Aug 2018 10:16:54 +1000 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: Message-ID: <20180821001654.GA24160@ando.pearwood.info> On Mon, Aug 20, 2018 at 09:07:20AM -0700, Chris Barker via Python-ideas wrote: > (side note -- are all domain-specific technical term "jargon"? Yes. But not all jargon is a domain-specific technical term. https://en.wiktionary.org/wiki/jargon -- Steve From wes.turner at gmail.com Mon Aug 20 22:44:19 2018 From: wes.turner at gmail.com (Wes Turner) Date: Mon, 20 Aug 2018 22:44:19 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: pycontracts may be worth a look. https://andreacensi.github.io/contracts/ - @contract decorator, annotations, docstrings IDK if pycontracts supports runtime parameter validations that involve more than one parameter. Inheritance does appear to be supported, as are numpy array dimension constraints. I can't recall whether the pycontracts expression language precedes MyPy compile-time annotations; both with one syntax really would be great. On Monday, August 20, 2018, Daniel Moisset wrote: > I think that annotations were suggested because you could write an > expression there without getting evaluated. > > I've thought about this problem many times in the past (as a Python dev > with a long history working in Eiffel too).... For me one of the crucial > issue that is hard to translate into the python model is that the > assertions (say, a function precondition) are not conceptually part of the > function itself, but the interface of the class. The "natural" python ways > of attaching these assertions somehow to the function object do not work > when you also use inheritance, because when you override a method the new > function object clobbers the previous one. I've experimented at some point > on how to put them in classes (and doing metaclass or __getattribute__ > tricks) but nothing convinced me). In general, the way that python puts > method call and inheritance semantic in a specific layout of runtime > objects (which in general is really clever) seems to be a bit alien to the > DbC idea where the asbtraction/interface of the class is conceptually > separate and has independent information wrt to the runtime objects. > > > On 16 August 2018 at 18:49, Marko Ristin-Kaufmann > wrote: > >> Hi Jonathan and Paul, >> Thank you very much for your suggestions! I will try to contact the >> author of the PEP. >> >> Let me clarify a bit a potential misunderstanding. Please mind that >> contracts are not tied to individual variables, but to expressions. Think >> of it as defining a lambda which takes as input all the arguments of the >> function (and a result variable in case of post-conditions) which always >> needs to evaluate to True. >> >> Cheers, >> Marko >> >> Le jeu. 16 ao?t 2018 ? 12:24, Paul Moore a ?crit : >> >>> On Thu, 16 Aug 2018 at 10:41, Jonathan Fine wrote: >>> > >>> > Hi Marko >>> > >>> > Thank you for introducing yourself, and clearly stating your question. >>> > That helps us all. You asked: >>> > >>> > > Could somebody update me on the state of the discussion on this >>> matter? >>> > >>> > I think bring the existing PEP up to date would be a good starting >>> > point. Its content hasn't been changed since 2003 (except for PEP-wide >>> > admin changes. (Recall that Python 3.0 was released in 2008.) >>> > >>> > https://www.python.org/dev/peps/pep-0316/ >>> > https://github.com/python/peps/commits/master/pep-0316.txt >>> > >>> > In fact, revising the PEP might be enough to answer your question. >>> > What do you think, Marko? >>> > >>> > Experts: is there a process for revising old PEPs, such as this one? >>> > Or at least a precedent we could follow (or adapt)? >>> >>> I'm not aware of a formal process, but I'd have thought the following >>> steps would be a reasonable approach: >>> >>> 1. Review the PEP, and research the discussions that happened at the >>> time, particularly of interest is why the PEP was deferred. >>> 2. Consider what (if anything) has changed since the original deferral >>> (which could simply be "time has moved on, people's views may have >>> changed" but ideally would include a bit more in the way of concrete >>> motivation). >>> 3. Contact the original PEP author and ask if he is interested in >>> reopening the discussion, collaborating on a revision, or handing the >>> PEP over. >>> 4. Start up a discussion here, pointing out the original PEP and >>> summarising the previous debate and why you want to restart the >>> discussion. If you're hoping to change the details of the original >>> PEP, summarise your changes and why you feel they are an improvement >>> over the original. >>> >>> To answer the OP's question more directly: >>> >>> > Could somebody update me on the state of the discussion on this matter? >>> >>> As far as I am aware, there has been no discussion on this subject >>> since the PEP 316 discussions which ended up in its deferral. Elazar >>> mentioned PEP 563, and there *may* have been mention of design by >>> contract uses in the discussions on that PEP, but you'd have to search >>> the mailing list archives to confirm that one way or another. >>> >>> Hence the suggestions that if you want to restart discussion, reviving >>> PEP 316 is likely the best approach. >>> >>> Paul >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> >> > > > -- > > Daniel Moisset > Technical Leader > > A: 1 Fore St, EC2Y 9DT London > P: +44 7398 827139 <+44+7398+827139> > M: dmoisset at machinalis.com | S: dmoisset > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tjreedy at udel.edu Mon Aug 20 23:15:35 2018 From: tjreedy at udel.edu (Terry Reedy) Date: Mon, 20 Aug 2018 23:15:35 -0400 Subject: [Python-ideas] Asynchronous friendly iterables In-Reply-To: References: Message-ID: On 8/20/2018 3:19 AM, Simon De Greve wrote: > Hello everyone, > > I'm quite new working with asyncio and thus maybe missing some things > about it, but wouldn't it be quite easier to have some iterables to > support async for loops "natively", since asyncio is now part of the > Stdlib? One purpose of asynchronous programming is to pause a task that is waiting for input from an external system, so as to not waste CPU time. As other noted, this is not an issue with iterating through in-memory collections. It is worth noting that 'async' and 'await' are syntax keywords for working with coroutines (how is underdocumented) and that the asyncio module is just one event-loop system that can drive coroutines. The tkinter module, over 20 years old, can also. > I've tried to work with asyncio while using discord.py, and has some > struggle with an "async for" loop on a dictionary, so I had to implement > a new dict subclass that would just reimplement items(), keys() and > values() functions. Another purpose of asynchonous programming is to keep a system responsive, for instance, to user input by not letting a compute-bound task tie-up a cpu indefinitely. This issue *can* apply to iterating through sufficiently large collection in, for instance, a tkinter gui program. But pausing iteration after *each* iteration is usually a terrible waste of overhead. So one wants to do some number of iterations at full speed and then pause to allow other events to be handled. > I think that it would be a cool improvement to implement some of those > in some standard way. Occasionally pausing iteration should not be a method of the iterable or iterator. We need instead wrapper functions. One idea is to pause every k iterations. For user responsiveness, we want to pause for event handling after a certain time has elapsed, say 50 milliseconds. I think it should be possible to do this directly instead of pre-testing how long it takes to do 1 interation. I know how to do the above with tkinter callback loops, but I have not yet worked out how to do so with async def coroutines. -- Terry Jan Reedy From tjreedy at udel.edu Mon Aug 20 23:37:09 2018 From: tjreedy at udel.edu (Terry Reedy) Date: Mon, 20 Aug 2018 23:37:09 -0400 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: On 8/20/2018 5:13 PM, Barry Scott wrote: > > >> On 20 Aug 2018, at 17:07, Chris Barker via Python-ideas >> > > wrote: >> >> > Summary: I look at the phrase 'strike a balance' in different languages, >> >> It is interesting that you picked up on "strike a balance" which has >> been a standard English phrase for a very long time rather than >> the much >> more resent, (and itself a form of jargon), "dumbing down". >> >> The other point is that the use of Jargon is often as a form of >> shorthand so as to avoid excessive verbosity, (or long windedness). >> >> >> We are (maybe) mingling two issues here --? there is an important >> distinction between idiomatic expressions ("striking a balance", >> "dumbing down") and technical terms (jargon). >> >> If you want to make it easier for non-native english speakers to >> understand -- minimal use of idiomatic expressions is a good idea. >> They really don't serve much real purpose, other than making the prose >> more colorful and friendly (to those that understand it). Sometimes a >> bit of brevity is gained, but not much. > > The technical writing course I went on as an engineer years ago > recommenced "Controlled English" in documentation. > Its good for none english speakers and the lack of?colloquial expression > means English speaks are not miss lead. > > As you say this is nothing to do with jargon. > >> >> Technical jargon, on the other hand, can be very helpful for precision >> and compactness. > > It also means you will understand other people doing the same activity. > Be they musicians or programmers. > >> >> (side note -- are all domain-specific technical term "jargon"? I tend >> to see "jargon" as having a negative connotation -- specifically that >> it isn't required for technical specificity. That is, "jargon" is >> language that is unnecessarily domain specific) > > I found this definition: > > "J/argon/. A special language belonging exclusively to a group, often a > profession. Engineers, lawyers, doctors, tax analysts, and the like all > use /jargon/ to exchange complex information efficiently. > /Jargon/ is often unintelligible to those outside the group that uses it." To me, 'jargon' refers more to in-group replacements for common words (slang) than to technical terms. 'Hack the bug' for 'Fix the program error' is an example of the former. 'Use a coroutine' uses a technical term that needs several sentences and some preliminary knowledge about functions to explain. In any case, docs should avoid slangy jargon and explain technical terms. > Not all group members remember to avoid jargon > when talking to people > outside the group. > If you are on the outside looking in at the people that will not explain > in plain english you could well consider jargon as a bad thing. >> I think it's pretty important to use the common domain specific terms >> in introductory texts -- how else will folks learn them? So I make a >> distinction between *using* a technical term, and *introducing* a >> technical term. > > Yes. -- Terry Jan Reedy From turnbull.stephen.fw at u.tsukuba.ac.jp Tue Aug 21 01:07:33 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Tue, 21 Aug 2018 14:07:33 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <1b8e0506-3414-4fb9-9a0c-c913c3074309@googlegroups.com> <20180813010612.GP22431@ando.pearwood.info> <5B71FF06.2070407@canterbury.ac.nz> Message-ID: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> Rhodri James writes: > On 18/08/18 01:59, Abe Dillon wrote: > > The argument I tried to make is, "yes I believe there are cases where a > > less jargon identifier is preferable and that I believe 'lambda' is an > > example of a missed opportunity to use a less jargon (maybe 'esoteric' is a > > better word here?), more descriptive name." > > While I don't entirely disagree with you, if I had been responsible for > inventing that bit of Python I would probably have gone with "lambda" > too. It had been part of my vocabulary as a computer scientist long > before I met it in a programming language. I was an economist then, and I'm an economist still, but I met lambda in 1977. Surely lambda has had that role in computer languages since shortly before I was born. I would guess anybody above a certain age would reach for "lambda" first for a keyword to denote or define an anonymous function. Not because of the lambda calculus, but because of Lisp. (OK, that's indirectly because of the lambda calculus.) Had Guido decided to change it to "def", I suspect he'd be regretting it slightly today, for reasons similar to the regrets about "range": we normally only allow omitting positional arguments at the end of the list. Maybe there's a better word than "regret". After all, It's hard to see how you could prototype range better than "range([START,] END, [STRIDE])", and the same might be true for "def [NAME] ([ARG0,] ...):". From marko.ristin at gmail.com Tue Aug 21 03:06:54 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Tue, 21 Aug 2018 09:06:54 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: Hi, I had a look at the messages related to the PEP in question (PEP 316) in the archive. As far as I can tell, the main objection is that you can achieve contracts by implementing it with decorators. I think that these objections miss what actually Daniel Moisset wrote in his message: contracts are more than pre- and post-condition checks on a function. The inheritance of decorators does not imply just inheriting the pre- and post-conditions, but also relaxing and tightening them (represented by "require else" and "ensure then" in Eiffel). If this is to be used effectively in practice with little overhead then we would either need to introduce new syntax to the language or make the compiler improve the byte code on the fly. Is there any chance to introduce these constructs in the language or is it too small a feature for such a big change? Since we wanted to have contracts in Golang, we implemented a tool that synchronizes the documentation of a function with the function code ( https://github.com/Parquery/gocontracts). Maybe this is the easier path to follow in Python as well? @Wes Turner: thanks for pointing to pycontracts. I'm aware of the library. It implements only contracts based on a single property. We found that limiting and rolled out our own solution that suited us much better: https://github.com/Parquery/icontract/ I also found informative messages on contract breach to be particularly important for fast development and error inspection in the production. Cheers, Marko On 21 August 2018 at 04:44, Wes Turner wrote: > pycontracts may be worth a look. > > https://andreacensi.github.io/contracts/ > > - @contract decorator, annotations, docstrings > > IDK if pycontracts supports runtime parameter validations that involve > more than one parameter. > > Inheritance does appear to be supported, > as are numpy array dimension constraints. > > I can't recall whether the pycontracts expression language precedes MyPy > compile-time annotations; both with one syntax really would be great. > > > On Monday, August 20, 2018, Daniel Moisset > wrote: > >> I think that annotations were suggested because you could write an >> expression there without getting evaluated. >> >> I've thought about this problem many times in the past (as a Python dev >> with a long history working in Eiffel too).... For me one of the crucial >> issue that is hard to translate into the python model is that the >> assertions (say, a function precondition) are not conceptually part of the >> function itself, but the interface of the class. The "natural" python ways >> of attaching these assertions somehow to the function object do not work >> when you also use inheritance, because when you override a method the new >> function object clobbers the previous one. I've experimented at some point >> on how to put them in classes (and doing metaclass or __getattribute__ >> tricks) but nothing convinced me). In general, the way that python puts >> method call and inheritance semantic in a specific layout of runtime >> objects (which in general is really clever) seems to be a bit alien to the >> DbC idea where the asbtraction/interface of the class is conceptually >> separate and has independent information wrt to the runtime objects. >> >> >> On 16 August 2018 at 18:49, Marko Ristin-Kaufmann > > wrote: >> >>> Hi Jonathan and Paul, >>> Thank you very much for your suggestions! I will try to contact the >>> author of the PEP. >>> >>> Let me clarify a bit a potential misunderstanding. Please mind that >>> contracts are not tied to individual variables, but to expressions. Think >>> of it as defining a lambda which takes as input all the arguments of the >>> function (and a result variable in case of post-conditions) which always >>> needs to evaluate to True. >>> >>> Cheers, >>> Marko >>> >>> Le jeu. 16 ao?t 2018 ? 12:24, Paul Moore a ?crit : >>> >>>> On Thu, 16 Aug 2018 at 10:41, Jonathan Fine >>>> wrote: >>>> > >>>> > Hi Marko >>>> > >>>> > Thank you for introducing yourself, and clearly stating your question. >>>> > That helps us all. You asked: >>>> > >>>> > > Could somebody update me on the state of the discussion on this >>>> matter? >>>> > >>>> > I think bring the existing PEP up to date would be a good starting >>>> > point. Its content hasn't been changed since 2003 (except for PEP-wide >>>> > admin changes. (Recall that Python 3.0 was released in 2008.) >>>> > >>>> > https://www.python.org/dev/peps/pep-0316/ >>>> > https://github.com/python/peps/commits/master/pep-0316.txt >>>> > >>>> > In fact, revising the PEP might be enough to answer your question. >>>> > What do you think, Marko? >>>> > >>>> > Experts: is there a process for revising old PEPs, such as this one? >>>> > Or at least a precedent we could follow (or adapt)? >>>> >>>> I'm not aware of a formal process, but I'd have thought the following >>>> steps would be a reasonable approach: >>>> >>>> 1. Review the PEP, and research the discussions that happened at the >>>> time, particularly of interest is why the PEP was deferred. >>>> 2. Consider what (if anything) has changed since the original deferral >>>> (which could simply be "time has moved on, people's views may have >>>> changed" but ideally would include a bit more in the way of concrete >>>> motivation). >>>> 3. Contact the original PEP author and ask if he is interested in >>>> reopening the discussion, collaborating on a revision, or handing the >>>> PEP over. >>>> 4. Start up a discussion here, pointing out the original PEP and >>>> summarising the previous debate and why you want to restart the >>>> discussion. If you're hoping to change the details of the original >>>> PEP, summarise your changes and why you feel they are an improvement >>>> over the original. >>>> >>>> To answer the OP's question more directly: >>>> >>>> > Could somebody update me on the state of the discussion on this >>>> matter? >>>> >>>> As far as I am aware, there has been no discussion on this subject >>>> since the PEP 316 discussions which ended up in its deferral. Elazar >>>> mentioned PEP 563, and there *may* have been mention of design by >>>> contract uses in the discussions on that PEP, but you'd have to search >>>> the mailing list archives to confirm that one way or another. >>>> >>>> Hence the suggestions that if you want to restart discussion, reviving >>>> PEP 316 is likely the best approach. >>>> >>>> Paul >>>> _______________________________________________ >>>> Python-ideas mailing list >>>> Python-ideas at python.org >>>> https://mail.python.org/mailman/listinfo/python-ideas >>>> Code of Conduct: http://python.org/psf/codeofconduct/ >>>> >>> >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >>> >> >> >> -- >> >> Daniel Moisset >> Technical Leader >> >> A: 1 Fore St, EC2Y 9DT London >> P: +44 7398 827139 <+44+7398+827139> >> M: dmoisset at machinalis.com | S: dmoisset >> >> >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Tue Aug 21 06:20:35 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 21 Aug 2018 20:20:35 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: <20180821102035.GB24160@ando.pearwood.info> On Tue, Aug 21, 2018 at 09:06:54AM +0200, Marko Ristin-Kaufmann wrote: > Is there any chance to introduce these constructs in the language or is it > too small a feature for such a big change? I don't think contracts is a small feature. I think it is a HUGE feature, but under-appreciated by most developers. (Probably due to unfamiliarity, and the difficulty in using it in a language with no syntactic support.) Whether it is practical to add it to Python, I don't know. I suspect that we would have to develop some sort of third-party solution first, even if it did not do everything contracts ought to do (or do them less efficiently) as a proof of concept. PyContracts is probably a good place to start. For those who missed Wes' email: https://andreacensi.github.io/contracts/ Cobra is another good place to look, as it demonstrates a nice syntax that reads like a cross between Python and Eiffel: http://cobra-language.com/trac/cobra/wiki/Contracts -- Steve From songofacandy at gmail.com Tue Aug 21 06:33:15 2018 From: songofacandy at gmail.com (INADA Naoki) Date: Tue, 21 Aug 2018 19:33:15 +0900 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: On Thu, Aug 16, 2018 at 4:19 PM Elazar wrote: > > You might also be interested in pep-563. although it is not intended for design by contract, it can help (syntactically). > FYI, PEP 563 doesn't help it. Read this section: https://www.python.org/dev/peps/pep-0563/#non-typing-usage-of-annotations "With this in mind, uses for annotations incompatible with the aforementioned PEPs should be considered deprecated." -- INADA Naoki From p.f.moore at gmail.com Tue Aug 21 06:40:10 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Tue, 21 Aug 2018 11:40:10 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180821102035.GB24160@ando.pearwood.info> References: <20180821102035.GB24160@ando.pearwood.info> Message-ID: On Tue, 21 Aug 2018 at 11:27, Steven D'Aprano wrote: > > On Tue, Aug 21, 2018 at 09:06:54AM +0200, Marko Ristin-Kaufmann wrote: > > > Is there any chance to introduce these constructs in the language or is it > > too small a feature for such a big change? > > I don't think contracts is a small feature. I think it is a HUGE > feature, but under-appreciated by most developers. (Probably due to > unfamiliarity, and the difficulty in using it in a language with no > syntactic support.) Agreed. And it sounds like there are a lot of subtleties to contracts that I certainly hadn't appreciated (I don't know if the same is true of others). For example, On Tue, 21 Aug 2018 at 08:08, Marko Ristin-Kaufmann wrote: > > I think that these objections miss what actually Daniel Moisset wrote in his message: contracts are more than pre- and post-condition checks on a function. The inheritance of decorators does not imply just inheriting the pre- and post-conditions, but also relaxing and tightening them (represented by "require else" and "ensure then" in Eiffel). If this is to be used effectively in practice with little overhead then we would either need to introduce new syntax to the language or make the compiler improve the byte code on the fly. I've no idea what "relaxing" and "tightening" of contracts involves, or how it would translate into Python. So I'd imagine that in order to put together a proposal for adding contracts to Python, you'd need to explain what contracts are, and how they work, to get past people's preconceptions that "they are just assertions". Otherwise, it's likely to be hard to persuade people of the benefits. Personally, I don't really think I can comment much further, precisely because it looks like I don't know enough about what contracts are and how they'd be used to contribute :-) Paul From jfine2358 at gmail.com Tue Aug 21 09:12:47 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 14:12:47 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: Hi Earlier today, I did a search for 'documentation by example python' and found Example of great documentation in Python: Nick Loadholtes (copied) https://ironboundsoftware.com/blog/2017/12/11/great-documentation-python/ The example is: https://docs.python.org/3/library/random.html#examples-and-recipes So who to thank: Here's the history of the source for the doc page. https://github.com/python/cpython/commits/3.7/Doc/library/random.rst I don't have time right now to look at all the history. But most of the recent commits are from Raymond Hettinger. I'll give Nick's web page the last word. Make your docs work as hard as your code does. Clear examples will make your code stand out in a good way. Great documentation is out there, lets make more of it. Here?s what you need to create: * A plain language explanation of what your library does * The shortest possible code example * A quick list of any common issues * Links to where you can learn more details If you can create that for your code, you are doing a great service to us all. -- Jonathan From steve at pearwood.info Tue Aug 21 10:31:21 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 22 Aug 2018 00:31:21 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> Message-ID: <20180821143121.GD24160@ando.pearwood.info> On Tue, Aug 21, 2018 at 02:07:33PM +0900, Stephen J. Turnbull wrote: > I was an economist then, and I'm an economist still, but I met lambda > in 1977. Surely lambda has had that role in computer languages since > shortly before I was born. I would guess anybody above a certain age > would reach for "lambda" first for a keyword to denote or define an > anonymous function. Not because of the lambda calculus, but because > of Lisp. (OK, that's indirectly because of the lambda calculus.) Its pretty much a term of art. (Aside: "term of art" is itself a term of art: https://legal-dictionary.thefreedictionary.com/Term+of+Art ) I think that complaining about lambda is like complaining about "3-sigma versus 6-sigma processes" in process management. (Not computer processes, manufacturing processes and quality control.) Or for that matter, "mean" and "standard deviation" in statistics. The main difference is that most people are introduced to mean and stdev in secondary school, while functional programming idioms and lambda are generally stumbled across in the field. (I know that's how I learned of the term: through Python.) > Had Guido decided to change it to "def", I suspect he'd be regretting > it slightly today, for reasons similar to the regrets about "range": > we normally only allow omitting positional arguments at the end of the > list. Maybe there's a better word than "regret". After all, It's > hard to see how you could prototype range better than "range([START,] > END, [STRIDE])", and the same might be true for "def [NAME] ([ARG0,] > ...):". Secure in the knowledge that Guido probably isn't reading this and won't contradict me *wink* I'm going to try channelling him. I think he would regret "def expressions", but not because of the range reason. I think its because he likes the relatively strict demarcation between statements and expressions. We have 4 statements that have a expression form: if...else versus ternary if expressions; for loops versus comprehensions; (soon) = assignment versus := assignment expressions; and def versus lambda. (Did I miss any? I don't include technicalities like dot attribute access versus getattr and similar.) It's notable that in none of those cases the syntax is quite the same in the two forms. There's always enough differentiation between the statement and expression that there's never any ambiguity which is intended. We don't have: result = if condition expression else expression where it is the lack of colons which hints that it is an expression, we have a completely different syntax. So I think Guido probably wouldn't like the idea of using def in expressions: def function(arg, callback=def: None): pass That's my guess, for what it's worth. -- Steve From jfine2358 at gmail.com Tue Aug 21 12:55:34 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 17:55:34 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: Nick Loadholtes wrote (elsewhere, quoted in this thread - by me). > Make your docs work as hard as your code does. Clear examples will > make your code stand out in a good way. With a bit more searching I found: https://www.reddit.com/r/Python/comments/70myto/whats_new_in_python_37_python_370a0_documentation/dn4v667/ I'll disagree. Nothing is better than Mathworks documentation. I like documentation by example. Python gives you the dry, technically correct verbiage behind how something works. Matlab says: "Here, copy paste this and it'll work". To the point that the workspace is designed to automatically strip >>> from any copy and pasted commands. Even with most Python examples you can't just copy and paste a chunk of an example from the web or documentation because you need to clean off >>> first. It did me good, to read the resulting discussion on reddit. -- Jonathan From gadgetsteve at live.co.uk Tue Aug 21 13:51:58 2018 From: gadgetsteve at live.co.uk (Steve Barnes) Date: Tue, 21 Aug 2018 17:51:58 +0000 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: On 21/08/2018 17:55, Jonathan Fine wrote: > Nick Loadholtes wrote (elsewhere, quoted in this thread - by me). > >> Make your docs work as hard as your code does. Clear examples will >> make your code stand out in a good way. > > With a bit more searching I found: > > https://www.reddit.com/r/Python/comments/70myto/whats_new_in_python_37_python_370a0_documentation/dn4v667/ > > I'll disagree. Nothing is better than Mathworks documentation. I like > documentation by example. > > Python gives you the dry, technically correct verbiage behind how > something works. > > Matlab says: "Here, copy paste this and it'll work". > > To the point that the workspace is designed to automatically strip >>> > from any copy and pasted commands. > > Even with most Python examples you can't just copy and paste a chunk > of an example from the web or documentation because you need to clean > off >>> first. > > > It did me good, to read the resulting discussion on reddit. > I would just like to point out that the ipython %paste magic very handily strips leading >, ... & + characters from the pasted block, (there is also some clever dedenting done). So taking the example code: >>> def fn(param): ... """ Print the param """ ... print(param) ... >>> fn(6) on the clipboard and in ipython entering %paste results in: In [2]: %paste >>> def fn(param): ... """ Print the param """ ... print(param) ... >>> fn(6) ## -- End pasted text -- 6 Which is ideal. I personally find that many beginners get on a lot better in the iPython console than in the python one. -- 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. https://www.avg.com From abedillon at gmail.com Tue Aug 21 13:56:27 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 12:56:27 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180821143121.GD24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Stephen Turnbull] > I was an economist then, and I'm an economist still, but I met lambda > in 1977. Surely lambda has had that role in computer languages since > shortly before I was born. According to Wikipedia Lisp was the first language to use anonymous functions (introduced in 1958). [Stephen Turnbull] > I would guess anybody above a certain age > would reach for "lambda" first for a keyword to denote or define an > anonymous function. Not because of the lambda calculus, but because > of Lisp. Wikipedia lists the anonymous function syntax of 40+ languages and only 5 (Lisp, Scheme, Python, Ruby, and Maxima) use the "lambda" keyword. Haskel uses a "\" which I'm pretty sure is supposed to look like the lambda symbol, but even that syntax seems unpopular too. [Stephen Turnbull] > Maybe there's a better word than "regret". After all, It's > hard to see how you could prototype range better than "range([START,] > END, [STRIDE])", and the same might be true for "def [NAME] ([ARG0,] > ...):". I wasn't aware that Guido considered "range" to be warty. I like the way it mimics slicing syntax. It makes it easy for me to remember. It seems like a very pragmatic design. [Steven D'Aprano] > Secure in the knowledge that Guido probably isn't reading this and won't > contradict me *wink* I'm going to try channelling him. SUMMON THE GREAT CREATOR! I wonder if I say his name three times... Guido Van Rossum! Guido Van Rossum! Guido Van Rossum! [Steven D'Aprano] > I think he would regret "def expressions", but not because of the range > reason. I think its because he likes the relatively strict demarcation between statements > and expressions. > We have 4 statements that have a expression form: > if...else versus ternary if expressions; > for loops versus comprehensions; > (soon) = assignment versus := assignment expressions; and > def versus lambda. (I don't know why Gmail's quotes screw up formatting...) I don't think that's the reason those expressions have different formats than their statement counterparts. Expressions allow for more flexible arrangement than expressions because the order of execution of an expression doesn't have to follow the order of declaration. While it's more natural to say "do something to each item in this collection that meets some condition" you can't access variables before they're declared in statements so you have to tell the computer explicitly that you're looping over some iterable first. Expressions allow you to be more expressive. You don't have to put your edge-case checking up-front and in the way. When 99.9% of the time you just want: x = y you can shove the edge-case checking to the side and let the core logic shine: x = y if not edge_case else special_value # extra spaces added for emphasis besides: result = if condition expression else expression is super awkward to read out loud. That's not how I think at least. I've never hears someone say, "My child's name will be if it's a girl Sally otherwise Billy." All of the expressions use either the same or similar keywords or symbols *except* def and lambda. func = def : Is about as different from the statement form as "x := y" is from "x = y". No name, no parentheses for the arguments. Finally, I know you've heard the other half of my anti-lambda manifest, but I don't know if Stephen Turnbull has, so I'll briefly present it again. It's not just the name "lambda" that bothers me, it's the arrangement of the logic and signature. I believe that the expressiveness that allows comprehensions to put the core logic in front of the less important (for readability) loop and filtering constructs, anonymous functions could have been arranged to put the logic in front of the (almost always) less important signature. The reason I say the signature is almost always less important is because one almost always uses an anonymous functions as an argument (key-function, callback, map, reduce, filter, etc.) to something that already defines the call signature it expects. Consider the alternate form: with (thought there are many alternative possibilities) hand = sorted(cards, key=lambda card: value[card.suit] if card is not wild else max_value) hand = sorted(cards, by=value[card.suit] if card is not wild else max_value with card) # notice how unsurprising it is that the signature is "card" Oh wait... Did I accidentally replace "key" with "by"? Huh... It seems to make more sense even though the jargon is a "key function"... Oops! ;) Note: if this were a full proposal, lambdas with complex arguments or in certain situations would require parens: ( with ) On Tue, Aug 21, 2018 at 9:31 AM, Steven D'Aprano wrote: > On Tue, Aug 21, 2018 at 02:07:33PM +0900, Stephen J. Turnbull wrote: > > > I was an economist then, and I'm an economist still, but I met lambda > > in 1977. Surely lambda has had that role in computer languages since > > shortly before I was born. I would guess anybody above a certain age > > would reach for "lambda" first for a keyword to denote or define an > > anonymous function. Not because of the lambda calculus, but because > > of Lisp. (OK, that's indirectly because of the lambda calculus.) > > Its pretty much a term of art. > > (Aside: "term of art" is itself a term of art: > https://legal-dictionary.thefreedictionary.com/Term+of+Art ) > > > I think that complaining about lambda is like complaining about "3-sigma > versus 6-sigma processes" in process management. (Not computer > processes, manufacturing processes and quality control.) Or for that > matter, "mean" and "standard deviation" in statistics. > > The main difference is that most people are introduced to mean and stdev > in secondary school, while functional programming idioms and lambda are > generally stumbled across in the field. (I know that's how I learned of > the term: through Python.) > > > > Had Guido decided to change it to "def", I suspect he'd be regretting > > it slightly today, for reasons similar to the regrets about "range": > > we normally only allow omitting positional arguments at the end of the > > list. Maybe there's a better word than "regret". After all, It's > > hard to see how you could prototype range better than "range([START,] > > END, [STRIDE])", and the same might be true for "def [NAME] ([ARG0,] > > ...):". > > Secure in the knowledge that Guido probably isn't reading this and won't > contradict me *wink* I'm going to try channelling him. I think he would > regret "def expressions", but not because of the range reason. I think > its because he likes the relatively strict demarcation between > statements and expressions. > > We have 4 statements that have a expression form: > > if...else versus ternary if expressions; > > for loops versus comprehensions; > > (soon) = assignment versus := assignment expressions; and > > def versus lambda. > > (Did I miss any? I don't include technicalities like dot attribute > access versus getattr and similar.) It's notable that in none of those > cases the syntax is quite the same in the two forms. There's always > enough differentiation between the statement and expression that there's > never any ambiguity which is intended. We don't have: > > result = if condition expression else expression > > where it is the lack of colons which hints that it is an expression, we > have a completely different syntax. So I think Guido probably wouldn't > like the idea of using def in expressions: > > def function(arg, callback=def: None): > pass > > > That's my guess, for what it's worth. > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 14:12:08 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 04:12:08 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 3:56 AM, Abe Dillon wrote: > I've never hears someone say, "My child's name will be if it's a girl Sally > otherwise Billy." "My child's name depends on gender - if it's a girl, Sally, otherwise Billy." Seems fine to me. You can always come up with something awkward in a particular order, but it's not the order that made it awkward. > Consider the alternate form: with (thought there are > many alternative possibilities) > > hand = sorted(cards, key=lambda card: value[card.suit] if card is not wild > else max_value) > > hand = sorted(cards, by=value[card.suit] if card is not wild else > max_value with card) > > # notice how unsurprising it is that the signature is "card" Okay, let's read that. hand = # we're assigning this to the name 'hand' sorted( # calling the function named 'sorted' cards, # positional argument, whatever's in the 'cards' variable by= # keyword argument, what comes next is the 'by' argument value[card.suit] # subscript 'value' with 'card.suit' if card is not wild # yep else max_value # so we have an alternative with card # WAIT WAIT WAIT Once you get to 'with card', you have to go back and completely reinterpret everything prior to that as a function. You have to scan back and go "hang on, so exactly how much of this is getting wrapped up into a function here?". Contrast the Python version: hand = sorted(cards, key=lambda card: value[card.suit] if card is not wild else max_value) hand = # we're assigning this to the name 'hand' sorted( # calling the function named 'sorted' cards, # positional argument, whatever's in the 'cards' variable key= # keyword argument, what comes next is the 'key' argument lambda card: # a function taking one argument value[card.suit] # subscript 'value' with 'card.suit' if card is not wild # yep else max_value # so we have an alternative ) # and we're done The only part where you have to back up and change your interpretation is when you hit "if card is not wild", which reads well enough to justify the odd ordering. (JFTR, I wouldn't implement a deck of cards this way. It implies that there is exactly one wild card, where many decks of cards have at least two. In English, "card is not wild" can be interpreted as a membership check, but in Python, it is only an identity check; you're capitalizing on false readability by using this notation.) > Oh wait... Did I accidentally replace "key" with "by"? Huh... It seems to > make more sense even though the jargon is a "key function"... Oops! ;) I'm sure it would make even more sense if you wrote it this way: hand = sorted(cards, by="suit") That's how SQL works - you just name the column that you want to order the results by. But if you think "by" is a better keyword here, start explaining why your ordering is done with an anonymous function, not with an attribute name. ChrisA From rosuav at gmail.com Tue Aug 21 14:14:33 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 04:14:33 +1000 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: On Wed, Aug 22, 2018 at 2:55 AM, Jonathan Fine wrote: > Nick Loadholtes wrote (elsewhere, quoted in this thread - by me). > >> Make your docs work as hard as your code does. Clear examples will >> make your code stand out in a good way. > > With a bit more searching I found: > > https://www.reddit.com/r/Python/comments/70myto/whats_new_in_python_37_python_370a0_documentation/dn4v667/ > > I'll disagree. Nothing is better than Mathworks documentation. I like > documentation by example. > > Python gives you the dry, technically correct verbiage behind how > something works. > > Matlab says: "Here, copy paste this and it'll work". > > To the point that the workspace is designed to automatically strip >>> > from any copy and pasted commands. > > Even with most Python examples you can't just copy and paste a chunk > of an example from the web or documentation because you need to clean > off >>> first. > Where in the linked-to What's New page is there an example of that? There are several code blocks that ARE copy/pasteable, even into the vanilla interpreter. ChrisA From jfine2358 at gmail.com Tue Aug 21 14:29:06 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 19:29:06 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: Chris Angelico wrote > Where in the linked-to What's New page is there an example of that? > There are several code blocks that ARE copy/pasteable, even into the > vanilla interpreter. Good question. The reddit user wrote. https://www.reddit.com/r/Python/comments/70myto/whats_new_in_python_37_python_370a0_documentation/dn4zd20/ Take this example for re.sub. [https://docs.python.org/3/library/re.html#re.sub] Trying that out requires 3 separate copy and pastes just to do one example. Or you have to put it in an intermediate file, clean it up then paste it in. The examples are also grouped by sub function not by what they do. I think the problem is the user didn't see the [>>>] toggle at the top right of the code block. I know I didn't just now, when I tried it just now. It was only the strength of your assertion, Chris, that made me go back and try again. https://docs.python.org/3/tutorial/introduction.html In the following examples, input and output are distinguished by the presence or absence of prompts (>>> and ?): to repeat the example, you must type everything after the prompt, when the prompt appears; lines that do not begin with a prompt are output from the interpreter. Note that a secondary prompt on a line by itself in an example means you must type a blank line; this is used to end a multi-line command. No mention here, or elsewhere on the page, that [>>>] at the top right of a code example toggles the presence or absence of prompts. -- Jonathan From jfine2358 at gmail.com Tue Aug 21 14:36:52 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 19:36:52 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: Hi Steve You wrote: > I would just like to point out that the ipython %paste magic very > handily strips leading >, ... & + characters from the pasted block, > (there is also some clever dedenting done). [useful example, snipped] > Which is ideal. I personally find that many beginners get on a lot > better in the iPython console than in the python one. Thank you very much for this. I didn't know about this solution to the problem. Docs search for ipython brings up https://docs.python.org/3/tutorial/interactive.html One alternative enhanced interactive interpreter that has been around for quite some time is IPython, which features tab completion, object exploration and advanced history management. It can also be thoroughly customized and embedded into other applications. Another similar enhanced interactive environment is bpython. I've now played a little with (both look nice): > https://www.bpython-interpreter.org > https://repl.it/repls/LightcoralMoralDistributedcomputing Perhaps beginners would benefit from something better than the default, but simpler than ipython. But I don't have any experience to support this view. There's related prior art in the well-regarded https://codewith.mu/en/about. (Steve, I'd welcome your comments on this.) So thank you for bringing iPython's nifty %paste trick to my (and the thread's) attention. -- Jonathan From jfine2358 at gmail.com Tue Aug 21 14:53:07 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 19:53:07 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: I wrote: > No mention here, or elsewhere on the page, that [>>>] at the top > right of a code example toggles the presence or absence of prompts. Now raised, and cross-referenced as an issue. https://bugs.python.org/issue34451 docs: tutorial/introduction doesn't mention toggle of prompts Perhaps discussion of this should move there. -- Jonathan From abedillon at gmail.com Tue Aug 21 14:56:16 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 13:56:16 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Chris Angelico] > Okay, let's read that. > hand = # we're assigning this to the name 'hand' > sorted( # calling the function named 'sorted' > cards, # positional argument, whatever's in the 'cards' variable > by= # keyword argument, what comes next is the 'by' argument > value[card.suit] # subscript 'value' with 'card.suit' > if card is not wild # yep > else max_value # so we have an alternative > with card # WAIT WAIT WAIT > Once you get to 'with card', you have to go back and completely > reinterpret everything prior to that as a function. The revelation that it's a function should come when you read the "by" or "key". If you don't know what that parameter is, then that's where the "wait wait wiat!" should happen. Then type "help(sorted)" in a console or something. Another hint can come from the appearance of an undeclared variable: card. (I know, I know: I didn't declare several variables, just imagine that 'card' is the only variable not previously declared). It's no more surprising than reading a comprehension: initials = {person.name[0] for person in people if person.name} initials = # we're assigning this to the name "initials" initials = { # it's a dictionary or set of something initials = { person.name[0] # I'v never seen "person" before, this must be a comprehension or something # anyway, no ":" means it's a set of the first letter of each person's name intiials = { person.name[0] for person # WAIT WAIT WIAT WHAT?!? Just kidding, I saw this coming... [Chris Angelico] > > Oh wait... Did I accidentally replace "key" with "by"? Huh... It seems to > > make more sense even though the jargon is a "key function"... Oops! ;) > I'm sure it would make even more sense if you wrote it this way: > hand = sorted(cards, by="suit") > That's how SQL works - you just name the column that you want to order > the results by. But if you think "by" is a better keyword here, start > explaining why your ordering is done with an anonymous function, not > with an attribute name. If the logic is simple enough, you can just use a reference to the method from the class: hand = sorted(cards, by=Card.suit) # where Card is the class That's why I tend to use a more complex example. Otherwise the lambda isn't really justified. [Chris Angelico] > JFTR, I wouldn't implement a deck of cards this way. I don't implement decks of cards often, but in toy problems; I find just using 2-character strings works fine: Ace_of_spades = "As" Ten_of_hearts = "Th" etc... That can easily be extended by a named tuple initialized with unpacking: Card = namedtuple("Card", "rank suit") Ace_of_spades = Card(*"As") [Chris Angelico] > It implies that there is exactly one wild card, where many > decks of cards have at least two. I don't know of many games that have wild cards, but that's a simple remedy: hand = sorted(cards, by=value[card.suit] if card not in wilds else max_value with card) [Chris Angelico] > In English, "card is not wild" can > be interpreted as a membership check, but in Python, it is only an > identity check; you're capitalizing on false readability by using this > notation. I promise that wasn't my intent. Since both my proposed form and the lambda form use the same expression, it doesn't really tip the balance in favor of my argument. Also, most toy card problems I work with use a finite, immutable set of cards, so identity checking isn't *that* weird. On Tue, Aug 21, 2018 at 1:12 PM, Chris Angelico wrote: > On Wed, Aug 22, 2018 at 3:56 AM, Abe Dillon wrote: > > I've never hears someone say, "My child's name will be if it's a girl > Sally > > otherwise Billy." > > "My child's name depends on gender - if it's a girl, Sally, otherwise > Billy." Seems fine to me. You can always come up with something > awkward in a particular order, but it's not the order that made it > awkward. > > > Consider the alternate form: with (thought there are > > many alternative possibilities) > > > > hand = sorted(cards, key=lambda card: value[card.suit] if card is not > wild > > else max_value) > > > > hand = sorted(cards, by=value[card.suit] if card is not wild else > > max_value with card) > > > > # notice how unsurprising it is that the signature is "card" > > Okay, let's read that. > > hand = # we're assigning this to the name 'hand' > sorted( # calling the function named 'sorted' > cards, # positional argument, whatever's in the 'cards' variable > by= # keyword argument, what comes next is the 'by' argument > value[card.suit] # subscript 'value' with 'card.suit' > if card is not wild # yep > else max_value # so we have an alternative > with card # WAIT WAIT WAIT > > Once you get to 'with card', you have to go back and completely > reinterpret everything prior to that as a function. You have to scan > back and go "hang on, so exactly how much of this is getting wrapped > up into a function here?". Contrast the Python version: > > hand = sorted(cards, key=lambda card: value[card.suit] if card is not > wild else max_value) > > hand = # we're assigning this to the name 'hand' > sorted( # calling the function named 'sorted' > cards, # positional argument, whatever's in the 'cards' variable > key= # keyword argument, what comes next is the 'key' argument > lambda card: # a function taking one argument > value[card.suit] # subscript 'value' with 'card.suit' > if card is not wild # yep > else max_value # so we have an alternative > ) # and we're done > > The only part where you have to back up and change your interpretation > is when you hit "if card is not wild", which reads well enough to > justify the odd ordering. (JFTR, I wouldn't implement a deck of cards > this way. It implies that there is exactly one wild card, where many > decks of cards have at least two. In English, "card is not wild" can > be interpreted as a membership check, but in Python, it is only an > identity check; you're capitalizing on false readability by using this > notation.) > > > Oh wait... Did I accidentally replace "key" with "by"? Huh... It seems to > > make more sense even though the jargon is a "key function"... Oops! ;) > > I'm sure it would make even more sense if you wrote it this way: > > hand = sorted(cards, by="suit") > > That's how SQL works - you just name the column that you want to order > the results by. But if you think "by" is a better keyword here, start > explaining why your ordering is done with an anonymous function, not > with an attribute name. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 14:58:26 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 04:58:26 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 4:56 AM, Abe Dillon wrote: > [Chris Angelico] >> >> Okay, let's read that. >> hand = # we're assigning this to the name 'hand' >> sorted( # calling the function named 'sorted' >> cards, # positional argument, whatever's in the 'cards' variable >> by= # keyword argument, what comes next is the 'by' argument >> value[card.suit] # subscript 'value' with 'card.suit' >> if card is not wild # yep >> else max_value # so we have an alternative >> with card # WAIT WAIT WAIT >> Once you get to 'with card', you have to go back and completely >> reinterpret everything prior to that as a function. > > > The revelation that it's a function should come when you read the "by" or > "key". If you don't know what that parameter is, then that's where the "wait > wait wiat!" should happen. That right there is unacceptable. You should not have to know the destination to understand what something fundamentally is. You can't redefine language syntax based on the function being called. ChrisA From rosuav at gmail.com Tue Aug 21 15:06:46 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 05:06:46 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 4:56 AM, Abe Dillon wrote: > [Chris Angelico] >> >> In English, "card is not wild" can >> be interpreted as a membership check, but in Python, it is only an >> identity check; you're capitalizing on false readability by using this >> notation. > > > I promise that wasn't my intent. Since both my proposed form and the lambda > form use the same expression, > it doesn't really tip the balance in favor of my argument. Also, most toy > card problems I work with use a finite, > immutable set of cards, so identity checking isn't *that* weird. Fair enough. To be fair, I use decks of cards primarily for non-game usage (for instance, teaching data structures and algorithms - cards laid out on a table can represent a tree, heap, array, etc), and my decks of cards are artistic. A deck containing four suits of thirteen cards plus one joker would have 53 cards, which is a prime number; printing 54 cards lets you lay them out as 9 by 6 on a sheet, so it's easy to add a second joker. Some decks (I have an Alice in Wonderland themed deck) have *four* jokers. As such, the most logical way to do this would be as an attribute of the card. Its jokerness is as much a feature as the clubness of another card. You can pick up a physical card, look at it, and say "This is a joker"; you don't have to see if it's in a list of specific known jokers. hand = sorted(cards, by=value[card.suit] if not card.wild else max_value with card) Honestly, though, it'd usually be more interesting to sort by rank within suit. What you're doing here would group the cards by suit, ignoring their ranks; more useful would be: hand = sorted(cards, key=lambda card: (card.is_wild, card.suit, card.rank)) Much cleaner. No conditionals needed. ChrisA From kirillbalunov at gmail.com Tue Aug 21 16:02:30 2018 From: kirillbalunov at gmail.com (Kirill Balunov) Date: Tue, 21 Aug 2018 23:02:30 +0300 Subject: [Python-ideas] Jump to function as an an alternative to call function In-Reply-To: <20180820142137.GC22431@ando.pearwood.info> References: <20180816013458.GW22431@ando.pearwood.info> <20180816082843.GX22431@ando.pearwood.info> <20180820142137.GC22431@ando.pearwood.info> Message-ID: ??, 20 ???. 2018 ?. ? 17:23, Steven D'Aprano : > On Sun, Aug 19, 2018 at 06:18:56PM +0300, Kirill Balunov wrote: > [...] > [Kirill] > > Let me disagree with you. While CPython is only one of the > implementations > > of the Python language, it is the most common one and defacto is > considered > > as a standard. > > Not in this case. If CPython intended this to be the language behaviour, > it should specify that limitation instead of merely giving a doc warning > that changes "may not" affect the local variables. > > In fact, the warning in the docs is too strong. Modifying locals() > inside a class or module scope is allowed, and works fine. It is only > functions which is problematic. > > I think I was pretty clear, that I only spoke about `locals` behavior inside functions and all its derivatives. At least I tried :) Talking about class and module, as for me, modifying `locals()` inside a class or module scope is allowed but is far from the right way to do. The phrase `may not affect` is the worst phrase for deterministic system. Your program may work or may not work correctly depending on the underlying Python implementation, but you would not know about this because there will be no error and no warning. Good luck fixing such bugs. > > > Therefore, all the others, to be compliant, try to replicate > > all subtleties and features of the basic implementation - CPython. > > Implementations are expected to obey the documented behaviour (unless > given special dispensation to break the rules, which I think has > happened once or twice with MicroPython). For behaviour which isn't > dpcumented, it is true that implementations *often* try to copy CPython, > but that's not mandatory and there are exceptions. > > I think you are talking about recent discussion of MicroPython's `dict` implementation (that the order is not guaranteed?) It is a necessary trade off for them given their niche (if I understand correctly the explanation given by Paul Sokolovsky). > [...] > > Users of CPython frequently rely on CPython implementation details. Why > do you think Jython and IronPython users will be different? > > Hmm, what do you mean? It seems to me that everything happens the other way round. For example, recent attempts of numpy to make numpy more PyPy friendly. In fact, I do not know anyone who specifically rely on CPython implementation details in their production code. with kind regards, -gdg -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Tue Aug 21 16:24:09 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 15:24:09 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Chris Angelico] > That right there is unacceptable. You should not have to know the > destination to understand what something fundamentally is. You don't *have* to know what the parameter "key" is to know that (value[card.suit] ... with card) is a function. You can identify that it's a function just by reading the full expression. However, if you don't know what "key" is, then it'll cause far more confusion than the late declaration of the function's parameters. [Chris Angelico] > You can't redefine language syntax based on the function being called. That's not at all what I suggested. You were walking through my example from the reader's perspective. I was explaining how the reader will often have plenty of context about what they're reading before they get to the signature declaration. Whether it be because they know what the "key" parameter means or because they know "card" is undeclared or both. I never claimed the language syntax should be based on the function being called. func = value[card.suit] if card not in wilds else wild_value with card Works independent of the function being called. It's just not a common use case because it obviates the expressiveness of anonymous functions. You might as well use a "def" statement. The thing that makes callbacks difficult is not knowing how they're called. I tried to throw a little JavaScript into my curriculum once thinking "how bad can it be?" and suggested my students work on a project using the Force Directed Graph from D3.js . That was a HUGE mistake not because anonymous functions are confusing but because the example (at the time) had no documentation at all (like this one ) and used mysterious callbacks everywhere. The main documentation for D3.js is super difficult to navigate, when all you want to do is slightly modify one of the examples (use svg images for the nodes and have stats display "on mouse over"). If you don't know what "".join() does, then you're going to have trouble making sense of: def initials(person): return "".join(name[0] + "." for name in person.names if name) The late assignment of the name variable will NOT be your main source of confusion. If you do know what "".join() does, then it should take you much less context to realize you're reading a generator expression. By the time you read the yet-to-be-assigned "name" variable you should be tipped off. On Tue, Aug 21, 2018 at 1:58 PM, Chris Angelico wrote: > On Wed, Aug 22, 2018 at 4:56 AM, Abe Dillon wrote: > > [Chris Angelico] > >> > >> Okay, let's read that. > >> hand = # we're assigning this to the name 'hand' > >> sorted( # calling the function named 'sorted' > >> cards, # positional argument, whatever's in the 'cards' variable > >> by= # keyword argument, what comes next is the 'by' argument > >> value[card.suit] # subscript 'value' with 'card.suit' > >> if card is not wild # yep > >> else max_value # so we have an alternative > >> with card # WAIT WAIT WAIT > >> Once you get to 'with card', you have to go back and completely > >> reinterpret everything prior to that as a function. > > > > > > The revelation that it's a function should come when you read the "by" or > > "key". If you don't know what that parameter is, then that's where the > "wait > > wait wiat!" should happen. > > That right there is unacceptable. You should not have to know the > destination to understand what something fundamentally is. You can't > redefine language syntax based on the function being called. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 16:32:59 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 06:32:59 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 6:24 AM, Abe Dillon wrote: > [Chris Angelico] >> >> That right there is unacceptable. You should not have to know the >> destination to understand what something fundamentally is. > > > You don't *have* to know what the parameter "key" is to know that > (value[card.suit] ... with card) is a function. You can identify that it's a > function just by reading the full expression. However, if you don't know > what "key" is, then it'll cause far more confusion than the late declaration > of the function's parameters. > > [Chris Angelico] >> >> You can't redefine language syntax based on the function being called. > > > That's not at all what I suggested. You were walking through my example from > the reader's perspective. I was explaining how the reader will often have > plenty of context about what they're reading before they get to the > signature declaration. Whether it be because they know what the "key" > parameter means or because they know "card" is undeclared or both. I never > claimed the language syntax should be based on the function being called. > > func = value[card.suit] if card not in wilds else wild_value with card > > Works independent of the function being called. It's just not a common use > case because it obviates the expressiveness of anonymous functions. You > might as well use a "def" statement. Python's parser is *deliberately* incapable of backtracking this far in its definition of syntax. So if you want to have something where the first long slab of it is entirely acceptable as an expression, right up until you get to the "with" at the end, it's not going to work. You then said that it was the parameter "key" that told you that this would be a function, which is also unacceptable in Python syntax. So how do you intend to do this? And you still haven't done anything to show that this is actually better than "lambda card:" at the beginning. I'm done. ChrisA From abedillon at gmail.com Tue Aug 21 16:33:53 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 15:33:53 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Chris Angelico] > I use decks of cards primarily for non-game > usage (for instance, teaching data structures and algorithms - cards > laid out on a table can represent a tree, heap, array, etc) I do too. They're a great tool for visualizing and physically trying out different techniques. [Chris Angelico] > A deck containing four suits of thirteen > cards plus one joker would have 53 cards, which is a prime number; > printing 54 cards lets you lay them out as 9 by 6 on a sheet, so it's > easy to add a second joker. Some decks (I have an Alice in Wonderland > themed deck) have *four* jokers. > As such, the most logical way to do this would be as an attribute of > the card. In most cases I've seen wild cards used, it's a declaration about a certain card (e.g. "Eights are wild." or "The 2 of clubs is wild."). I've found that if you're trying to model a game like poker or Monopoly, it's tempting to add complexity to simple objects, but it can lead to problems later on. A card doesn't know if it's wild. That's a function of the game being played. An ace may be high or low. On Tue, Aug 21, 2018 at 2:06 PM, Chris Angelico wrote: > On Wed, Aug 22, 2018 at 4:56 AM, Abe Dillon wrote: > > [Chris Angelico] > >> > >> In English, "card is not wild" can > >> be interpreted as a membership check, but in Python, it is only an > >> identity check; you're capitalizing on false readability by using this > >> notation. > > > > > > I promise that wasn't my intent. Since both my proposed form and the > lambda > > form use the same expression, > > it doesn't really tip the balance in favor of my argument. Also, most toy > > card problems I work with use a finite, > > immutable set of cards, so identity checking isn't *that* weird. > > Fair enough. To be fair, I use decks of cards primarily for non-game > usage (for instance, teaching data structures and algorithms - cards > laid out on a table can represent a tree, heap, array, etc), and my > decks of cards are artistic. A deck containing four suits of thirteen > cards plus one joker would have 53 cards, which is a prime number; > printing 54 cards lets you lay them out as 9 by 6 on a sheet, so it's > easy to add a second joker. Some decks (I have an Alice in Wonderland > themed deck) have *four* jokers. > > As such, the most logical way to do this would be as an attribute of > the card. Its jokerness is as much a feature as the clubness of > another card. You can pick up a physical card, look at it, and say > "This is a joker"; you don't have to see if it's in a list of specific > known jokers. > > hand = sorted(cards, by=value[card.suit] if not card.wild else > max_value with card) > > Honestly, though, it'd usually be more interesting to sort by rank > within suit. What you're doing here would group the cards by suit, > ignoring their ranks; more useful would be: > > hand = sorted(cards, key=lambda card: (card.is_wild, card.suit, card.rank)) > > Much cleaner. No conditionals needed. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 16:42:04 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 06:42:04 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 6:33 AM, Abe Dillon wrote: > [Chris Angelico] >> >> I use decks of cards primarily for non-game >> usage (for instance, teaching data structures and algorithms - cards >> laid out on a table can represent a tree, heap, array, etc) > > > I do too. They're a great tool for visualizing and physically trying out > different techniques. > > [Chris Angelico] >> >> A deck containing four suits of thirteen >> cards plus one joker would have 53 cards, which is a prime number; >> printing 54 cards lets you lay them out as 9 by 6 on a sheet, so it's >> easy to add a second joker. Some decks (I have an Alice in Wonderland >> themed deck) have *four* jokers. >> As such, the most logical way to do this would be as an attribute of >> the card. > > > In most cases I've seen wild cards used, it's a declaration about a certain > card (e.g. "Eights are wild." > or "The 2 of clubs is wild."). I've found that if you're trying to model a > game like poker or Monopoly, it's tempting to add complexity to simple > objects, but it can lead to problems later on. A card doesn't know if it's > wild. That's a function of the game being played. An ace may be high or low. Well, okay. Then you should check if the card is a joker, rather than checking if it's wild. That means your sort function is "by suit, and within that by rank, but jokers are at the end" (ignoring wildness). That said, though... I've seen and used a Canasta deck of cards, which have game-specific information printed on them. Physical cards. So there's precedent for that! ChrisA From jfine2358 at gmail.com Tue Aug 21 16:51:38 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 21:51:38 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: Hi Abe First, I have reservations about the name lambda. But there's a lot of code out there that uses lambda, and I'd like that code to continue to run. You wrote: > func = value[card.suit] if card not in wilds else wild_value with card I thought I'd try this, and variants, in the Python interpreter. I got # An expression. It's valid syntax, get run-time error. >>> value[card.suit] if card not in wilds else wild_value NameError: name 'card' is not defined # An expression. It's valid syntax. Its value is a function. No run-time error. >>> lambda card: value[card.suit] if card not in wilds else wild_value at 0x7ff815e2bbf8> # If Python were enhanced, an valid expression whose value is a function. >>> value[card.suit] if card not in wilds else wild_value with card SyntaxError: invalid syntax My understanding is that you prefer >>> EXPRESSION with IDEN to >>> lambda IDEN: EXPRESSION How do you feel about this, as a means of defining an anonymous function? >>> with IDEN: EXPRESSION We can't adopt it, of course, because it's already valid syntax, but with semantics. >>> with wibble: ... wobble NameError: name 'wibble' is not defined Now for a trick question. Consider >>> fn = (lambda : EXPRESSION) This produces a function that has zero parameters. How would you write this, using 'with'. Would it be: >>> fn = (EXPRESSION with) I think this looks rather odd. -- Jonathan From jfine2358 at gmail.com Tue Aug 21 17:27:20 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 22:27:20 +0100 Subject: [Python-ideas] A simple proposal concerning lambda Message-ID: Here's what I call a simple proposal. Some people might find it outrageous. Today is not 1st April. BACKGROUND ============ Many Python users don't like the name lambda. But many Python users don't want any change here. This is true because there are millions of Python users, and even 100 is many. And it's hard to introduce a new keyword, which might break existing code. (And perhaps even worse, break the community.) https://wiki.python.org/moin/LocalUserGroups > There about 1,637 Python user groups worldwide in almost 191 cities, 37 countries and over 860,333 members. SOME VALID PYTHON ================== Here's some valid Python, defining two functions fn and gn, that are virtually identical. >>> def fn(a, b=2, c=3): ... return a ** b / c >>> fn >>> gn = lambda a, b=2, c=3: a ** b / c >>> gn at 0x7ff815e2bbf8> Notice that fn and gn have the same type, and differ by name. >>> type(fn), type(gn) (, ) >>> fn.__qualname__, gn.__qualname__ ('fn', '') And that we can modify the display name of fn and gn. >>> fn.__qualname__ = 'my_fn' >>> fn >>> gn.__qualname__ = 'my_gn' >>> gn MY SIMPLE PROPOSAL ==================== Here is my simple proposal. Enhance Python to allow >>> hn = def a, b=2, c=3: a ** b / c >>> hn >>> hn.__qualname__ '' MIGRATION ========== Migration of code would require only a keyword substitution of 'lambda' by 'def'. And in the docs 1. Note that 'def' can mean 'define' (the current use), and also 'defer' (evaluation of an expression). 2. In the first case, we have a *named function*. In the second case, we have an *expression function*. This idea came to me while writing: https://mail.python.org/pipermail/python-ideas/2018-August/052880.html -- Jonathan From greg.ewing at canterbury.ac.nz Tue Aug 21 17:53:45 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Wed, 22 Aug 2018 09:53:45 +1200 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> Message-ID: <5B7C89E9.6090600@canterbury.ac.nz> Jonathan Fine wrote: > Matlab says: "Here, copy paste this and it'll work". > > To the point that the workspace is designed to automatically strip >>> > from any copy and pasted commands. Maybe this is something Python's REPL should do? -- Greg From abedillon at gmail.com Tue Aug 21 18:02:07 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 17:02:07 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Jonathan Fine] > I have reservations about the name lambda. But there's a lot of > code out there that uses lambda, and I'd like that code to continue to > run. Yes. I'm under no delusion that lambda will be replaced any time soon. Nor do I believe any alternative I suggest will be enough of an improvement to warrant breaking the "there should be one and only one obvious way to do something rule". So I don't expect this conversation to lead to any change to the language, I just think my case that it's sub-optimal might inform future design decisions. Though it doesn't look like anyone finds it especially convincing. [Jonathan Fine] > My understanding is that you prefer > >>> EXPRESSION with IDEN > to > >>> lambda IDEN: EXPRESSION Correct. My argument is two fold: 1) the name "lambda" is needlessly esoteric. 2) the format of lambdas is "backwards" I tried to focus on the name gripe in this thread because trying to explain both at the same time caused confusion. However, Stephen Turnbull's and (more so) Steven D'Aprano's comments made the format argument semi-relevant and I can't help getting on that soap-box... [Jonathan Fine] > How do you feel about this, as a means of defining an anonymous function? > >>> with IDEN: EXPRESSION I think it's better than lambda. I can't decide if I like it more than: >>> def IDEN: EXPRESSION Because def is more clearly connected to function declaration and i'm somewhat sympathetic to the idea of expressionizing "with"-statements. The only reason I don't prefer: >>> EXPRESSION def IDEN to >>> EXPRESSION with IDEN Is that it looks weird to me. It just doesn't seem right. [Jonathan Fine] > Now for a trick question. Consider > >>> fn = (lambda : EXPRESSION) > This produces a function that has zero parameters. > How would you write this, using 'with'. Would it be: > >>> fn = (EXPRESSION with) > I think this looks rather odd. That's a good point. I hadn't considered that. There are several possible formats that put the expression before the signature definition. The specific form isn't quite as interesting to me. I would even prefer something like: >>> def (EXPRESSION [ SIG]) Mostly because "def" could then have a double meaning: "define" and "deferred expression". I think that's kinda neat. My problem with putting the signature first is that it usually amounts to noisy preamble that gets in the way of the important code. In pseudo code you'd often write: >>> hand = sorted(cards, by=card.suit) But obviously the compiler doesn't know what "card" is since it's never declared, so we write: >>> hand = sorted(cards, by=lambda card: card.suit) Notice that the information that's important to the reader: the expression, is pushed behind information the computer needs but the reader probably doesn't care about. My claim is that in most cases, the signature is more noise than signal, so it should come after the expression. A function passed as a callback, key-function, mapper, reducer, filter, event handler, etc. has a mostly pre-defined call signature. In most other cases, you're better off using a named function. Thanks for your input! On Tue, Aug 21, 2018 at 3:51 PM, Jonathan Fine wrote: > Hi Abe > > First, I have reservations about the name lambda. But there's a lot of > code out there that uses lambda, and I'd like that code to continue to > run. > > You wrote: > > func = value[card.suit] if card not in wilds else wild_value with card > > I thought I'd try this, and variants, in the Python interpreter. I got > > # An expression. It's valid syntax, get run-time error. > >>> value[card.suit] if card not in wilds else wild_value > NameError: name 'card' is not defined > > # An expression. It's valid syntax. Its value is a function. No run-time > error. > >>> lambda card: value[card.suit] if card not in wilds else wild_value > at 0x7ff815e2bbf8> > > # If Python were enhanced, an valid expression whose value is a function. > >>> value[card.suit] if card not in wilds else wild_value with card > SyntaxError: invalid syntax > > My understanding is that you prefer > >>> EXPRESSION with IDEN > to > >>> lambda IDEN: EXPRESSION > > How do you feel about this, as a means of defining an anonymous function? > >>> with IDEN: EXPRESSION > > We can't adopt it, of course, because it's already valid syntax, but > with semantics. > > >>> with wibble: > ... wobble > NameError: name 'wibble' is not defined > > Now for a trick question. Consider > >>> fn = (lambda : EXPRESSION) > This produces a function that has zero parameters. > > How would you write this, using 'with'. Would it be: > >>> fn = (EXPRESSION with) > I think this looks rather odd. > > -- > Jonathan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Tue Aug 21 18:07:18 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 21 Aug 2018 23:07:18 +0100 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: <5B7C89E9.6090600@canterbury.ac.nz> References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> Message-ID: Hi Greg You (and a reddit user) wrote: >> Matlab says: "Here, copy paste this and it'll work". >> To the point that the workspace is designed to automatically strip >>> >> from any copy and pasted commands. > Maybe this is something Python's REPL should do? Good idea. Maybe this is something that you (or someone else) should raise on bugs.python.org? And I expect that then, they'll ask for it to be discussed on python-ideas. So what do we get from the bounce? Well, you (or someone else) would be keeping an eye on this. (Aside: I'd like to be the someone else, but I don't have the time.). -- Jonathan From abedillon at gmail.com Tue Aug 21 18:45:53 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 17:45:53 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Chris Angelico] > Python's parser is *deliberately* incapable of backtracking this far > in its definition of syntax. Can you explain how far the parser is capable of backtracking? It seems like with would require a similar amount of backtracking to ternary expressions: if else If the preceding expression is the same in both cases, then the parser needs to backtrack just as far when it finds an "if" as when it finds a "with". [Chris Angelico] > You then said that it was the parameter "key" that told you that > this would be a function, which is also unacceptable in Python syntax. That was *never* a statement about syntax. It was about the context clues a reader has, not the parser. The proposed syntax: with is an expression that evaluates to a function object regardless of any parameter or any function it might or might not be passed to. My argument is simply: Most cases where an anonymous function is more expressive than a named function are also cases where, *from the perspective of a human reading the code*, the signature is noisy preamble that gets in the way of the expression. In psuedo code, people tend to write things like: >>> hand = sorted(cards, by=card.suit) Obviously that wouldn't compile because the computer doesn't know what "card" is. However; >>> hand = sorted(cards, by=lambda card: card.suit) puts a bunch of noise that's mostly of interest to the computer in front of the expression that's of interest to the reader. There is precedent for late-variable-binding in Python expressions already (e.g. comprehensions), so it makes sense to me that the expression version of function declaration could also bind the signature after the main expression. The same logic follows for mappers, reducers, filters, callbacks, event-handlers, etc. [Chris Angelico] > So how do you intend to do this? I don't intend any of this to make its way into Python. It's a case study of expression design. It's interesting to me to explore such alternatives. It's fine to prod it and examine its flaws as Jonathan Fine has. [Chris Angelico] > And you still haven't done anything to show that this is actually > better than "lambda card:" I'm trying to, but I also have to answer all your misconceptions about the idea (like that the syntax is function or parameter-dependent). [Chris Angelico] > I'm done. OK. I'm sorry if I upset you. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 18:51:40 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 08:51:40 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 8:45 AM, Abe Dillon wrote: > [Chris Angelico] >> >> Python's parser is *deliberately* incapable of backtracking this far >> in its definition of syntax. > > > Can you explain how far the parser is capable of backtracking? > It seems like with would require a similar amount > of backtracking to ternary expressions: > > if else > > If the preceding expression is the same in both cases, then the parser needs > to backtrack just as far when it finds an "if" as when it finds a "with". I have to defer to someone who knows in more detail here, but the parser will look ahead one "token", whatever a token is. (Technically it doesn't backtrack, it looks ahead - same difference.) In order for the ternary-if to work, the expression before the if has to be of a more restricted type than just "any expression" (for instance, you can't put a lambda function there, unless you parenthesize it). But I'm not fluent in all the details, and I definitely am not comfortable citing exactly what the limits are. The last time I tried editing the grammar, weird things happened. ChrisA From abedillon at gmail.com Tue Aug 21 19:32:54 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 18:32:54 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: [Chris Angelico] > I have to defer to someone who knows in more detail here, but the > parser will look ahead one "token", whatever a token is. (Technically > it doesn't backtrack, it looks ahead - same difference.) In order for > the ternary-if to work, the expression before the if has to be of a > more restricted type than just "any expression" (for instance, you > can't put a lambda function there, unless you parenthesize it). Interesting. I really need to try delving into the nuts and bolts of Python. I didn't know that about ternary expressions. I don't know if you saw my recent discussion with Jonathan Fine, but he brought up some good points too. -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Tue Aug 21 19:51:49 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 18:51:49 -0500 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: Message-ID: I'm trying to dig up past threads about alternatives to lambda because I would be astonished if "def" hadn't been considered and rejected for some reason. What I've found so far is this unreassuring post from Guido back in 2006 On Tue, Aug 21, 2018 at 4:27 PM, Jonathan Fine wrote: > Here's what I call a simple proposal. Some people might find it > outrageous. Today is not 1st April. > > > BACKGROUND > ============ > Many Python users don't like the name lambda. But many Python users > don't want any change here. This is true because there are millions of > Python users, and even 100 is many. And it's hard to introduce a new > keyword, which might break existing code. (And perhaps even worse, > break the community.) > > https://wiki.python.org/moin/LocalUserGroups > > There about 1,637 Python user groups worldwide in almost 191 cities, 37 > countries and over 860,333 members. > > > SOME VALID PYTHON > ================== > Here's some valid Python, defining two functions fn and gn, that are > virtually identical. > > >>> def fn(a, b=2, c=3): > ... return a ** b / c > >>> fn > > > >>> gn = lambda a, b=2, c=3: a ** b / c > >>> gn > at 0x7ff815e2bbf8> > > Notice that fn and gn have the same type, and differ by name. > > >>> type(fn), type(gn) > (, ) > >>> fn.__qualname__, gn.__qualname__ > ('fn', '') > > And that we can modify the display name of fn and gn. > > >>> fn.__qualname__ = 'my_fn' > >>> fn > > > >>> gn.__qualname__ = 'my_gn' > >>> gn > > > > MY SIMPLE PROPOSAL > ==================== > > Here is my simple proposal. Enhance Python to allow > > >>> hn = def a, b=2, c=3: a ** b / c > >>> hn > > >>> hn.__qualname__ > '' > > MIGRATION > ========== > > Migration of code would require only a keyword substitution of > 'lambda' by 'def'. > > And in the docs > 1. Note that 'def' can mean 'define' (the current use), and also > 'defer' (evaluation of an expression). > 2. In the first case, we have a *named function*. In the second case, > we have an *expression function*. > > This idea came to me while writing: > https://mail.python.org/pipermail/python-ideas/2018-August/052880.html > > -- > Jonathan > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Tue Aug 21 20:25:41 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 22 Aug 2018 01:25:41 +0100 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: Message-ID: Hi Abe Summary: You've done good work here. I've skim read the 2006 discussion you found. You wrote: > I'm trying to dig up past threads about alternatives to lambda because I > would be astonished if "def" hadn't been considered and rejected for some > reason. What I've found so far is this unreassuring post from Guido back in > 2006 > [Python-Dev] Let's just *keep* lambda > https://mail.python.org/pipermail/python-dev/2006-February/060415.html This is an excellent piece of work. I'm most grateful. Here's what Guido said: > After so many attempts to come up with an alternative for lambda, > perhaps we should admit defeat. I've not had the time to follow the > most recent rounds, but I propose that we keep lambda, so as to stop > wasting everybody's talent and time on an impossible quest. I've quickly read through the posts that followed Guido's message, picked out the ones that interest me. Here's a list. > https://mail.python.org/pipermail/python-dev/2006-February/060487.html > https://mail.python.org/pipermail/python-dev/2006-February/060474.html > https://mail.python.org/pipermail/python-dev/2006-February/060471.html > https://mail.python.org/pipermail/python-dev/2006-February/060445.html > https://mail.python.org/pipermail/python-dev/2006-February/060435.html > https://mail.python.org/pipermail/python-dev/2006-February/060431.html > https://mail.python.org/pipermail/python-dev/2006-February/060470.html And one of the messages had a link to still live and excellent page > https://wiki.python.org/moin/AlternateLambdaSyntax This page lists over 100 suggestions, mostly variants. So far as I can see, my simple proposal isn't listed on that page. The page also says > **Definitely Desirable Features** [snip] > *More friendly to inexperienced users* [snip] > Compared to other Python keywords, 'lambda' is rather esoteric. > In the challenge for "farthest outside day-to-day English usage", > its closest competitor would probably be 'assert', as even 'def' > and 'elif' are just abbreviations for 'define' and 'else if'. Use of > simpler keywords may make deferred expressions appear less > intimidating than they seem with the current unusual keyword. The word 'deferred' appears 7 times on the page. It also appears in the python-dev messages. If someone with more time and less bias then myself were to summarise this discussion from 2006, I'd be most grateful, and they'd have material for a great blog post. Finally, many thanks to Abe for finding this gem, and countless people's hard work in keeping it alive to be found. Backwards compatibility is there for a reason. -- Jonathan From python at mrabarnett.plus.com Tue Aug 21 21:24:35 2018 From: python at mrabarnett.plus.com (MRAB) Date: Wed, 22 Aug 2018 02:24:35 +0100 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: Message-ID: <93da1bb6-3d70-8e9d-d25f-eabdbdcd027b@mrabarnett.plus.com> On 2018-08-22 01:25, Jonathan Fine wrote: > Hi Abe > > Summary: You've done good work here. I've skim read the 2006 > discussion you found. > > You wrote: > >> I'm trying to dig up past threads about alternatives to lambda because I >> would be astonished if "def" hadn't been considered and rejected for some >> reason. What I've found so far is this unreassuring post from Guido back in >> 2006 > >> [Python-Dev] Let's just *keep* lambda >> https://mail.python.org/pipermail/python-dev/2006-February/060415.html > > This is an excellent piece of work. I'm most grateful. Here's what Guido said: > >> After so many attempts to come up with an alternative for lambda, >> perhaps we should admit defeat. I've not had the time to follow the >> most recent rounds, but I propose that we keep lambda, so as to stop >> wasting everybody's talent and time on an impossible quest. > > I've quickly read through the posts that followed Guido's message, > picked out the ones that interest me. Here's a list. > >> https://mail.python.org/pipermail/python-dev/2006-February/060487.html >> https://mail.python.org/pipermail/python-dev/2006-February/060474.html >> https://mail.python.org/pipermail/python-dev/2006-February/060471.html >> https://mail.python.org/pipermail/python-dev/2006-February/060445.html >> https://mail.python.org/pipermail/python-dev/2006-February/060435.html >> https://mail.python.org/pipermail/python-dev/2006-February/060431.html >> https://mail.python.org/pipermail/python-dev/2006-February/060470.html > > And one of the messages had a link to still live and excellent page > >> https://wiki.python.org/moin/AlternateLambdaSyntax > > This page lists over 100 suggestions, mostly variants. So far as I can > see, my simple proposal isn't listed on that page. The page also says > Hmm. That lists: def (a, b, c): return f(a) + o(b) - o(c) and: def (a, b, c) = f(a) + o(b) - o(c) but not: def (a, b, c): f(a) + o(b) - o(c) >> **Definitely Desirable Features** > [snip] >> *More friendly to inexperienced users* > [snip] >> Compared to other Python keywords, 'lambda' is rather esoteric. >> In the challenge for "farthest outside day-to-day English usage", >> its closest competitor would probably be 'assert', as even 'def' >> and 'elif' are just abbreviations for 'define' and 'else if'. Use of >> simpler keywords may make deferred expressions appear less >> intimidating than they seem with the current unusual keyword. > > The word 'deferred' appears 7 times on the page. It also appears in > the python-dev messages. > > If someone with more time and less bias then myself were to summarise > this discussion from 2006, I'd be most grateful, and they'd have > material for a great blog post. > > Finally, many thanks to Abe for finding this gem, and countless > people's hard work in keeping it alive to be found. Backwards > compatibility is there for a reason. > From elazarg at gmail.com Tue Aug 21 21:38:29 2018 From: elazarg at gmail.com (Elazar) Date: Tue, 21 Aug 2018 21:38:29 -0400 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: <93da1bb6-3d70-8e9d-d25f-eabdbdcd027b@mrabarnett.plus.com> References: <93da1bb6-3d70-8e9d-d25f-eabdbdcd027b@mrabarnett.plus.com> Message-ID: I don't think this change makes sense, but if it's done, there should be another change, with actual implications: There is no way to express the types of the parameters in a lambda - `lambda x: int : x` is obviously a syntax error. Replacing the colon with a different symbol, such as "=>" will make this possible: def x => x def x: int => x def x: int -> int => x It will also give one less meaning to the colon. Elazar On Tue, Aug 21, 2018 at 6:28 PM MRAB wrote: > On 2018-08-22 01:25, Jonathan Fine wrote: > > Hi Abe > > > > Summary: You've done good work here. I've skim read the 2006 > > discussion you found. > > > > You wrote: > > > >> I'm trying to dig up past threads about alternatives to lambda because I > >> would be astonished if "def" hadn't been considered and rejected for > some > >> reason. What I've found so far is this unreassuring post from Guido > back in > >> 2006 > > > >> [Python-Dev] Let's just *keep* lambda > >> https://mail.python.org/pipermail/python-dev/2006-February/060415.html > > > > This is an excellent piece of work. I'm most grateful. Here's what Guido > said: > > > >> After so many attempts to come up with an alternative for lambda, > >> perhaps we should admit defeat. I've not had the time to follow the > >> most recent rounds, but I propose that we keep lambda, so as to stop > >> wasting everybody's talent and time on an impossible quest. > > > > I've quickly read through the posts that followed Guido's message, > > picked out the ones that interest me. Here's a list. > > > >> https://mail.python.org/pipermail/python-dev/2006-February/060487.html > >> https://mail.python.org/pipermail/python-dev/2006-February/060474.html > >> https://mail.python.org/pipermail/python-dev/2006-February/060471.html > >> https://mail.python.org/pipermail/python-dev/2006-February/060445.html > >> https://mail.python.org/pipermail/python-dev/2006-February/060435.html > >> https://mail.python.org/pipermail/python-dev/2006-February/060431.html > >> https://mail.python.org/pipermail/python-dev/2006-February/060470.html > > > > And one of the messages had a link to still live and excellent page > > > >> https://wiki.python.org/moin/AlternateLambdaSyntax > > > > This page lists over 100 suggestions, mostly variants. So far as I can > > see, my simple proposal isn't listed on that page. The page also says > > > Hmm. > > That lists: > > def (a, b, c): return f(a) + o(b) - o(c) > > and: > > def (a, b, c) = f(a) + o(b) - o(c) > > but not: > > def (a, b, c): f(a) + o(b) - o(c) > > >> **Definitely Desirable Features** > > [snip] > >> *More friendly to inexperienced users* > > [snip] > >> Compared to other Python keywords, 'lambda' is rather esoteric. > >> In the challenge for "farthest outside day-to-day English usage", > >> its closest competitor would probably be 'assert', as even 'def' > >> and 'elif' are just abbreviations for 'define' and 'else if'. Use of > >> simpler keywords may make deferred expressions appear less > >> intimidating than they seem with the current unusual keyword. > > > > The word 'deferred' appears 7 times on the page. It also appears in > > the python-dev messages. > > > > If someone with more time and less bias then myself were to summarise > > this discussion from 2006, I'd be most grateful, and they'd have > > material for a great blog post. > > > > Finally, many thanks to Abe for finding this gem, and countless > > people's hard work in keeping it alive to be found. Backwards > > compatibility is there for a reason. > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Tue Aug 21 21:55:03 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 22 Aug 2018 11:55:03 +1000 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: Message-ID: <20180822015502.GE24160@ando.pearwood.info> On Tue, Aug 21, 2018 at 10:27:20PM +0100, Jonathan Fine wrote: > Here is my simple proposal. Enhance Python to allow > > >>> hn = def a, b=2, c=3: a ** b / c Enhancements ought to allow us to write new code that we couldn't do before, or open up new kinds of algorithms that weren't easy or possible before. This is a mere cosmetic change, replacing a perfectly valid keyword with one which clashes with an existing keyword in what I consider to be an ugly way. While we're at it, perhaps we ought to replace: - "else" with "otherwise" ("else" is a weird word, outside of programming we hardly ever use it without a leading "or") - "import" with "load" (shorter) - "for" with "repeat with" (I've always found it awkward that the word "for" sounds like an number) - "raise" with "throw" - and most importantly, "def" with "fun", which will have the advantage of making Python programming more fun! Admittedly these run into backwards-compatibility issues, which your suggestion does not. But if we're going to break people's code by changing keywords, let's do it properly! *wink* Changing the public API of a language, its keywords, is not something to be done lightly. The consequences of such a change can include: - breaking backwards compatibility; - code churn (people have to "fix their code" even if it wasn't broken); - confusion ("what's the difference between def anonymous functions and lambda anonymous functions?"); - more to learn during the transition (sometimes code uses lambda, sometimes def, so you need to know both) - more documentation explaining why the name is only sometimes needed; - more unit tests etc to ensure the feature works correctly, e.g. to test for the syntax error when people use def unanonymously when they should use it anonymously: map(def func(a, b, c): a+b-c, zip(seq1, seq2, seq3)) Those costs are real and should only be paid when the benefits outweigh the costs. In this specific case, there's also a very real cost: - you will *seriously annoy and frustrate* those of us who like lambda and dislike the look of "def" inside expressions; - while only *slightly pleasing* those who have already learned lambda but don't like it. They've already learned the existing word, now they have to unlearn it. And the corresponding benefit is tiny: - The conceptual difficulties with lambda is not the word but the concept of anonymous functions as first class values; that doesn't change, so no benefit there. - One less keyword in the language (after the transition period). - Two fewer keystrokes. - but "def" is still jargon that needs to be learned. (Does it mean defeat, defame, defer, defend, or that thing bears do in the woods? To a non-English speaker, memorising "def" = "define" is no less obscure than memorising "lam" = "lambda" would be for English speakers.) I don't think this cosmetic change comes even close to the break-even point of costs versus benefits. Maybe if we were designing Python from scratch today, there would be a good argument to be made for using def in both the statement and expression form, but even that's not a sure thing. Changing it *now* is more costly with less benefit. To give an example of a problematic keyword where changing it is not just cosmetic, for many years, consider the "for...else" statement. It seems to be saying: run the for loop *or else* run this block but that's not what it actually means. But even if we had consensus that the "else" keyword should be changed (to what? "then" is my suggestion), the benefit is probably too small to disrupt the Python ecosystem by actually making that change. By the way, I'll also point out that the way you have demonstrated the use of anonymous functions is considered a (mild) abuse of syntax. Your example: # reverting back to lambda for the moment hn = lambda a, b=2, c=3: a ** b / c ought to be written as: def hn(a, b=2, c=3): return a ** b / c which ensures that hn has a nice name for debugging. Lambdas ought to be limited to in-place uses, as part of a larger expression and not just an assignment, probably 99% of the time. Hence: results = map(lambda a, b=2, c=3: a ** b / c, sequence) widget.register(callback=lambda: spam.eggs()) are reasonable examples of how one might find lambdas in the wild. Replacing the keyword: results = map(def a, b=2, c=3: a ** b / c, sequence) widget.register(callback=def: spam.eggs()) Doesn't look so attractive now, I wager. Using "def" inside an expression looks strange. And this looks outright disturbing: def method(self, arg, callback=def arg: arg+1): pass -- Steve From turnbull.stephen.fw at u.tsukuba.ac.jp Tue Aug 21 22:04:22 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Wed, 22 Aug 2018 11:04:22 +0900 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: Message-ID: <23420.50342.431846.485657@turnbull.sk.tsukuba.ac.jp> Abe Dillon writes: > What I've found so far is this unreassuring post from Guido back in > 2006 > IIRC, early drafts of PEP 3000 (the PEP that was the planning document for the Python 3 project) removed lambda altogether. However there was strong opposition, so we ended up keeping lambda. Some of those discussions morphed to ideas about "improving" lambda. So you may find discussions of lambda in threads titled "PEP 3000" or "Python 3000". -- Associate Professor Division of Policy and Planning Science http://turnbull.sk.tsukuba.ac.jp/ Faculty of Systems and Information Email: turnbull at sk.tsukuba.ac.jp University of Tsukuba Tel: 029-853-5175 Tennodai 1-1-1, Tsukuba 305-8573 JAPAN From abedillon at gmail.com Tue Aug 21 22:10:21 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 21:10:21 -0500 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: Message-ID: [Jonathan Fine] > one of the messages had a link to still live and excellent page > > https://wiki.python.org/moin/AlternateLambdaSyntax > This page lists over 100 suggestions, mostly variants. So far as I can > see, my simple proposal isn't listed on that page. The page also says Awesome! Unfortunately the links to conversations seem to all be broken! Most of the links are from December 2004, so I pulled up the discussion for that month and searched "lambda" I was able to find what I believe is reference [1]: https://mail.python.org/pipermail/python-list/2004-December/264515.html It looks like the post numbers got mangled... Anyway, it looks like that page covers December 2004-June 2005, I found a few nuggets of opposition: https://mail.python.org/pipermail/python-list/2004-December/247348.html https://mail.python.org/pipermail/python-list/2004-December/273038.html I sort-of understand the opposition to multi-line anonymous functions, but I think the Terry Reedy (in the second link) is a bit too dismissive of the concept of anonymous functions. I don't work with user-interfaces a lot, but when I do; I can see why UI coders use anonymous functions so much. Defining a function in a statement can be far less expressive and far more noisy than in an expression. It's like: I'll tell you my solution, but first let me shave this Yak here. You're defining often one-off functions before describing what you're going to use it for. It's only after you actually pass them to an event-watcher that the context of their logic is clear. For instance: >>> def handler(event): # First, let me tell you about a function ... # It's a 1-off with a throw-away name ... return result # You'll see what I need it for later... ... >>> ui_element.on_mouseover(handler) vs. >>> # lack of noisy preamble to your code >>> ui_element.on_mouseover( with event) The anonymous function is given meaning by virtue of the context in-which it's defined. -------------- next part -------------- An HTML attachment was scrubbed... URL: From python at mrabarnett.plus.com Tue Aug 21 22:12:09 2018 From: python at mrabarnett.plus.com (MRAB) Date: Wed, 22 Aug 2018 03:12:09 +0100 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <93da1bb6-3d70-8e9d-d25f-eabdbdcd027b@mrabarnett.plus.com> Message-ID: <2368fb00-c20f-b9f5-1b45-0987e2e288d3@mrabarnett.plus.com> On 2018-08-22 02:38, Elazar wrote: > I don't think this change makes sense, but if it's done, there should be > another change, with actual implications: > There is no way to express the types of the parameters in a lambda - > `lambda x: int : x` is obviously a syntax error. Replacing the colon > with a different symbol, such as "=>" will make this possible: > > ? ? def x => x > ? ? def x: int => x > ? ? def x: int -> int => x > > It will also give one less meaning to the colon. > The examples I showed had parens, so your examples could be: def (x): x def (x: int): x def (x: int) -> int: x > > On Tue, Aug 21, 2018 at 6:28 PM MRAB > wrote: > > On 2018-08-22 01:25, Jonathan Fine wrote: > > Hi Abe > > > > Summary: You've done good work here. I've skim read the 2006 > > discussion you found. > > > > You wrote: > > > >> I'm trying to dig up past threads about alternatives to lambda > because I > >> would be astonished if "def" hadn't been considered and rejected > for some > >> reason. What I've found so far is this unreassuring? post from > Guido back in > >> 2006 > > > >> [Python-Dev] Let's just *keep* lambda > >> > https://mail.python.org/pipermail/python-dev/2006-February/060415.html > > > > This is an excellent piece of work. I'm most grateful. Here's > what Guido said: > > > >> After so many attempts to come up with an alternative for lambda, > >> perhaps we should admit defeat. I've not had the time to follow the > >> most recent rounds, but I propose that we keep lambda, so as to stop > >> wasting everybody's talent and time on an impossible quest. > > > > I've quickly read through the posts that followed Guido's message, > > picked out the ones that interest me. Here's a list. > > > >> > https://mail.python.org/pipermail/python-dev/2006-February/060487.html > >> > https://mail.python.org/pipermail/python-dev/2006-February/060474.html > >> > https://mail.python.org/pipermail/python-dev/2006-February/060471.html > >> > https://mail.python.org/pipermail/python-dev/2006-February/060445.html > >> > https://mail.python.org/pipermail/python-dev/2006-February/060435.html > >> > https://mail.python.org/pipermail/python-dev/2006-February/060431.html > >> > https://mail.python.org/pipermail/python-dev/2006-February/060470.html > > > > And one of the messages had a link to still live and excellent page > > > >> https://wiki.python.org/moin/AlternateLambdaSyntax > > > > This page lists over 100 suggestions, mostly variants. So far as > I can > > see, my simple proposal isn't listed on that page. The page also says > > > Hmm. > > That lists: > > ? ? ?def (a, b, c): return f(a) + o(b) - o(c) > > and: > > ? ? ?def (a, b, c) = f(a) + o(b) - o(c) > > but not: > > ? ? ?def (a, b, c): f(a) + o(b) - o(c) > > >> **Definitely Desirable Features** > > [snip] > >> *More friendly to inexperienced users* > > [snip] > >> Compared to other Python keywords, 'lambda' is rather esoteric. > >> In the challenge for "farthest outside day-to-day English usage", > >> its closest competitor would probably be 'assert', as even 'def' > >> and 'elif' are just abbreviations for 'define' and 'else if'. Use of > >> simpler keywords may make deferred expressions appear less > >> intimidating than they seem with the current unusual keyword. > > > > The word 'deferred' appears 7 times on the page. It also appears in > > the python-dev messages. > > > > If someone with more time and less bias then myself were to summarise > > this discussion from 2006, I'd be most grateful, and they'd have > > material for a great blog post. > > > > Finally, many thanks to Abe for finding this gem, and countless > > people's hard work in keeping it alive to be found. Backwards > > compatibility is there for a reason. > > From abedillon at gmail.com Tue Aug 21 22:48:54 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 21:48:54 -0500 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: <20180822015502.GE24160@ando.pearwood.info> References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: [Steven D'Aprano] > most importantly, "def" with "fun", which will have the > advantage of making Python programming more fun! I'm sold. Make the change and SHIP IT! No need for committee approval. [Steven D'Aprano] > If we're going to break people's code by > changing keywords, let's do it properly! *wink* I'm not backing this proposal, but I am curious what the proposal could break. [Steven D'Aprano] > - Two fewer keystrokes. THREE!!! [Steven D'Aprano] > - but "def" is still jargon that needs to be learned. It already has to be learned and it's already associated with function declaration. [Steven D'Aprano] > I don't think this cosmetic change comes even close to the break-even > point of costs versus benefits. Maybe if we were designing Python from > scratch today, there would be a good argument to be made for using def > in both the statement and expression form, but even that's not a sure > thing. Changing it *now* is more costly with less benefit. Yeah, that's pretty much my take on the matter. That ship sailed way back when Py3k was finalized. [Steven D'Aprano] > To give an example of a problematic keyword where changing it is not > just cosmetic, for many years, consider the "for...else" statement. It > seems to be saying: > run the for loop > *or else* run this block > but that's not what it actually means. But even if we had consensus that > the "else" keyword should be changed (to what? "then" is my suggestion), > the benefit is probably too small to disrupt the Python ecosystem by > actually making that change. for-finished? for-done? for-stopped? # referencing StopIteration for-anything_but_else? [Steven D'Aprano] > > By the way, I'll also point out that the way you have demonstrated the > use of anonymous functions is considered a (mild) abuse of syntax. Your > example: > # reverting back to lambda for the moment > hn = lambda a, b=2, c=3: a ** b / c > ought to be written as: > def hn(a, b=2, c=3): return a ** b / c Oh, come-on; D'Aprano! That was just to demonstrate properties of the resulting object. It's not meant to be production code. [Steven D'Aprano] > Replacing the keyword: > results = map(def a, b=2, c=3: a ** b / c, sequence) > widget.register(callback=def: spam.eggs()) > Doesn't look so attractive now, I wager. Using "def" inside an > expression looks strange. And this looks outright disturbing: > def method(self, arg, callback=def arg: arg+1): > pass Eh... I think they look fine. Which is worse: def method(self, arg, callback=def arg: arg+1): pass or lambda arg, callback=lambda arg: arg+1: None because the second one makes me go cross-eyed... On Tue, Aug 21, 2018 at 8:55 PM, Steven D'Aprano wrote: > On Tue, Aug 21, 2018 at 10:27:20PM +0100, Jonathan Fine wrote: > > > Here is my simple proposal. Enhance Python to allow > > > > >>> hn = def a, b=2, c=3: a ** b / c > > Enhancements ought to allow us to write new code that we couldn't do > before, or open up new kinds of algorithms that weren't easy or possible > before. > > This is a mere cosmetic change, replacing a perfectly valid keyword with > one which clashes with an existing keyword in what I consider to be an > ugly way. > > While we're at it, perhaps we ought to replace: > > - "else" with "otherwise" > ("else" is a weird word, outside of programming we hardly ever use it > without a leading "or") > > - "import" with "load" (shorter) > > - "for" with "repeat with" > (I've always found it awkward that the word "for" sounds like an number) > > - "raise" with "throw" > > - and most importantly, "def" with "fun", which will have the > advantage of making Python programming more fun! > > Admittedly these run into backwards-compatibility issues, which your > suggestion does not. But if we're going to break people's code by > changing keywords, let's do it properly! *wink* > > Changing the public API of a language, its keywords, is not something to > be done lightly. The consequences of such a change can include: > > - breaking backwards compatibility; > > - code churn (people have to "fix their code" even if it wasn't broken); > > - confusion ("what's the difference between def anonymous functions > and lambda anonymous functions?"); > > - more to learn during the transition (sometimes code uses lambda, > sometimes def, so you need to know both) > > - more documentation explaining why the name is only sometimes needed; > > - more unit tests etc to ensure the feature works correctly, e.g. to > test for the syntax error when people use def unanonymously when > they should use it anonymously: > > map(def func(a, b, c): a+b-c, zip(seq1, seq2, seq3)) > > > Those costs are real and should only be paid when the benefits outweigh > the costs. In this specific case, there's also a very real cost: > > - you will *seriously annoy and frustrate* those of us who like lambda > and dislike the look of "def" inside expressions; > > - while only *slightly pleasing* those who have already learned lambda > but don't like it. They've already learned the existing word, now they > have to unlearn it. > > And the corresponding benefit is tiny: > > - The conceptual difficulties with lambda is not the word but the > concept of anonymous functions as first class values; that doesn't > change, so no benefit there. > > - One less keyword in the language (after the transition period). > > - Two fewer keystrokes. > > - but "def" is still jargon that needs to be learned. > > (Does it mean defeat, defame, defer, defend, or that thing bears do in > the woods? To a non-English speaker, memorising "def" = "define" is no > less obscure than memorising "lam" = "lambda" would be for English > speakers.) > > I don't think this cosmetic change comes even close to the break-even > point of costs versus benefits. Maybe if we were designing Python from > scratch today, there would be a good argument to be made for using def > in both the statement and expression form, but even that's not a sure > thing. Changing it *now* is more costly with less benefit. > > To give an example of a problematic keyword where changing it is not > just cosmetic, for many years, consider the "for...else" statement. It > seems to be saying: > > run the for loop > > *or else* run this block > > but that's not what it actually means. But even if we had consensus that > the "else" keyword should be changed (to what? "then" is my suggestion), > the benefit is probably too small to disrupt the Python ecosystem by > actually making that change. > > By the way, I'll also point out that the way you have demonstrated the > use of anonymous functions is considered a (mild) abuse of syntax. Your > example: > > # reverting back to lambda for the moment > hn = lambda a, b=2, c=3: a ** b / c > > ought to be written as: > > def hn(a, b=2, c=3): return a ** b / c > > which ensures that hn has a nice name for debugging. Lambdas ought to be > limited to in-place uses, as part of a larger expression and not just an > assignment, probably 99% of the time. Hence: > > results = map(lambda a, b=2, c=3: a ** b / c, sequence) > > widget.register(callback=lambda: spam.eggs()) > > are reasonable examples of how one might find lambdas in the wild. > Replacing the keyword: > > results = map(def a, b=2, c=3: a ** b / c, sequence) > > widget.register(callback=def: spam.eggs()) > > Doesn't look so attractive now, I wager. Using "def" inside an > expression looks strange. And this looks outright disturbing: > > def method(self, arg, callback=def arg: arg+1): > pass > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 22:52:29 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 12:52:29 +1000 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 12:48 PM, Abe Dillon wrote: > [Steven D'Aprano] >> >> Replacing the keyword: >> results = map(def a, b=2, c=3: a ** b / c, sequence) >> widget.register(callback=def: spam.eggs()) >> Doesn't look so attractive now, I wager. Using "def" inside an >> expression looks strange. And this looks outright disturbing: >> def method(self, arg, callback=def arg: arg+1): >> pass > > > Eh... I think they look fine. Which is worse: > > def method(self, arg, callback=def arg: arg+1): > pass > > or > > lambda arg, callback=lambda arg: arg+1: None > > because the second one makes me go cross-eyed... If you have a use-case for a lambda function that takes a callback and has a default value for that callback, please submit it to The Daily WTF. In Steve's example, the main function was created with a statement. ChrisA From abedillon at gmail.com Tue Aug 21 22:57:51 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 21:57:51 -0500 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: [Chris Angelico] > If you have a use-case for a lambda function that takes a callback and > has a default value for that callback, please submit it to The Daily > WTF. In Steve's example, the main function was created with a > statement. Fair enough, but I still think D'Aprano may have engineered his example to be particularly unreadable. Why would you use 'arg' for both the argument to the method and the callback! That's at least a little WTF. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Tue Aug 21 23:09:45 2018 From: rosuav at gmail.com (Chris Angelico) Date: Wed, 22 Aug 2018 13:09:45 +1000 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018 at 12:57 PM, Abe Dillon wrote: > [Chris Angelico] >> >> If you have a use-case for a lambda function that takes a callback and >> has a default value for that callback, please submit it to The Daily >> WTF. In Steve's example, the main function was created with a >> statement. > > > Fair enough, but I still think D'Aprano may have engineered his example to > be particularly unreadable. > Why would you use 'arg' for both the argument to the method and the > callback! That's at least a little WTF. True, but hardly significant. The one inside lambda is local to it. Though... it's insignificant when the function header precedes the expression/body. With the proposal to move the header to the end, that might become problematic, which makes it yet another cost to the proposal. ChrisA From abedillon at gmail.com Tue Aug 21 23:21:34 2018 From: abedillon at gmail.com (Abe Dillon) Date: Tue, 21 Aug 2018 22:21:34 -0500 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: [Chris Angelico] > Though... it's insignificant when the function header precedes the > expression/body. With the proposal to move the header to the end, that > might become problematic, which makes it yet another cost to the > proposal. I don't think it would be a problem because, like ternary and other circuiting operations, the expression isn't evaluated until certain criteria are met. The arrangement shouldn't matter. ...I think. On Tue, Aug 21, 2018 at 10:10 PM Chris Angelico wrote: > On Wed, Aug 22, 2018 at 12:57 PM, Abe Dillon wrote: > > [Chris Angelico] > >> > >> If you have a use-case for a lambda function that takes a callback and > >> has a default value for that callback, please submit it to The Daily > >> WTF. In Steve's example, the main function was created with a > >> statement. > > > > > > Fair enough, but I still think D'Aprano may have engineered his example > to > > be particularly unreadable. > > Why would you use 'arg' for both the argument to the method and the > > callback! That's at least a little WTF. > > True, but hardly significant. The one inside lambda is local to it. > > Though... it's insignificant when the function header precedes the > expression/body. With the proposal to move the header to the end, that > might become problematic, which makes it yet another cost to the > proposal. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Tue Aug 21 23:24:24 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Wed, 22 Aug 2018 12:24:24 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: <23420.55144.2677.692751@turnbull.sk.tsukuba.ac.jp> Chris Angelico writes: > I have to defer to someone who knows in more detail here, but the > parser will look ahead one "token", whatever a token is. (Technically > it doesn't backtrack, it looks ahead - same difference.) Tokens are basically keywords, identifiers, most single punctuation characters, and indentation. Some strings of punctuation are tokens by special dispensation. > In order for the ternary-if to work, the expression before the if > has to be of a more restricted type than just "any expression" (for > instance, you can't put a lambda function there, unless you > parenthesize it). It's not that it's a restricted expression, it's that a valid lambda will consist of a syntactically complete expression. If you then place "if" after that lambda without parenthesizing, the parser will think that the lambda contains the whole ternary expression because pretty much any Python expression has a value that can be implicitly cast to bool. Steve From steve at pearwood.info Wed Aug 22 02:11:54 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 22 Aug 2018 16:11:54 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: <20180822061154.GF24160@ando.pearwood.info> On Tue, Aug 21, 2018 at 01:56:16PM -0500, Abe Dillon wrote: > The revelation that it's a function should come when you read the "by" or > "key". I disagree. The most important fact is that it is a function, not specifically what it does. Consider: widget.register(value[a](x) with x) (As per your earlier example of ternary if operator, I've inserted spaces to emphasis the gap.) At first it looks like you are evaluating value[1](x) eagerly, right there in the method call, and then you have to backtrack and change your expectation about what you just read when you get to the end and see the declarations. Even Forth, which (apart from its use of extremely concise commands) is most (in)famous for backwards things writing in Reverse Polish Notation, or programming by Yoda *wink* nevertheless puts the "function declaration" before the body. Classically, you define a function like this: : func DUP DROP ; The colon tells the interpreter to start compiling a function named "func", DUP and DROP are the commands in the body of the function (in this case, a pointless combination), and the semi-colon says to stop compiling and bind the new function body to the given name. Classical Forth doesn't have named function parameters, but some RPN languages do, and likewise they come first. In the HP calculator RPN language, we write something like: << -> x << DUP DROP >> >> to grap an argument and assign it to "x". Given some sort of look-ahead, it's *possible* to put the parameter list at the end of the function body: def function: do_this(a) do_that(b) do_something_else(c) with (a, b, c=None) but I think you can see why that would be annoying. You don't even know which names are global and which are parameters until you get to the very end of the function. Blah. The same applies to function expressions. Given the function body: value[a](x) which of value, a and x are global names and which are parameters? > If you don't know what that parameter is, then that's where the > "wait wait wiat!" should happen. "Wait wait wait!" should ideally never happen. In programming, surprises are not a good thing, and they're even less good when they are retroactive. "Ha, fooled you! You thought you were dealing with an eagerly evaluated expression, but it was a deferred function body declaration instead! Mwahahahaha!!!" -- Steve From steve at pearwood.info Wed Aug 22 02:20:52 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 22 Aug 2018 16:20:52 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> Message-ID: <20180822062052.GG24160@ando.pearwood.info> On Tue, Aug 21, 2018 at 05:45:53PM -0500, Abe Dillon wrote: > Can you explain how far the parser is capable of backtracking? Its an LL(1) parser, if I recall correctly, so if you look at the details of LL(1) parsing, that should answer the question. https://en.wikipedia.org/wiki/LL_parser But if I'm reading the Wikipedia page correctly, I think the answer is "no backtracking at all". > It seems like with would require a similar amount > of backtracking to ternary expressions: > > if else I don't think needs any backtracking. The parser doesn't have to read the "if" and then go back to re-read the previous expression. It can look ahead from the expression by one token, see the "if", and recognise it is a ternary if. -- Steve From rhodri at kynesim.co.uk Wed Aug 22 09:15:52 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 22 Aug 2018 14:15:52 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822061154.GF24160@ando.pearwood.info> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> Message-ID: On 22/08/18 07:11, Steven D'Aprano wrote: > "Wait wait wait!" should ideally never happen. In programming, surprises > are not a good thing, and they're even less good when they are > retroactive. > > "Ha, fooled you! You thought you were dealing with an eagerly evaluated > expression, but it was a deferred function body declaration instead! > Mwahahahaha!!!" This, by the way, is why think using the same syntax for function definition and generator definition was a mistake. It's only when I reach a "yield" statement that I realise my expectations for this code are wrong. (That was a decision made a long time ago, and I'm not fool enough to think that there's any benefit in trying to change it now. I can still be a grumpy old man over it, though.) -- Rhodri James *-* Kynesim Ltd From jfine2358 at gmail.com Wed Aug 22 09:38:07 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 22 Aug 2018 14:38:07 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> Message-ID: Hi Rhodri You wrote: >This, by the way, is why think using the same syntax for function definition and generator definition was a mistake. It's only when I reach a "yield" statement that I realise my expectations for this code are wrong. Here's something that might help, and surprise, you. This has been present since Python 2.5. >>> def fn(): ... if None: ... yield ... >>> list(fn()) # Fails, unless fn is a generator function. [] I think what's happening is this. Even though the None-guarded yield has been optimised away, it leaves a residue. Namely, that there's a yield in the function. Hence fn() is an iterator. Having explained the surprise, here's how it can help you. Suppose you have a long function body, with a single yield at the bottom. If you write like this: def my_very_long_function_with_one_yield_point(...): if None: yield # This is a generator function. then the next programmer can know immediately that it's a generator function. -- Jonathan From jfine2358 at gmail.com Wed Aug 22 11:58:17 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 22 Aug 2018 16:58:17 +0100 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: I wrote: > Here is my simple proposal. Enhance Python to allow > > >>> hn = def a, b=2, c=3: a ** b / c I'd like to add a clarification. Here are two proposals. ONE. Wherever you could have used 'lambda', you now have a choice. You can still use 'lambda', or you can use 'def' instead. The semantics are unchanged. TWO. Wherever you could have used 'lambda', you must now use 'def' instead. The semantics are unchanged. I'm proposing ONE, not TWO. All existing Python code will continue to run exactly as before. No Python code will have to be changed. And no new programming capabilities would be added. So why do it? In a nutshell, to remove an obstacle. To make DEFerred expressions easier to understand. Is it worth doing? That's a cost-benefit analysis. I think the main benefit will be in the docs, and in teaching people Python. And does it fit in with the Zen of Python? > There should be one-- and preferably only one --obvious way to do it. > Although that way may not be obvious at first unless you're Dutch. So is having both 'def' and 'lambda' unpythonic? Two ways to do the same thing! With PEP 572 (see exceptional cases), the following are equivalent: >>> a = 1 >>> (a := 1) And we're allowed to use tabs or spaces for indentation (see PEP 666). So *maybe* having both 'lambda' and 'def' is sufficiently Pythonic. -- Jonathan From python-ideas at mgmiller.net Wed Aug 22 12:11:15 2018 From: python-ideas at mgmiller.net (Mike Miller) Date: Wed, 22 Aug 2018 09:11:15 -0700 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> I've often thought the same about "lambda." Although I've long since gotten used to the word, "def" without a function name seemed like a better choice, especially for beginners. +0.25 for proposal ONE However, parentheses should be allowed and lambda put on a long deprecation schedule. -Mike On 2018-08-22 08:58, Jonathan Fine wrote: > > ONE. Wherever you could have used 'lambda', you now have a choice. > You can still use 'lambda', or you can use 'def' instead. The > semantics are unchanged. > From steve at pearwood.info Wed Aug 22 12:34:19 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 02:34:19 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> Message-ID: <20180822163417.GK24160@ando.pearwood.info> Michael makes some reasonable points, but I think the very premise of this thread is putting the cart before the horse. As educators, if we fail to teach the technical language of a field to our students, we are failing to prepare those students to enter that field. Technical jargon is the language of the field. If it makes teaching beginners more difficult, well, so it goes. Lots of things make teaching more difficult e.g.: - technical jargon; - expecting students to write code that runs; - expecting the code to run correctly; - having them do input validation and error handling; - and write documentation and comments for their code. Lambda is becoming a standard technical term in computing, even in languages which don't use that keyword. The official name for Java's anonymous functions is "lambda expressions": https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html Ruby has no fewer than three separate kinds of anonymous callable, blocks, procs and lambdas: https://medium.com/@AdamKing0126/ruby-whats-the-deal-with-procs-and-lambdas-165450cdf573 and the term is now used in C++, C#, LINQ and others, even if they don't use it as a keyword. https://duckduckgo.com/?q=lambda+expressions We should not focus too heavily on the earliest and most ignorant stage of people's programming life. That stage makes up probably less than 10% of their life as a programmer. Python is a general purpose programming language and we shouldn't shy from the appropriate use of technical terms in the documentation and the language itself. Python is not Scratch and the primary focus of Python the language is not education. Many people come to Python for the first time with one, two or ten other languages under their belt, and some of them even have a good grasp of computer science. We should not talk down to those experienced coders for the sake of those in the first year or so of their programming life. Scratch, for example, doesn't use the word "function" to describe functions. They use "blocks" (but not in the Ruby sense). This is, I suppose, fine for the average kid of age 8, if you think talking down to kids is okay (or necessary). But if we were designing Python from scratch today (pun intended), we surely ought not follow their lead. https://en.scratch-wiki.info/wiki/Custom_Blocks More comments below, following Michael's comments. On Tue, Aug 14, 2018 at 12:42:29PM -0700, Michael Selik wrote: > The conversation about syntactic sugar for ``functools.partial`` led to a > question about whether jargon like "lambda" makes the concept of an > anonymous function more difficult to learn. And the experience of educators like Chris teaching Javascript suggests strongly that no, it doesn't, since Javascript learners have just as much trouble learning the concept of "function" as Python learners have with "lambda". Chris' conclusion is that anonymous functions are inherently hard for many beginners to learn, regardless of whether the syntax is called "lambda" or "function". That matches my own observations, interacting with newbies on various mailing lists, as well as my own personal experience. I believe that many people have a lot of trouble grasping the concept of functions as first-class values capable of being passed to other functions as data. It requires a major rethink of the way we think of functions. We go from treating them purely as verbs: sort the list to nouns in their own right: process the sort # the what now? Not "process the sorted list", but reify the sort verb into an actual thing (an object or value) and then process that thing itself. This is mind-bending when you think about it, far more mind-blowing than the normal linguistic process of nouning verbs and verbing nouns. No wonder people take a while to get fully comfortable with the concept. It took me a long time to stop writing code like this: map(lambda x: len(x), sequence) instead of simply map(len, sequence). I doubt it would have taken any less time if it were map(function x: len(x), sequence) instead. Aside from having to learn the correct spelling ("lamdba"?) it was never the *name* that gave me trouble. Of course there is a cost for beginners to having to learn a name, and the less often the name is used, the longer it takes (unless it is extremely memorable). But that cost is paid for, with interest, later, as a journeyman or journeywoman programmer. > In my own experience teaching, I find that many concepts are easier to > introduce if I avoid the Python jargon until after I've explained what it > does. This is supported by education research. Some light Googling found a > study on the topic [0] that is consistent with my own observations. I agree. When I teach my students function transformations in maths, any time I use the technical terms translation, dilation and reflection, I follow up with the common terms shift, stretch, and flip, and vice versa. I make a point of always associating the imprecise plain English words with the precise technical terms. Nevertheless, it is important that I teach them the technical terms too. -- Steve From chris.barker at noaa.gov Wed Aug 22 12:38:57 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Wed, 22 Aug 2018 09:38:57 -0700 Subject: [Python-ideas] Off topic: 'strike a balance' - second language English In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> Message-ID: On Tue, Aug 21, 2018 at 3:07 PM, Jonathan Fine wrote: > > Maybe this is something Python's REPL should do? > > Good idea. > I can't find (with very little effort) any documentation of this, but I have a vague recollection that the core devs want to keep the built-in REPL really simple -- more advanced features are for third party packages like iPython. I tend to agree -- while something like this: "making the built-in repl more friendly t copy-and-paste from examples" seems like a no brainer, the fact is that there are a LOT of features that would make it easier for newbies, and in the end, you'd end up with something like iPython. Honestly, Python does "suffer" a bit when in competition with commercial products, in that it is a language (and an implementation of that language), not an entire programming environment. So to use it, you need to figure out which Editor or IDE you want to use, what debugger, etc..... And the REPL, while being pretty key to interactive data analysis, is not a key feature of programming languages in general, even interpreted ones. So the solution is: use a third party solution for a complete environment suitable for your needs. For instance, for people doing data analysis, I recommend Anaconda -- then you get iPython and JUpyter (and Spyder) out of the box -- and away we go. maybe it's worth a note t pyton-dev to confirm my vague impression (or some more thorough googling for previous discussions) -- but I wouldn't put much effort into ideas for the REPL without confirming that the core dev are open to the concept. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From contact at brice.xyz Wed Aug 22 12:44:47 2018 From: contact at brice.xyz (Brice Parent) Date: Wed, 22 Aug 2018 18:44:47 +0200 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: <2368fb00-c20f-b9f5-1b45-0987e2e288d3@mrabarnett.plus.com> References: <93da1bb6-3d70-8e9d-d25f-eabdbdcd027b@mrabarnett.plus.com> <2368fb00-c20f-b9f5-1b45-0987e2e288d3@mrabarnett.plus.com> Message-ID: <1dcfd6a2-ad72-bd5d-672c-6ef08469dbce@brice.xyz> Le 22/08/2018 ? 04:12, MRAB a ?crit?: > On 2018-08-22 02:38, Elazar wrote: >> I don't think this change makes sense, but if it's done, there should >> be another change, with actual implications: >> There is no way to express the types of the parameters in a lambda - >> `lambda x: int : x` is obviously a syntax error. Replacing the colon >> with a different symbol, such as "=>" will make this possible: >> >> ?? ? def x => x >> ?? ? def x: int => x >> ?? ? def x: int -> int => x >> >> It will also give one less meaning to the colon. >> > The examples I showed had parens, so your examples could be: > > ??? def (x): x > ??? def (x: int): x > ??? def (x: int) -> int: x With or without allowing `def` to be an equivalent of `lambda`, I think this is a great idea. To me, someone who understands the following 2 lines: lambda x, y: x * y def a(x: float, y: int) -> float: ... would probably understand the following: lambda(x: float, y: int) -> float: x * y (more type hints, I like it!) From stephanh42 at gmail.com Wed Aug 22 12:51:28 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Wed, 22 Aug 2018 18:51:28 +0200 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> References: <20180822015502.GE24160@ando.pearwood.info> <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> Message-ID: Let me stand up and say that I personally like lambda. It's the standard terminology and not easily confused. I doubt that "many Python users" have a problem with it. Evidence? I dislike the def proposal strongly. It is too similar to a normal def. At least get a new keyword then Some other languages: lambda: scheme, lisp \ : Haskell fn : Standard ml function : JavaScript [] : C++ Stephan Op wo 22 aug. 2018 18:16 schreef Mike Miller : > I've often thought the same about "lambda." > > Although I've long since gotten used to the word, "def" without a function > name > seemed like a better choice, especially for beginners. > > +0.25 for proposal ONE > > However, parentheses should be allowed and lambda put on a long > deprecation > schedule. > > -Mike > > > On 2018-08-22 08:58, Jonathan Fine wrote: > > > > ONE. Wherever you could have used 'lambda', you now have a choice. > > You can still use 'lambda', or you can use 'def' instead. The > > semantics are unchanged. > > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Wed Aug 22 12:59:56 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Wed, 22 Aug 2018 09:59:56 -0700 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> Message-ID: On Wed, Aug 22, 2018 at 9:51 AM, Stephan Houben wrote: > Let me stand up and say that I personally like lambda. It's the standard > terminology and not easily confused. > I agree. And secondly, even if I didn't like it, changing the name of something because it's a slightly less confusing name to newbies is a really low priority! If you look back at previous discussion, the real push was to exp[and lambda's capabilities -- maybe allow more than one expression, or ??? But that would make it MORE confusing to newbies, not less. I actually think it makes a strikes a pretty good balance -- to use the idiomatic phrase :-) -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Wed Aug 22 12:57:23 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 02:57:23 +1000 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: <20180822165723.GM24160@ando.pearwood.info> On Wed, Aug 22, 2018 at 04:58:17PM +0100, Jonathan Fine wrote: > I wrote: > > > Here is my simple proposal. Enhance Python to allow > > > > >>> hn = def a, b=2, c=3: a ** b / c > > I'd like to add a clarification. Here are two proposals. > > ONE. Wherever you could have used 'lambda', you now have a choice. > You can still use 'lambda', or you can use 'def' instead. The > semantics are unchanged. > > TWO. Wherever you could have used 'lambda', you must now use 'def' > instead. The semantics are unchanged. > > I'm proposing ONE, not TWO. All existing Python code will continue to > run exactly as before. No Python code will have to be changed. And no > new programming capabilities would be added. > > So why do it? In a nutshell, to remove an obstacle. And add a new obstacle: "What's the difference between function expressions created with def and function expressions created with lambda?" "Nothing." "So why do I have to learn TWO sets of syntax for exactly the same thing?" "Because its easier than learning one!" > To make DEFerred expressions easier to understand. They're not "deferred expressions", they're functions. It is true that function bodies contain deferred expressions (or statements), but the whole is not the part. -- Steve From jfine2358 at gmail.com Wed Aug 22 13:06:42 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 22 Aug 2018 18:06:42 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822163417.GK24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: Hi Steve You and I have different experience, background and interests. You wrote > As educators, if we fail to teach the technical language of a field to > our students, we are failing to prepare those students to enter that > field. Technical jargon is the language of the field. Python is a language with an enormous range. That is one of it's many strengths. Its users range from school-children, doing programming as part of their general education, all the way to research scientists, professional system administrators and the like. There are some really clever professional Python programmers. Some students learning Python, shock horror, won't enter the field. What proportion, I don't know. Some good statistics here would be helpful. For a different view of Python, take a look at * https://www.codeclub.org.uk/ * https://tutorial.djangogirls.org/en/python_introduction/ * https://codewith.mu/ * https://microbit.org/ * https://microbit.org/code/ The last two are important. > http://www.bbc.co.uk/programmes/articles/4hVG2Br1W1LKCmw8nSm9WnQ/the-bbc-micro-bit The BBC micro:bit is a pocket-sized codeable computer with motion detection, a built-in compass and Bluetooth technology, which was given free to every child in year 7 or equivalent across the UK in 2016. All these children could be Python users. Very different from the students that you, as an educator, are preparing to enter the technical field of computer software. You further write > We should not focus too heavily on the earliest and most ignorant stage > of people's programming life. That stage makes up probably less than 10% > of their life as a programmer. I'm very happy that Python works for the novice, and occasional programmers. Who have not aspirations to have a life as a programmer. Maybe they're musicians, or artists, or someone building a personal website. There are some really clever people in these fields, who write non-professional Python software. I'm very happy that Python works for high powered experts who are doing machine learning, numerical analysis, partial differential equations, big data and cloud system administration. To turn you statement around: We shouldn't focus too heavily on the latest and most learned stages of programming. Such activity, by hours spent, makes up probably less than 10% of humanity's time spent coding. Not disagreeing with you. Just viewing things differently. -- Jonathan From solipsis at pitrou.net Wed Aug 22 13:08:36 2018 From: solipsis at pitrou.net (Antoine Pitrou) Date: Wed, 22 Aug 2018 19:08:36 +0200 Subject: [Python-ideas] REPL features References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> Message-ID: <20180822190836.3ae7d378@fsol> On Wed, 22 Aug 2018 09:38:57 -0700 Chris Barker via Python-ideas wrote: > On Tue, Aug 21, 2018 at 3:07 PM, Jonathan Fine wrote: > > > > Maybe this is something Python's REPL should do? > > > > Good idea. > > > > I can't find (with very little effort) any documentation of this, but I > have a vague recollection that the core devs want to keep the built-in REPL > really simple -- more advanced features are for third party packages like > iPython. > > I tend to agree -- while something like this: "making the built-in repl > more friendly t copy-and-paste from examples" seems like a no brainer, the > fact is that there are a LOT of features that would make it easier for > newbies, and in the end, you'd end up with something like iPython. > > Honestly, Python does "suffer" a bit when in competition with commercial > products, in that it is a language (and an implementation of that > language), not an entire programming environment. So to use it, you need to > figure out which Editor or IDE you want to use, what debugger, etc..... > > And the REPL, while being pretty key to interactive data analysis, is not a > key feature of programming languages in general, even interpreted ones. > > So the solution is: use a third party solution for a complete environment > suitable for your needs. For instance, for people doing data analysis, I > recommend Anaconda -- then you get iPython and JUpyter (and Spyder) out of > the box -- and away we go. > > maybe it's worth a note t pyton-dev to confirm my vague impression (or some > more thorough googling for previous discussions) -- but I wouldn't put much > effort into ideas for the REPL without confirming that the core dev are > open to the concept. To me it sounds fine to improve the REPL. Especially, being able to paste examples without effort was a sore point for me until I finally switched to IPython. How much complexity and development work that would entail I don't know, though :-) Regards Antoine. From abedillon at gmail.com Wed Aug 22 13:11:40 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 22 Aug 2018 12:11:40 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822061154.GF24160@ando.pearwood.info> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> Message-ID: [Steven D'Aprano] > > The revelation that it's a function should come when you read the "by" or > > "key". > I disagree. The most important fact is that it is a function, not > specifically what it does. I was trying to say that the context almost always gives away that the reader should expect a function. Again, the pseudo code: hand = sorted(cards, by=card.suit) Is usually enough for most people to understand. When you add in what the computer needs to make the whole thing mechanically unambiguous: hand = sorted(cards, key=lambda card: card.suit) You can see the noise added compared to the pseudo code. The difference (to me) looks like this: hand = sorted(cards, by#=#############card.suit) Ideally, we could move that noise out of the way so that the intent is more clearly expressed: hand = sorted(cards, by=card.suit ########## Functions, variables and parameters are normally named such that they give away lots of context (or they should be). Context that's available to the reader but not the computer. [Steven D'Aprano] > Consider: > widget.register(value[a](x) with x) > At first it looks like you are evaluating value[1](x) eagerly, right > there in the method call, and then you have to backtrack and change your > expectation about what you just read when you get to the end and see the > declarations. First, how is your example any worse that the delayed binding of generator expressions? widget.register(value[a](x) for x in things) Of course the context of what they're reading builds as they read it. You could put those spaces anywhere: widget.register(value[a] (x) for x in things) Delayed binding works because human readers can deal with a little ambiguity in what they're reading especially if it means putting the intent of the code before the book keeping. If we're assuming a naive reader who's never seen the widget.register method and method and variable names that are pretty ambiguous (not unheard of, especially in anonymous functions) then I would say the blocker is not knowing what widget.register is in the first place. If you don't know that, then what point is continuing to read? Will knowing the kinds of object being passed clear everything up? widget.combobulate(5, "elephant", True) Once the reader has encountered widget.register they'll know it takes a function as an input. Just like anyone who's used time.sleep will be thrown for a loop as soon as they see lambda in: time.sleep(lambda x: value[a](x)) [Steven D'Aprano] > Given some sort of look-ahead, it's *possible* to put the parameter list > at the end of the function body: > def function: > do_this(a) > do_that(b) > do_something_else(c) > with (a, b, c=None) > but I think you can see why that would be annoying. Yes! Common ground! Named functions serve a different purpose than anonymous functions. They usually handle situations where the interface is more important than the implementation. def square_root(x): ... Better spit out the square root of whatever number I give it. I don't care how. Anonymous functions are almost always used in contexts where the interface is implied and the important bit is *what* it does: ui_element.on_mouseover( with event) [Steven D'Aprano] > You don't even know > which names are global and which are parameters until you get to the > very end of the function. Blah. > The same applies to function expressions. Given the function body: > value[a](x) > which of value, a and x are global names and which are parameters? The same could be said of the value[a](x) in: widget.register(value[a](x) for x in things) [Steven D'Aprano] > "Wait wait wait!" should ideally never happen. In programming, surprises > are not a good thing, and they're even less good when they are > retroactive. It happens when someone has never seen the map function used or sorted used with a key function. It happens during the time where reading code is hard to begin with. The "wait wait wait" happens when you don't know what map is. Once you learn that, then you learn that the first parameter is a function. Then whenever you see map, you should expect the first parameter to be a function. No amount of broadcasting that the first parameter is indeed a function will cure the confusion of not knowing what map, or wiget.register is. *Having said all that:* Jonathan Fine pointed out that the format that I've been championing (where I've been using "with" for the separator) has a subtle flaw where empty signatures are pretty awkward: d = defaultdict(100 with) It *kind-of* works with "def" and you read it as, "the preceding expression is deferred" followed by an *optional* signature declaration. d = defaultdict(100 def) But it's not great. Another alternative is to use some (ideally short) prefix and making the signature declaration optional: [ ] d = defaultdict(def 100) hand = sorted(cards, by=def card.suit with card) of course there are many possible choices for the prefix and separator and subtle alterations like: hand = sorted(cards, by==>card.suit with(card)) . # where '=>' is the prefix, it just blends nicely or: d = defaultdict(100 with()) Anyway, none of that interests me. What interests me is the recognition of *why* expressionization of statements often leads to a re-ordered version of the original. My thesis is that expressions are slightly more flexible than statements which allows for a more expressive ordering that is sometimes better for readability. I think it's important to understand that if we ever expressionize other statements like try-except, with, etc. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Wed Aug 22 13:22:33 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 03:22:33 +1000 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> Message-ID: <20180822172233.GN24160@ando.pearwood.info> On Tue, Aug 21, 2018 at 09:57:51PM -0500, Abe Dillon wrote: > [Chris Angelico] > > > If you have a use-case for a lambda function that takes a callback and > > has a default value for that callback, please submit it to The Daily > > WTF. In Steve's example, the main function was created with a > > statement. > > > Fair enough, but I still think D'Aprano may have engineered his example to > be particularly unreadable. I picked the example to showcase an example of where this suggested new syntax looks bad. Part of debating proposals is to look at pros and cons, not just to look at the best cases. But it wasn't an engineered example in the sense of "invented just for this purpose". Of course I used metasyntactic variables rather than real code, but I assure you I have real code that uses lambda in function parameter lists. Nor am I the only one. For example, I have a private module (fortunately now retired) that backports itertools to older versions of Python, and it includes a version of groupby that looks like this: class groupby(object): def __init__(self, iterable, key=lambda obj: obj): ... I, er, "borrowed" a Prime number sieve class from somewhere (and forget where, so I can't give credit where credit is due) and it starts like this: class Primes(object): def __init__(self, n=None, extend=False, exf=lambda x:x + x//2): The std lib contains a test that this correctly raises SyntaxError: def f(*, x=lambda __debug__:0): pass (the problem here is that __debug__ cannot be used as a parameter name). So its not just me who uses lambda as a default argument. > Why would you use 'arg' for both the argument to the method and the > callback! That's at least a little WTF. Heh, I didn't even notice that. It certainly wasn't intentional. Sorry. -- Steve From mertz at gnosis.cx Wed Aug 22 13:38:03 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 22 Aug 2018 13:38:03 -0400 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822163417.GK24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: On Wed, Aug 22, 2018, 12:40 PM Steven D'Aprano wrote: > I believe that many people have a lot of trouble grasping the concept of > functions as first-class values capable of being passed to other functions > as data... It took me a long time to stop writing code like this: > > map(lambda x: len(x), sequence) > > instead of simply map(len, sequence). > That long time is ongoing :-) You recently wrote in another thread: widget.register(callback=lambda: spam.eggs()) Instead of the slightly faster and definitely more direct: widget.register(callback=spam.eggs()) > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rhodri at kynesim.co.uk Wed Aug 22 13:42:42 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 22 Aug 2018 18:42:42 +0100 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> Message-ID: <475de31f-1ed6-bdaa-b667-a69fdc754629@kynesim.co.uk> On 22/08/18 17:59, Chris Barker via Python-ideas wrote: > On Wed, Aug 22, 2018 at 9:51 AM, Stephan Houben > wrote: > >> Let me stand up and say that I personally like lambda. It's the standard >> terminology and not easily confused. >> > I agree. > > And secondly, even if I didn't like it, changing the name of something > because it's a slightly less confusing name to newbies is a really low > priority! Jonathan isn't proposing to change the name, just to add a synonym. The obvious quote from the Zen at this point is: "There should be one-- and preferably only one --obvious way to do it." -- Rhodri James *-* Kynesim Ltd From steve at pearwood.info Wed Aug 22 13:44:07 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 03:44:07 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> Message-ID: <20180822174406.GO24160@ando.pearwood.info> On Wed, Aug 22, 2018 at 12:11:40PM -0500, Abe Dillon wrote: > [Steven D'Aprano] > > > > The revelation that it's a function should come when you read the "by" or > > > "key". > > I disagree. The most important fact is that it is a function, not > > specifically what it does. > > > I was trying to say that the context almost always gives away that the > reader should expect a function. > > Again, the pseudo code: > > hand = sorted(cards, by=card.suit) > > Is usually enough for most people to understand. You are judging that from the perspective of someone whose native language makes it easy to say "sorted by foo" (for some value of foo). We shouldn't judge syntax proposals just on the cases that are carefully chosen to showcase them at their best. Especially not trivial cases. Here is a line from the importbench tool in Python 3.5: def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): Under your proposal, that becomes: def bench(name, cleanup=None with ???, *, seconds=1, repeat=3): except I'm not really sure what goes in the ??? for an empty parameter list. But whatever it is, do you still think it is obvious that people will recognise "None" to mean a function without having to backtrack? And from the threading tests: t = threading.Thread(target=lambda: None) difflib tests include this call: sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', ...) which becomes: sm = difflib.SequenceMatcher(isjunk=x == ' ' with x, ...) The expression x==' ' doesn't look like a function to me. > Ideally, we could move that noise out of the way so that the intent is more > clearly expressed: So you say. I say it isn't noise, and if you ask me to express my intent, I'll state that it is a function first and at the beginning of the expression, not the end. > > Consider: > > widget.register(value[a](x) with x) > > > At first it looks like you are evaluating value[1](x) eagerly, right > > there in the method call, and then you have to backtrack and change your > > expectation about what you just read when you get to the end and see the > > declarations. > > > First, how is your example any worse that the delayed binding of generator > expressions? > > widget.register(value[a](x) for x in things) Who says its worse? I think they are equally as problematic. Many people have trouble with comprehension syntax precisely because it breaks left-to-right order. I think we ought to be cautious about emulating that elsewhere. -- Steve From steve at pearwood.info Wed Aug 22 13:46:33 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 03:46:33 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: <20180822174632.GP24160@ando.pearwood.info> On Wed, Aug 22, 2018 at 01:38:03PM -0400, David Mertz wrote: > On Wed, Aug 22, 2018, 12:40 PM Steven D'Aprano wrote: > > > I believe that many people have a lot of trouble grasping the concept of > > functions as first-class values capable of being passed to other functions > > as data... It took me a long time to stop writing code like this: > > > > map(lambda x: len(x), sequence) > > > > instead of simply map(len, sequence). > > > > That long time is ongoing :-) > > You recently wrote in another thread: > > widget.register(callback=lambda: spam.eggs()) Hah, so I did. > Instead of the slightly faster and definitely more direct: > > widget.register(callback=spam.eggs()) Except that doesn't work, since you are passing the result of calling spam.eggs as the callback, instead of spam.eggs itself :-) -- Steve From rhodri at kynesim.co.uk Wed Aug 22 13:56:51 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 22 Aug 2018 18:56:51 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> Message-ID: <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> On 22/08/18 14:38, Jonathan Fine wrote: > Hi Rhodri > > You wrote: > >> This, by the way, is why think using the same syntax for function definition and generator definition was a mistake. It's only when I reach a "yield" statement that I realise my expectations for this code are wrong. > > Here's something that might help, and surprise, you. This has been > present since Python 2.5. If by "help" you mean "make even more confused", then yes. Surprise is a given with generators, as I said. > >>>> def fn(): > ... if None: > ... yield > ... >>>> list(fn()) # Fails, unless fn is a generator function. > [] > > I think what's happening is this. Even though the None-guarded yield > has been optimised away, it leaves a residue. Namely, that there's a > yield in the function. Hence fn() is an iterator. > > Having explained the surprise, here's how it can help you. Suppose you > have a long function body, with a single yield at the bottom. If you > write like this: > > def my_very_long_function_with_one_yield_point(...): > if None: yield # This is a generator function. > > then the next programmer can know immediately that it's a generator function. Ew. I'd prefer this way of doing it: def my_very_long_function_with_one_yield_point(...): # This is a generator -- Rhodri James *-* Kynesim Ltd From rhodri at kynesim.co.uk Wed Aug 22 14:03:31 2018 From: rhodri at kynesim.co.uk (Rhodri James) Date: Wed, 22 Aug 2018 19:03:31 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: On 22/08/18 18:06, Jonathan Fine wrote: > The BBC micro:bit is a pocket-sized codeable computer with motion > detection, a built-in compass and Bluetooth technology, which was > given free to every child in year 7 or equivalent across the UK in > 2016. Ditto for the Raspberry Pi, which is cheap rather than free but aimed at very must the same market. > All these children could be Python users. Very different from the > students that you, as an educator, are preparing to enter the > technical field of computer software. In my experience teaching 12-15 year olds Python, not very different at all. Those that are interested in learning programming are interested in learning it properly, just like their older counterparts. Those that aren't interested in learning it aren't interested in learning it, no matter how much you dumb it down or talk it up. > To turn you statement around: We shouldn't focus too heavily on the > latest and most learned stages of programming. Such activity, by hours > spent, makes up probably less than 10% of humanity's time spent > coding. If you're talking about Python coding I sincerely doubt that statistic. If you're talking about coding in general, it's meaningless. -- Rhodri James *-* Kynesim Ltd From stephanh42 at gmail.com Wed Aug 22 14:41:52 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Wed, 22 Aug 2018 20:41:52 +0200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822163417.GK24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: Op wo 22 aug. 2018 18:40 schreef Steven D'Aprano : > Chris' conclusion is that anonymous functions are inherently hard for > many beginners to learn, regardless of whether the syntax is called > "lambda" or "function". > Civilization itself had trouble with the concept. Functions as mathematical objects in their own right were only conceived (late) in the 19th century. Church's lambda notation was the first way to write down a function without naming it, in the 1930's. And a proven consistent model for lambda calculus was only provided by Dana Scott in the 1970's! So clearly these mathematical developments haven't yet entered high school mathematics, which remains firmly set in an 18th century mindset, where we can interchangeably write down f or f(x). Unfortunately modern computer languages require more, so it is up to the comp sci teacher to fill the gap. But let's not blame Church's notation for that. ? f.(? x. f(x x)) (? x. f(x x)) lambda f: (lambda x: f(x(x))) (lambda x: f(x(x))) (Yeah I know it doesn't work in eagerly-evaluated Python). Stephan > That matches my own observations, interacting with newbies on various > mailing lists, as well as my own personal experience. > > I believe that many people have a lot of trouble grasping the concept of > functions as first-class values capable of being passed to other > functions as data. It requires a major rethink of the way we think of > functions. We go from treating them purely as verbs: > > sort the list > > to nouns in their own right: > > process the sort # the what now? > > > Not "process the sorted list", but reify the sort verb into an actual > thing (an object or value) and then process that thing itself. > > This is mind-bending when you think about it, far more mind-blowing than > the normal linguistic process of nouning verbs and verbing nouns. No > wonder people take a while to get fully comfortable with the concept. It > took me a long time to stop writing code like this: > > map(lambda x: len(x), sequence) > > instead of simply map(len, sequence). I doubt it would have taken any > less time if it were > > map(function x: len(x), sequence) > > instead. Aside from having to learn the correct spelling ("lamdba"?) it > was never the *name* that gave me trouble. > > Of course there is a cost for beginners to having to learn a name, and > the less often the name is used, the longer it takes (unless it is > extremely memorable). But that cost is paid for, with interest, later, > as a journeyman or journeywoman programmer. > > > > In my own experience teaching, I find that many concepts are easier to > > introduce if I avoid the Python jargon until after I've explained what it > > does. This is supported by education research. Some light Googling found > a > > study on the topic [0] that is consistent with my own observations. > > I agree. When I teach my students function transformations in maths, any > time I use the technical terms translation, dilation and reflection, I > follow up with the common terms shift, stretch, and flip, and vice > versa. I make a point of always associating the imprecise plain English > words with the precise technical terms. > > Nevertheless, it is important that I teach them the technical terms too. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dan at tombstonezero.net Wed Aug 22 14:50:29 2018 From: dan at tombstonezero.net (Dan Sommers) Date: Wed, 22 Aug 2018 18:50:29 +0000 (UTC) Subject: [Python-ideas] Does jargon make learning more difficult? References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <20180822174406.GO24160@ando.pearwood.info> Message-ID: On Thu, 23 Aug 2018 03:44:07 +1000, Steven D'Aprano wrote: > On Wed, Aug 22, 2018 at 12:11:40PM -0500, Abe Dillon wrote: > difflib tests include this call: > > sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', ...) > > which becomes: > > sm = difflib.SequenceMatcher(isjunk=x == ' ' with x, ...) > > The expression x==' ' doesn't look like a function to me. Hold that thought. >> Ideally, we could move that noise out of the way so that the intent >> is more clearly expressed: > > So you say. > > I say it isn't noise, and if you ask me to express my intent, I'll > state that it is a function first and at the beginning of the > expression, not the end. Okay, so I'm trying to follow along, and not jump in with another "me, too" response. Statements and expressions don't read from left to right. Blocks and functions don't read from top to bottom. Some people read programs from the inside out, assembling bigger and bigger building blocks until the entire program is just a building block. Others read programs from the outside in, decomposing really blg blocks until the remaining blocks are small enough to see and understand without further decomposing. Reading a program, let alone figuring out what it does, let alone figuring out what it's supposed to do, is not a simple single pass process. Something has to come first, and something has to come next, and something will end up coming at the end. Regardless, the reader will have to save some context, or go back and look at the beginning again. So is it better to see the definitions first, and the logic second? Or is it better to see the logic first and the definitions later? I don't know; it depends. It may even vary over time inside the same code base. When you talk about intent, I think about use cases. In the difflib code I quoted above, is the intent to define a function, or to instantiate a SequenceMatcher? Well, no, it's probably to compute some sort of difference. Instatiating a SequenceMatcher and defining isjunk are details. So you're both wrong. :-P Or you're both right. :-/ A large part of my previous job was digesting papers written by economists and mathematicians, and then translating the ideas and algowithms in those papers into code. Sometimes, I'd see stuff like this: Given x = the width of a widget and y = the price of that widget, let f(x, y) be x + y. And sometimes, even in the same paper, I'd see stuff like this: Let f(x, y) be x + y, where x = the width of a widget and y = the price of that widget. Which one is harder to read, or expresses the intent better? If that's what we're down to, then an assignment operator is a trivial exercise. Dan From rosuav at gmail.com Wed Aug 22 15:17:12 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 23 Aug 2018 05:17:12 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> Message-ID: On Thu, Aug 23, 2018 at 3:56 AM, Rhodri James wrote: > On 22/08/18 14:38, Jonathan Fine wrote: >>>>> def fn(): >> >> ... if None: >> ... yield >> ... >>>>> >>>>> list(fn()) # Fails, unless fn is a generator function. >> >> [] Actually, it fails unless fn returns some sort of iterable. >> I think what's happening is this. Even though the None-guarded yield >> has been optimised away, it leaves a residue. Namely, that there's a >> yield in the function. Hence fn() is an iterator. >> >> Having explained the surprise, here's how it can help you. Suppose you >> have a long function body, with a single yield at the bottom. If you >> write like this: >> >> def my_very_long_function_with_one_yield_point(...): >> if None: yield # This is a generator function. >> >> then the next programmer can know immediately that it's a generator >> function. > > > Ew. > > I'd prefer this way of doing it: > > def my_very_long_function_with_one_yield_point(...): > # This is a generator > Or you could use a return type annotation. Why should generator objects be special? A generator function is very similar to a function that returns a list, except that it can yield values as it gets them, rather than batching them up to the end. A generator function is a function which returns an iterable object of the type "generator". How is it different from a function that returns an integer? They return different things. How do you show what a function returns? You annotate it, put it in the docstring, put it in external docs... It's a function. It does something, it returns something. That's it. ChrisA From stephanh42 at gmail.com Wed Aug 22 15:21:38 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Wed, 22 Aug 2018 21:21:38 +0200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> Message-ID: Fwiw, I usually don't do def foo(): if False: yield None But simply: def foo(): return () That the returned iterable is not a generator seldom matters. Stephan Op wo 22 aug. 2018 21:17 schreef Chris Angelico : > On Thu, Aug 23, 2018 at 3:56 AM, Rhodri James > wrote: > > On 22/08/18 14:38, Jonathan Fine wrote: > >>>>> def fn(): > >> > >> ... if None: > >> ... yield > >> ... > >>>>> > >>>>> list(fn()) # Fails, unless fn is a generator function. > >> > >> [] > > Actually, it fails unless fn returns some sort of iterable. > > >> I think what's happening is this. Even though the None-guarded yield > >> has been optimised away, it leaves a residue. Namely, that there's a > >> yield in the function. Hence fn() is an iterator. > >> > >> Having explained the surprise, here's how it can help you. Suppose you > >> have a long function body, with a single yield at the bottom. If you > >> write like this: > >> > >> def my_very_long_function_with_one_yield_point(...): > >> if None: yield # This is a generator function. > >> > >> then the next programmer can know immediately that it's a generator > >> function. > > > > > > Ew. > > > > I'd prefer this way of doing it: > > > > def my_very_long_function_with_one_yield_point(...): > > # This is a generator > > > > Or you could use a return type annotation. > > Why should generator objects be special? A generator function is very > similar to a function that returns a list, except that it can yield > values as it gets them, rather than batching them up to the end. A > generator function is a function which returns an iterable object of > the type "generator". How is it different from a function that returns > an integer? They return different things. How do you show what a > function returns? You annotate it, put it in the docstring, put it in > external docs... It's a function. It does something, it returns > something. That's it. > > ChrisA > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Wed Aug 22 16:24:09 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 22 Aug 2018 16:24:09 -0400 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822174632.GP24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <20180822174632.GP24160@ando.pearwood.info> Message-ID: Oops. I blame the partial editing of copy/padte on doing it on my phone. I meant this, of course: widget.register(callback=spam.eggs) On Wed, Aug 22, 2018, 1:47 PM Steven D'Aprano wrote: > On Wed, Aug 22, 2018 at 01:38:03PM -0400, David Mertz wrote: > > On Wed, Aug 22, 2018, 12:40 PM Steven D'Aprano > wrote: > > > > > I believe that many people have a lot of trouble grasping the concept > of > > > functions as first-class values capable of being passed to other > functions > > > as data... It took me a long time to stop writing code like this: > > > > > > map(lambda x: len(x), sequence) > > > > > > instead of simply map(len, sequence). > > > > > > > That long time is ongoing :-) > > > > You recently wrote in another thread: > > > > widget.register(callback=lambda: spam.eggs()) > > Hah, so I did. > > > > Instead of the slightly faster and definitely more direct: > > > > widget.register(callback=spam.eggs()) > > Except that doesn't work, since you are passing the result of calling > spam.eggs as the callback, instead of spam.eggs itself :-) > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Wed Aug 22 13:44:26 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 22 Aug 2018 13:44:26 -0400 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: This isn't trying to snipe. I have written the exact same unnecessary circumlocution in my own code hundreds of times. Hopefully most of them simplified before release, but I'm sure not all. And I "wrote the book", as one says, _Functional Programming in Python_. Functions as sounds is a powerful but counterintuitive concept. On Wed, Aug 22, 2018, 1:38 PM David Mertz wrote: > On Wed, Aug 22, 2018, 12:40 PM Steven D'Aprano > wrote: > >> I believe that many people have a lot of trouble grasping the concept of >> functions as first-class values capable of being passed to other functions >> as data... It took me a long time to stop writing code like this: >> >> map(lambda x: len(x), sequence) >> >> instead of simply map(len, sequence). >> > > That long time is ongoing :-) > > You recently wrote in another thread: > > widget.register(callback=lambda: spam.eggs()) > > Instead of the slightly faster and definitely more direct: > > widget.register(callback=spam.eggs()) > >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Wed Aug 22 16:32:58 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 22 Aug 2018 16:32:58 -0400 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: ... functions as nouns... On Wed, Aug 22, 2018, 1:44 PM David Mertz wrote: > This isn't trying to snipe. I have written the exact same unnecessary > circumlocution in my own code hundreds of times. Hopefully most of them > simplified before release, but I'm sure not all. And I "wrote the book", as > one says, _Functional Programming in Python_. > > Functions as sounds is a powerful but counterintuitive concept. > > On Wed, Aug 22, 2018, 1:38 PM David Mertz wrote: > >> On Wed, Aug 22, 2018, 12:40 PM Steven D'Aprano >> wrote: >> >>> I believe that many people have a lot of trouble grasping the concept of >>> functions as first-class values capable of being passed to other functions >>> as data... It took me a long time to stop writing code like this: >>> >>> map(lambda x: len(x), sequence) >>> >>> instead of simply map(len, sequence). >>> >> >> That long time is ongoing :-) >> >> You recently wrote in another thread: >> >> widget.register(callback=lambda: spam.eggs()) >> >> Instead of the slightly faster and definitely more direct: >> >> widget.register(callback=spam.eggs()) >> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 22 16:34:07 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 23 Aug 2018 06:34:07 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <20180822174632.GP24160@ando.pearwood.info> Message-ID: On Thu, Aug 23, 2018 at 6:24 AM, David Mertz wrote: > Oops. I blame the partial editing of copy/padte on doing it on my phone. I > meant this, of course: > > widget.register(callback=spam.eggs) This isn't quite the same, incidentally. It's (mostly) equivalent to: widget.register(callback=lambda *a,**kw: spam.eggs(*a,**kw)) I don't know of any situations where you specifically want to mandate that there be no arguments, but it's enough difference that I'd go check the docs before doing the refactor. (This is FREQUENTLY significant in JavaScript, where argument count mismatches are silent. So I'm used to seeing those shim functions.) ChrisA From wes.turner at gmail.com Wed Aug 22 18:01:05 2018 From: wes.turner at gmail.com (Wes Turner) Date: Wed, 22 Aug 2018 18:01:05 -0400 Subject: [Python-ideas] REPL features In-Reply-To: <20180822190836.3ae7d378@fsol> References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> <20180822190836.3ae7d378@fsol> Message-ID: %edit -p > Bring up an editor and execute the resulting code. > -p: this will call the editor with the same data as the previous time it was used, regardless of how long ago (in your current session) it was. https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-edit Something like this that calls $EDITOR with a temp file would be useful in the Python REPL as well. On Wednesday, August 22, 2018, Antoine Pitrou wrote: > On Wed, 22 Aug 2018 09:38:57 -0700 > Chris Barker via Python-ideas > wrote: > > On Tue, Aug 21, 2018 at 3:07 PM, Jonathan Fine > wrote: > > > > > > Maybe this is something Python's REPL should do? > > > > > > Good idea. > > > > > > > I can't find (with very little effort) any documentation of this, but I > > have a vague recollection that the core devs want to keep the built-in > REPL > > really simple -- more advanced features are for third party packages like > > iPython. > > > > I tend to agree -- while something like this: "making the built-in repl > > more friendly t copy-and-paste from examples" seems like a no brainer, > the > > fact is that there are a LOT of features that would make it easier for > > newbies, and in the end, you'd end up with something like iPython. > > > > Honestly, Python does "suffer" a bit when in competition with commercial > > products, in that it is a language (and an implementation of that > > language), not an entire programming environment. So to use it, you need > to > > figure out which Editor or IDE you want to use, what debugger, etc..... > > > > And the REPL, while being pretty key to interactive data analysis, is > not a > > key feature of programming languages in general, even interpreted ones. > > > > So the solution is: use a third party solution for a complete environment > > suitable for your needs. For instance, for people doing data analysis, I > > recommend Anaconda -- then you get iPython and JUpyter (and Spyder) out > of > > the box -- and away we go. > > > > maybe it's worth a note t pyton-dev to confirm my vague impression (or > some > > more thorough googling for previous discussions) -- but I wouldn't put > much > > effort into ideas for the REPL without confirming that the core dev are > > open to the concept. > > To me it sounds fine to improve the REPL. Especially, being able to > paste examples without effort was a sore point for me until I finally > switched to IPython. How much complexity and development work that > would entail I don't know, though :-) > > Regards > > Antoine. > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From wes.turner at gmail.com Wed Aug 22 18:03:22 2018 From: wes.turner at gmail.com (Wes Turner) Date: Wed, 22 Aug 2018 18:03:22 -0400 Subject: [Python-ideas] REPL features In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> <20180822190836.3ae7d378@fsol> Message-ID: %doctest_mode works like the Python REPL (with '>>>' prompts and no pretty printing) https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-doctest_mode On Wednesday, August 22, 2018, Wes Turner wrote: > %edit -p > > > Bring up an editor and execute the resulting code. > > > -p: this will call the editor with the same data as the previous time it > was used, regardless of how long ago (in your current session) it was. > > https://ipython.readthedocs.io/en/stable/interactive/ > magics.html#magic-edit > > Something like this that calls $EDITOR with a temp file would be useful in > the Python REPL as well. > > On Wednesday, August 22, 2018, Antoine Pitrou wrote: > >> On Wed, 22 Aug 2018 09:38:57 -0700 >> Chris Barker via Python-ideas >> wrote: >> > On Tue, Aug 21, 2018 at 3:07 PM, Jonathan Fine >> wrote: >> > >> > > > Maybe this is something Python's REPL should do? >> > > >> > > Good idea. >> > > >> > >> > I can't find (with very little effort) any documentation of this, but I >> > have a vague recollection that the core devs want to keep the built-in >> REPL >> > really simple -- more advanced features are for third party packages >> like >> > iPython. >> > >> > I tend to agree -- while something like this: "making the built-in repl >> > more friendly t copy-and-paste from examples" seems like a no brainer, >> the >> > fact is that there are a LOT of features that would make it easier for >> > newbies, and in the end, you'd end up with something like iPython. >> > >> > Honestly, Python does "suffer" a bit when in competition with commercial >> > products, in that it is a language (and an implementation of that >> > language), not an entire programming environment. So to use it, you >> need to >> > figure out which Editor or IDE you want to use, what debugger, etc..... >> > >> > And the REPL, while being pretty key to interactive data analysis, is >> not a >> > key feature of programming languages in general, even interpreted ones. >> > >> > So the solution is: use a third party solution for a complete >> environment >> > suitable for your needs. For instance, for people doing data analysis, I >> > recommend Anaconda -- then you get iPython and JUpyter (and Spyder) out >> of >> > the box -- and away we go. >> > >> > maybe it's worth a note t pyton-dev to confirm my vague impression (or >> some >> > more thorough googling for previous discussions) -- but I wouldn't put >> much >> > effort into ideas for the REPL without confirming that the core dev are >> > open to the concept. >> >> To me it sounds fine to improve the REPL. Especially, being able to >> paste examples without effort was a sore point for me until I finally >> switched to IPython. How much complexity and development work that >> would entail I don't know, though :-) >> >> Regards >> >> Antoine. >> >> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Wed Aug 22 18:41:14 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 08:41:14 +1000 Subject: [Python-ideas] REPL features In-Reply-To: References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> <20180822190836.3ae7d378@fsol> Message-ID: <20180822224114.GQ24160@ando.pearwood.info> On Wed, Aug 22, 2018 at 06:01:05PM -0400, Wes Turner wrote: > %edit -p > > > Bring up an editor and execute the resulting code. https://code.activestate.com/recipes/578926-call-out-to-an-external-editor/ -- Steve From greg.ewing at canterbury.ac.nz Wed Aug 22 18:44:46 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 23 Aug 2018 10:44:46 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822163417.GK24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: <5B7DE75E.8060701@canterbury.ac.nz> Steven D'Aprano wrote: > Not "process the sorted list", but reify the sort verb into an actual > thing (an object or value) and then process that thing itself. > > This is mind-bending when you think about it, far more mind-blowing than > the normal linguistic process of nouning verbs and verbing nouns. I don't think it's all that much different. Consider the sentences: "Sorting is an interesting operation. It can be done efficiently or inefficiently." Here we temporarily bind the operation "sorting" to the pronoun "it". That's really the extent of processing that we do on functions. We don't actually do anything to the functions, we just give them temporary names. (Unless you go in for bytecode hacking or something, but beginners aren't going to be doing things like that.) > It took me a long time to stop writing code like this: > > map(lambda x: len(x), sequence) > > instead of simply map(len, sequence). Is that because you found the concept itself difficult to grok, or did you just have trouble seeing opportunities to apply it? If you saw map(len, sequence) in someone else's code, did you immediately recognise what it was doing, or did you have to stop and think about it? -- Greg From greg.ewing at canterbury.ac.nz Wed Aug 22 19:02:27 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 23 Aug 2018 11:02:27 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> Message-ID: <5B7DEB83.5000509@canterbury.ac.nz> Rhodri James wrote: > This, by the way, is why think using the same syntax for function > definition and generator definition was a mistake. I think I remember arguing the same thing back when generators were being devised. But there are arguments the other way too. From the outside, a generator is just a function that returns an iterator -- the fact that it works by yielding is an implementation detail. When you write an ordinary function that returns an iterator, the fact that it returns an iterator needs to be conveyed some other way, such as by its name or documentation. if you can do that for an ordinary function, you can do it for a generator just as well -- and probably should, so that you can tell what it returns without having to look at its definition. If the name of the function indicates that it returns an iterator, or there's a docstring at the top what says so, then you won't be surprised when you find a yield in it somewhere. -- Greg From rosuav at gmail.com Wed Aug 22 19:07:13 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 23 Aug 2018 09:07:13 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B7DEB83.5000509@canterbury.ac.nz> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <05b3e040-7cf8-cb9c-5e09-9aeb83ee2961@kynesim.co.uk> <5B7DEB83.5000509@canterbury.ac.nz> Message-ID: On Thu, Aug 23, 2018 at 9:02 AM, Greg Ewing wrote: > Rhodri James wrote: >> >> This, by the way, is why think using the same syntax for function >> definition and generator definition was a mistake. > > > I think I remember arguing the same thing back when generators > were being devised. > > But there are arguments the other way too. From the outside, > a generator is just a function that returns an iterator -- > the fact that it works by yielding is an implementation detail. > > When you write an ordinary function that returns an iterator, the > fact that it returns an iterator needs to be conveyed some other > way, such as by its name or documentation. if you can do that > for an ordinary function, you can do it for a generator just as > well -- and probably should, so that you can tell what it returns > without having to look at its definition. > > If the name of the function indicates that it returns an iterator, > or there's a docstring at the top what says so, then you won't > be surprised when you find a yield in it somewhere. def gen1(x): return iter(range(x)) def gen2(x): i = 0 while i < x: yield i i += 1 def gen3(x): if i % 2: return gen1(x) else: return gen2(x) Which of these three are generator functions? Technically only one of them is... but how would it make any difference? ChrisA From greg.ewing at canterbury.ac.nz Wed Aug 22 19:17:20 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 23 Aug 2018 11:17:20 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: <5B7DEF00.3040600@canterbury.ac.nz> Stephan Houben wrote: > Church's lambda notation was the first way to write > down a function without naming it, in the 1930's. That's debatable. It could be argued that calculus makes use of anonymous functions, e.g. the expression d/dx (x**2 + 2*x - 3) describes a function of x without giving a name to it. This means that > these mathematical developments haven't yet entered high > school mathematics is not entirely true -- anyone who's studied calculus has been exposed to the concept of an anonymous function, although it probably hasn't been explicitly described in those terms. -- Greg From abedillon at gmail.com Wed Aug 22 19:28:45 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 22 Aug 2018 18:28:45 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822174406.GO24160@ando.pearwood.info> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <20180822174406.GO24160@ando.pearwood.info> Message-ID: Replying out of order: [Steven D'Aprano] > Under your proposal, that becomes: > def bench(name, cleanup=None with ???, *, seconds=1, repeat=3): > except I'm not really sure what goes in the ??? for an empty parameter > list. I know I tend to write long-winded responses, but please read them fully before replying. I covered this. [Steven D'Aprano] > But whatever it is, do you still think it is obvious that people > will recognise "None" to mean a function without having to backtrack? It's not clear what you mean by backtracking at this point. cleanup=None with() requires no more backtracking than any other compound expression. cleanup=children.oldest().room doesn't tell you what kind of object is being assigned to cleanup. Is it a function? Who knows? Even if you know what 'children' is and what the 'oldest' method returns, you still don't know what's being assigned to cleanup without reading the entire expression. There has never been a guarantee that expressions evaluate left to right simply by virtue of the fact that an order of operations exists. The LL(1) parser limits parsing complexity to expressions which require at most one token look-ahead. Usually (I'll come back to this) that isn't hard for humans who process text in chunks of multiple tokens at a time. [Steven D'Aprano] > And from the threading tests: > t = threading.Thread(target=lambda: None) t = threading.Thread(target=None with()) seems pretty straight-forward to me. [Steven D'Aprano] > sm = difflib.SequenceMatcher(isjunk=x == ' ' with x, ...) > The expression x==' ' doesn't look like a function to me. You don't think that perhaps that's because it's brand new syntax? x=='' doesn't look like a function because it's not a function. You could play the same game with literally any compound expression: >>> func = ", ".join ", " doesn't look like a function to me! [Steven D'Aprano] > > Ideally, we could move that noise out of the way so that the intent is > more > > clearly expressed: > So you say. > I say it isn't noise, and if you ask me to express my intent, I'll state > that it is a function first and at the beginning of the expression, not > the end. Don't you think that depends on the situation at all? Don't you think there are cases where the fact that you're passing a function and the call signature of said function are exceedingly clear from context? ui_element.on_mousover( with event) We already have a way to declare a function signature first. If you think it's paramount, then just def it. If you honestly don't understand my position at all. If it's always a surprise to you that ", ".join() takes an iterable of strings or that sorted takes a key-function that takes element from the iterable being sorted, or that on_mousover takes a function that takes an event object etc. etc. etc. then I guess I've never met anyone quite like you. I don't know how to communicate my point of view any better than I already have. [Steven D'Aprano] > You are judging that from the perspective of someone whose native > language makes it easy to say "sorted by foo" (for some value of foo). This argument is such a tiring distraction. Please stop. If it's all just random symbols to some non-english speaker, then It doesn't matter either way to them. They can still deal with tokens in the same way as the LL(1) parser. Only one look-ahead. That's not at all how the world works, but I don't have the energy to get into that discussion right now. I've been writing a veritable novel on my views on lambda for over a week now and people keep re-tredding the same ground. [Steven D'Aprano] > We shouldn't judge syntax proposals just on the cases that are carefully > chosen to showcase them at their best. Especially not trivial cases. We can judge it by examining cases where it might be problematic, but there's no way to keep people from abusing coding constructs to produce unreadable code, so just throwing out random chunks of code like a.b[c:d]-e**f(g, h=i) + {j & k, l*(m-n(o,p))} with e, k then saying "looks bad to me" offers no insight into the pros and cons of the proposal. Well, yeah. It looks bad because it's terrible code. It feels like you're not even trying to understand the basic premise of my position. Otherwise, I would be delighted to move past the simplified examples and on to more complex and probably troublesome counter examples. Hell, we can talk about how this would effect blind space aliens who can only hear ultra-sonic chirps and are essentially incapable of learning English after we get past this roadblock... -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Wed Aug 22 19:38:04 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 22 Aug 2018 18:38:04 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <23420.55144.2677.692751@turnbull.sk.tsukuba.ac.jp> References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <23420.55144.2677.692751@turnbull.sk.tsukuba.ac.jp> Message-ID: Thanks, Stephen. That's interesting. So the parser can see one token past, for instance; what would be the end of an expression, see "if", and know to expand the AST? -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-ideas at mgmiller.net Wed Aug 22 19:37:54 2018 From: python-ideas at mgmiller.net (Mike Miller) Date: Wed, 22 Aug 2018 16:37:54 -0700 Subject: [Python-ideas] REPL features In-Reply-To: <20180822190836.3ae7d378@fsol> References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> <20180822190836.3ae7d378@fsol> Message-ID: <3032fd0e-020c-87ee-dfba-b106fe3c2e8d@mgmiller.net> On 2018-08-22 10:08, Antoine Pitrou wrote: > On Wed, 22 Aug 2018 09:38:57 -0700 > Chris Barker via Python-ideas >> On Tue, Aug 21, 2018 at 3:07 PM, Jonathan Fine wrote: >> >>>> Maybe this is something Python's REPL should do? > To me it sounds fine to improve the REPL. Especially, being able to > paste examples without effort was a sore point for me until I finally > switched to IPython. How much complexity and development work that > would entail I don't know, though :-) > > Regards > > Antoine. iPython brings in a lot of functionality, perhaps too much. Would prefer something more focused like bpython or ptpython. -Mike From python at mrabarnett.plus.com Wed Aug 22 20:04:29 2018 From: python at mrabarnett.plus.com (MRAB) Date: Thu, 23 Aug 2018 01:04:29 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B7DE75E.8060701@canterbury.ac.nz> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7DE75E.8060701@canterbury.ac.nz> Message-ID: <9afa2cf2-2443-8428-501c-e90ec0ef221f@mrabarnett.plus.com> On 2018-08-22 23:44, Greg Ewing wrote: > Steven D'Aprano wrote: >> Not "process the sorted list", but reify the sort verb into an actual >> thing (an object or value) and then process that thing itself. >> >> This is mind-bending when you think about it, far more mind-blowing than >> the normal linguistic process of nouning verbs and verbing nouns. > > I don't think it's all that much different. Consider the > sentences: > > "Sorting is an interesting operation. It can be done > efficiently or inefficiently." > > Here we temporarily bind the operation "sorting" to > the pronoun "it". That's really the extent of processing > that we do on functions. We don't actually do anything > to the functions, we just give them temporary names. > It's the difference between a gerund (noun) and a gerundive (adjective). In English they happen to have the same form: ~ing. In other languages, they don't. > (Unless you go in for bytecode hacking or something, > but beginners aren't going to be doing things like > that.) > >> It took me a long time to stop writing code like this: >> >> map(lambda x: len(x), sequence) >> >> instead of simply map(len, sequence). > > Is that because you found the concept itself difficult > to grok, or did you just have trouble seeing opportunities > to apply it? > > If you saw map(len, sequence) in someone else's code, > did you immediately recognise what it was doing, or did > you have to stop and think about it? > From abedillon at gmail.com Wed Aug 22 20:44:55 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 22 Aug 2018 19:44:55 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180822163417.GK24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: [Steven D'Aprano] > As educators, if we fail to teach the technical language of a field to > our students, we are failing to prepare those students to enter that > field. Technical jargon is the language of the field. It's not the responsibility of the tool to teach. My socket wrench doesn't have the history of socket wrenches inscribed on it, nor does it have any description of the different kinds of nuts and bolts. That's called the Single Responsibility Principal or SRP for short. Your job may be to educate, but that's not Python's job. [Steven D'Aprano] > We should not focus too heavily on the earliest and most ignorant stage > of people's programming life. The problem goes beyond just learning the term lambda, it can increase mental load on an already mentally demanding activity to have to translate an unfamiliar word every time you see it. It's lack of relation to anything else makes it hard to remember and hard to recall later. I've also argued that the very form of lambda expressions is noisier than it otherwise needs to be. It's not like noise is only distracting to novice developers. [Steven D'Aprano] > That stage makes up probably less than 10% > of their life as a programmer. My argument has never been about the high magnitude of the opportunity cost, just that there is one (IMHO) compared to a less jargon option. Better is better. period. Even if only improves the first 10% of your programming career. That's why I've said I don't ever think this discussion will lead to action. [Steven D'Aprano] > Python is a general purpose programming > language and we shouldn't shy from the appropriate use of technical > terms in the documentation and the language itself. A Caterpillar Bulldozer is a professional piece of equipment. That doesn't mean they throw out basic tenants of good user interface design and take it upon themselves to teach the operator construction jargon through the interface. They still find it's better to use a red break light symbol with the aim of clearly communicating to non-experts. Just like a child's go kart! Even Python didn't find it necessary to teach me the word "ternary" for ternary expression. [Steven D'Aprano] > And the experience of educators like Chris teaching Javascript suggests > strongly that no, it doesn't, since Javascript learners have just as > much trouble learning the concept of "function" as Python learners have > with "lambda". I don't think that one person's anecdotal evidence could be considered "strong" in the face of scientific studies. Especially when it's become clear that Chris was referring to a broad category of subjects that are only tangentially related to lambda expressions. [Steven D'Aprano] > Chris' conclusion is that anonymous functions are inherently hard for > many beginners to learn, regardless of whether the syntax is called > "lambda" or "function". That's not been my experience. [Steven D'Aprano] > I believe that many people have a lot of trouble grasping the concept of > functions as first-class values capable of being passed to other > functions as data. It requires a major rethink of the way we think of > functions. Those topics have nothing to do with lambda expressions. You can demonstrate them without ever writing a lambda expression. The difficulty of those concepts doesn't inform the choosing of the name. You might as well name it "schubalu" and when I say "that's unnecessarily confusing" just say "well it's easier to learn the word 'schubalu' than it is to learn how Bloom Filters work!" Yup. I can't argue with that. I guess we should stick with "schubalu"... [Steven D'Aprano] > Aside from having to learn the correct spelling ("lamdba"?) it > was never the *name* that gave me trouble. Maybe not for you, but it's fresh enough in my mind that the name itself caused confusion. I know it seems minor, but back in the 'partial' thread, I was literally just talking about the name: lambda. Nothing else matters because it's all invariant. Callbacks will still be hard to learn. Functions as first class objects will still be confusing. All I'm talking about is a missed opportunity to choose a moderately better name. Just like function.partial vs. function.given. I didn't think my opinion would spawn 6 threads and hours of nit-picking. None of your discussion about the difficulty of functional programming informs the value of jargon over less jargon. When is it better to favor more common language, if ever? [Steven D'Aprano] > that cost is paid for, with interest, later, > as a journeyman or journeywoman programmer. Yeah, or never. My friend used to say he was in IT, then it was Dev Ops, now there's a new term. Or it may be that everyone knows what you mean when you say "anonymous function" and you didn't earn any interest for learning "lambda". After I graduated with my EE degree, I bought a bunch of vocabulary flash cards so that I could take the GRE and go to grad school. I remember wondering, "why the hell does every flash-card set have 'numismatics' in it?! I can never remember that damn word!" now I know it. It's never paid interest... [Steven D'Aprano] > Nevertheless, it is important that I teach them the technical terms too. I find that beyond the basics: class, object, function, variable, argument, parameter, etc. Having students memorize jargon has limited value. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 22 20:56:50 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 23 Aug 2018 10:56:50 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: On Thu, Aug 23, 2018 at 10:44 AM, Abe Dillon wrote: > The problem goes beyond just learning the term lambda, it can increase > mental load on an already mentally demanding activity to have to translate > an unfamiliar word every time you see it. It's lack of relation to anything > else makes it hard to remember and hard to recall later. If the concept is utterly unfamiliar and the word is familiar, it creates a different problem: the false parallel. Let's suppose that, instead of calling them "lambda expressions", we call them "bacon expressions". Great! Lots of people know what bacon is. Is that an improvement? Definitely not. Some people love bacon and will wonder what anonymous functions have to do with their favourite food; others will wonder whether it's okay for a devout Jewish or Moslem person to use them. Technically this is true of "lambda" too, but for those who know Greek, it's like calling something an "S-expression", which is fairly obviously an abbreviation for something. ("Symbolic expression", I think? Someone might correct me there.) > I've also argued that the very form of lambda expressions is noisier than it > otherwise needs to be. It's not like noise is only distracting to novice > developers. Yes, you've asserted it. We've disputed it. You have yet to provide real evidence. > A Caterpillar Bulldozer is a professional piece of equipment. That doesn't > mean they throw out basic tenants of good user interface design and take it > upon themselves to teach the operator construction jargon through the > interface. They still find it's better to use a red break light symbol with > the aim of clearly communicating to non-experts. Just like a child's go > kart! Even Python didn't find it necessary to teach me the word "ternary" > for ternary expression. No, it probably called it an "if-expression" or "conditional expression" or something. "Ternary" just means it has three operands, so Python also has another very common ternary expression, namely the bounding: "5 < x < 10". >> And the experience of educators like Chris teaching Javascript suggests >> strongly that no, it doesn't, since Javascript learners have just as >> much trouble learning the concept of "function" as Python learners have >> with "lambda". > > > I don't think that one person's anecdotal evidence could be considered > "strong" in the face of scientific studies. > Especially when it's become clear that Chris was referring to a broad > category of subjects that are only tangentially related to lambda > expressions. What broad category of subjects? >> Chris' conclusion is that anonymous functions are inherently hard for >> many beginners to learn, regardless of whether the syntax is called >> "lambda" or "function". > > That's not been my experience. Okay! What's been your experience? Can you show us two comparable situations, one where you taught lambda functions in Python, and the other when you taught anonymous functions but without the word "lambda", and can demonstrate that one is harder than the other? My experience is that *highly intelligent* adult students, who have mastered many other concepts very rapidly, frequently have trouble with: * Asynchronous programming * Anonymous functions * The difference between serverside and clientside validation * How to debug code * Recursion >> I believe that many people have a lot of trouble grasping the concept of >> functions as first-class values capable of being passed to other >> functions as data. It requires a major rethink of the way we think of >> functions. > > > Those topics have nothing to do with lambda expressions. You can demonstrate > them without ever writing a lambda expression. > The difficulty of those concepts doesn't inform the choosing of the name. > You might as well name it "schubalu" and when I say "that's unnecessarily > confusing" just say "well it's easier to learn the word 'schubalu' than it > is to learn how Bloom Filters work!" > > Yup. I can't argue with that. I guess we should stick with "schubalu"... > > [Steven D'Aprano] >> >> Aside from having to learn the correct spelling ("lamdba"?) it >> was never the *name* that gave me trouble. > > > Maybe not for you, but it's fresh enough in my mind that the name itself > caused confusion. > I know it seems minor, but back in the 'partial' thread, I was literally > just talking about the name: lambda. > > Nothing else matters because it's all invariant. Callbacks will still be > hard to learn. Functions as first class objects will still be confusing. All > I'm talking about is a missed opportunity to choose a moderately better > name. Just like function.partial vs. function.given. I didn't think my > opinion would spawn 6 threads and hours of nit-picking. > > None of your discussion about the difficulty of functional programming > informs the value of jargon over less jargon. When is it better to favor > more common language, if ever? > > [Steven D'Aprano] >> >> that cost is paid for, with interest, later, >> as a journeyman or journeywoman programmer. > > > Yeah, or never. My friend used to say he was in IT, then it was Dev Ops, now > there's a new term. Or it may be that everyone knows what you mean when you > say "anonymous function" and you didn't earn any interest for learning > "lambda". After I graduated with my EE degree, I bought a bunch of > vocabulary flash cards so that I could take the GRE and go to grad school. I > remember wondering, "why the hell does every flash-card set have > 'numismatics' in it?! I can never remember that damn word!" now I know it. > It's never paid interest... > > [Steven D'Aprano] >> >> Nevertheless, it is important that I teach them the technical terms too. > > > I find that beyond the basics: class, object, function, variable, argument, > parameter, etc. > Having students memorize jargon has limited value. > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > From mertz at gnosis.cx Wed Aug 22 21:18:19 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 22 Aug 2018 21:18:19 -0400 Subject: [Python-ideas] REPL features In-Reply-To: <3032fd0e-020c-87ee-dfba-b106fe3c2e8d@mgmiller.net> References: <932E0A54-F4B0-4B2D-989E-7DDE1A2E6F2D@barrys-emacs.org> <5B7C89E9.6090600@canterbury.ac.nz> <20180822190836.3ae7d378@fsol> <3032fd0e-020c-87ee-dfba-b106fe3c2e8d@mgmiller.net> Message-ID: On Wed, Aug 22, 2018 at 7:47 PM Mike Miller wrote: > >> On Tue, Aug 21, 2018 at 3:07 PM, Jonathan Fine > wrote: > >>>> Maybe this is something Python's REPL should do? > iPython brings in a lot of functionality, perhaps too much. > Would prefer something more focused like bpython or ptpython. > Happily, you know where to get IPython, and BPython, and PTPython. Different users have different desires for an enhanced REPL, and different good, free software, projects exist. I would tend to oppose most of these "fixes" to the basic Python REPL as "feature creep." Full featured interactive shells are great. I use IPython and Jupyter dozens of times every day myself. I love those. But they make specific decisions on what and how to enhance things, and have a huge range of configuration options. The `python` REPL should really be just good enough to use, and allow other projects to provide the richer experience (and to maintain all the code associated with making them powerful and flexible). Obviously, that's not saying categorically that "nothing can ever change" in the Python REPL. But most things I would lean against adding. It does basically as much as it should, with no more code than is necessary to do that. -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Wed Aug 22 21:59:33 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 22 Aug 2018 20:59:33 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: [Chris Angelico] > If the concept is utterly unfamiliar and the word is familiar, it > creates a different problem: the false parallel. Let's suppose that, > instead of calling them "lambda expressions", we call them "bacon > expressions". Or maybe "curry expressions!"... (I really hate that jargon too) I think this is a pretty ridiculous take on my argument. [Chris Angelico] > Technically this is true of "lambda" too, but for those who > know Greek, it's like calling something an "S-expression", which is > fairly obviously an abbreviation for something. ("Symbolic > expression", I think? Someone might correct me there.) No. The lambda in lambda calculus was chosen arbitrarily. It has no deeper meaning. According to Dana Scott, who was a Ph. D student under Alonzo Church: The choice was "eeny, meeny, miny, moe" [Chris Angelico] > > I've also argued that the very form of lambda expressions is noisier > than it > > otherwise needs to be. It's not like noise is only distracting to novice > > developers. > Yes, you've asserted it. We've disputed it. You have yet to provide > real evidence. Why isn't my example comparing the pseudo code: hand = sorted(cards, by=card.suit) to the actual code: hand = sorted(cards, key=lambda card: card.suit) suitable to at least demonstrate the basic idea? I can show you the noise right here: hand = sorted(cards, ke#=#############card.suit) I could come up with a hundred such examples if you need more "evidence" of my point, but I'm not interested in nit picking how one should properly represent or sort cards. I'm also not interested in discussing how I need to check my privilege because my proposal might not help Hellen Keller write better code. Maybe I should put you on the defensive and make you prove that it's always best to inject as much jargon as possible into Python and that there's no better form of lambda. We could be discussing this idea more deeply. Jonathan Fine pointed out some interesting ideas about this. But mostly you and D'Aprano seem interested in being contrarians and denying that there might be any hint of legitimacy to my point of view. I don't think it's unassailable, but it has nothing to do with the proper way to represent a wild-card in a poker simulation. [Chris Angelico] > it probably called it an "if-expression" or "conditional > expression" or something. I don't know how many times I have to reiterate this: I'm not talking about what humans call it. I'm talking about how it's expressed in code. [Chris Angelico] > What broad category of subjects? * Functions as first-class objects * Callbacks & Event Handlers * Passing functions as arguments * the "semantics" as you put it In other-words, when you said: [Chris Angelico] > Whether you spell it "function(arg) {...}" or "lambda arg: ...", it's > the semantics that are hardest to learn. Those are orthogonal concerns! All else being equal, a descriptive name is better than a less descriptive alternative. It might not be on the same scale as the confusion caused by semantics, but it also doesn't have anything to do with the confusion caused by semantics. function.partial and function.given have the exact same semantics! We were literally only talking about names. Like I've said to D'Aprano: It may be way harder to drive a car than to buy windshield-wiper-solution for a car, but I can still prefer the name "windshield-wiper-solution" to "zeta" because calling it "zeta" just causes unnecessary confusion. Will it cause mass panic? Will it cause more car accidents? No. But, my goodness, you guys seem to want to talk a lot about that other stuff in order to convince me I'm wrong that "windshield-wiper-fluid" should not be called "zeta". I can't go two replies without you bringing it back up. It's really not worth the amount of words I've put into defending what I thought was a pretty reasonable POV. [Chris Angelico] > Okay! What's been your experience? That students have trouble realizing that def f(x): return x*x is exactly the same as: f = lambda x: x*x yet have very little trouble learning how to write a function in JavaScript: f = function(x) { return x*x } Literally just that. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Wed Aug 22 22:02:30 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 23 Aug 2018 12:02:30 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: On Thu, Aug 23, 2018 at 11:59 AM, Abe Dillon wrote: > [Chris Angelico] >> >> > I've also argued that the very form of lambda expressions is noisier >> > than it >> > otherwise needs to be. It's not like noise is only distracting to novice >> > developers. >> Yes, you've asserted it. We've disputed it. You have yet to provide >> real evidence. > > > Why isn't my example comparing the pseudo code: > > hand = sorted(cards, by=card.suit) > > to the actual code: > > hand = sorted(cards, key=lambda card: card.suit) > > suitable to at least demonstrate the basic idea? Because your form cannot possibly work without some additional information. How is "by=card.suit" supposed to ACTUALLY WORK? As soon as you make it work, you create extra noise all of your own - yaknow, like saying that "card" is a parameter to the function. So maybe it ain't just noise. I'm done arguing. You aren't listening. ChrisA From abedillon at gmail.com Wed Aug 22 22:10:23 2018 From: abedillon at gmail.com (Abe Dillon) Date: Wed, 22 Aug 2018 21:10:23 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: [Chris Angelico] > Because your form cannot possibly work without some additional > information. That isn't my form. That's PSEUDO CODE. Just like I wrote above it. You're the one who's not listening. The alternative I've suggested, for the thousanth time, is: hand = sorted(cards, by=card.suit with card) or hand = sorted(cards, by=card.suit with(card)) The noise compared to the PSEUDO CODE looks like this: hand = sorted(cards, by=card.suit ##########) Which, to me, is preferable to: hand = sorted(cards, ke#=#############card.suit) You need me to type that out a few dozen more times? -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Wed Aug 22 23:12:30 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 23 Aug 2018 15:12:30 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: <5B7E261E.9030209@canterbury.ac.nz> Abe Dillon wrote: > They still find it's better to use a red break > light symbol with the aim of clearly communicating to non-experts. The handbrake warning light on my dashboard has a symbol that represents a brake drum and a pair of brake shoes, and the word "BRAKE" written underneath it. That's a technical term and an implementation detail, right there in the user interface! (Never mind that the implentation detail isn't accurate, because the car actually has disc brakes...) -- Greg From steve at pearwood.info Thu Aug 23 01:19:46 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 15:19:46 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B7E261E.9030209@canterbury.ac.nz> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7E261E.9030209@canterbury.ac.nz> Message-ID: <20180823051945.GR24160@ando.pearwood.info> On Thu, Aug 23, 2018 at 03:12:30PM +1200, Greg Ewing wrote: > Abe Dillon wrote: > >They still find it's better to use a red break > >light symbol with the aim of clearly communicating to non-experts. > > The handbrake warning light on my dashboard has a symbol > that represents a brake drum and a pair of brake shoes, > and the word "BRAKE" written underneath it. That's a > technical term and an implementation detail, right there > in the user interface! Indeed. I wonder whether Abe drives, and if he does, whether he has read the owner's manual. They are typically *full* of jargon. Similarly for bulldozers. Here's a short instructional video: https://www.youtube.com/watch?v=p2mh6kUuedk Many of the controls are described in common terms (why would they need jargon terms for "forward", "reverse", "left", "right"?), but they also mention specialist jargon like "throttle" and "decelerator". A bulldozer has perhaps as many as a dozen critical functions: move forward, reverse, lift the blade, etc, which can only combine in a rather limited number of ways. The user-interface is designed for real-time manual operation. Programming languages have multiple dozen features, hundreds if you include Python's std lib, which combine in a near-infinite number of ways. Programming is a batch operation: while a bulldozer operator has to react on the spot, the programmer typical gets to think ahead, write some code, think some more, write a bit more, do some incremental tests, write some more code, do some research, write a bit more code, think some more etc in dozens or hundreds of iterations before actually running the code in production. I don't think its productive to compare programming to driving a bulldozer. A better analogy would be sound mixing: https://videohive.net/item/sound-mixer-2/2244660 https://www.soundonsound.com/sound-advice/glossary-technical-terms -- Steve From greg.ewing at canterbury.ac.nz Thu Aug 23 01:55:13 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 23 Aug 2018 17:55:13 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: <5B7E4C41.4060306@canterbury.ac.nz> Chris Angelico wrote: > for those who > know Greek, it's like calling something an "S-expression", which is > fairly obviously an abbreviation for something. ("Symbolic > expression", I think? Someone might correct me there.) Yes, except that lambda is an even more arbitrary choice of letter -- as far as I know, it doesn't stand for anything. The story goes that, in his handwritten notes, Church used something like a caret or circumflex. When his work was published, the typesetter either misread it as a lambda or subsituted a lambda because it was the closest thing he had in his font, and from there on it stuck. > Abe Dillon wrote: >>I've also argued that the very form of lambda expressions is noisier than it >>otherwise needs to be. It's not like noise is only distracting to novice >>developers. If we wanted to be true to the original we should call them "caret expressions" and write ^(x, y): x + y Nice and quiet! -- Greg From abedillon at gmail.com Thu Aug 23 01:58:30 2018 From: abedillon at gmail.com (Abe Dillon) Date: Thu, 23 Aug 2018 00:58:30 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180823051945.GR24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7E261E.9030209@canterbury.ac.nz> <20180823051945.GR24160@ando.pearwood.info> Message-ID: [Steven D'Aprano] > Indeed. I wonder whether Abe drives, and if he does, whether he has read > the owner's manual. They are typically *full* of jargon. Do you still not understand the difference between documentation and interface? You seem to not even acknowledge that there's a difference between how one talks about a tool and how one uses said tool. Typically, the main concern of someone making a complex tool like a bulldozed is that the interface is as clear, accessible, language agnostic, simple, and utilitarian as possible. The reverse noise is a simple beep, not a voice saying "throttle set to reverse position". You use levers and buttons typically labeled with symbols rather than words. There are reasons why designers favor symbols and indicator lights over technical jargon. It has nothing to do with kiddie design vs. professional tools. It has everything to do with favoring the most intuitive interface possible to get work done. I honestly don't know what to say anymore. You keep conflating the syntax of Python with documentation and human-to-human communication. It's incredible. I don't know how many times I need to point out the difference. Do you think python's conditional operator should be like this: z = ConditionalOperator(predicate: x==y?, affirmative: x*2, negative: None) ? What can I do to illustrate that there is, indeed, a difference between what people call something and how someone uses a tool? I'm at a loss for words. On Thu, Aug 23, 2018 at 12:21 AM Steven D'Aprano wrote: > On Thu, Aug 23, 2018 at 03:12:30PM +1200, Greg Ewing wrote: > > Abe Dillon wrote: > > >They still find it's better to use a red break > > >light symbol with the aim of clearly communicating to non-experts. > > > > The handbrake warning light on my dashboard has a symbol > > that represents a brake drum and a pair of brake shoes, > > and the word "BRAKE" written underneath it. That's a > > technical term and an implementation detail, right there > > in the user interface! > > Indeed. I wonder whether Abe drives, and if he does, whether he has read > the owner's manual. They are typically *full* of jargon. > > Similarly for bulldozers. Here's a short instructional video: > > https://www.youtube.com/watch?v=p2mh6kUuedk > > Many of the controls are described in common terms (why would they need > jargon terms for "forward", "reverse", "left", "right"?), but they also > mention specialist jargon like "throttle" and "decelerator". > > A bulldozer has perhaps as many as a dozen critical functions: move > forward, reverse, lift the blade, etc, which can only combine in a > rather limited number of ways. The user-interface is designed for > real-time manual operation. > > Programming languages have multiple dozen features, hundreds if you > include Python's std lib, which combine in a near-infinite number of > ways. Programming is a batch operation: while a bulldozer operator has > to react on the spot, the programmer typical gets to think ahead, write > some code, think some more, write a bit more, do some incremental tests, > write some more code, do some research, write a bit more code, think > some more etc in dozens or hundreds of iterations before actually > running the code in production. > > I don't think its productive to compare programming to driving a > bulldozer. A better analogy would be sound mixing: > > https://videohive.net/item/sound-mixer-2/2244660 > > https://www.soundonsound.com/sound-advice/glossary-technical-terms > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Thu Aug 23 02:01:42 2018 From: abedillon at gmail.com (Abe Dillon) Date: Thu, 23 Aug 2018 01:01:42 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B7E4C41.4060306@canterbury.ac.nz> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7E4C41.4060306@canterbury.ac.nz> Message-ID: [Greg Ewing] > If we wanted to be true to the original we should call > them "caret expressions" and write > ^(x, y): x + y > Nice and quiet! I actually... kinda like that. It doesn't really check any of my boxes, but it's better than 'lambda'. On Thu, Aug 23, 2018 at 12:55 AM Greg Ewing wrote: > Chris Angelico wrote: > > for those who > > know Greek, it's like calling something an "S-expression", which is > > fairly obviously an abbreviation for something. ("Symbolic > > expression", I think? Someone might correct me there.) > > Yes, except that lambda is an even more arbitrary choice of > letter -- as far as I know, it doesn't stand for anything. > > The story goes that, in his handwritten notes, Church used > something like a caret or circumflex. When his work was > published, the typesetter either misread it as a lambda > or subsituted a lambda because it was the closest thing > he had in his font, and from there on it stuck. > > > Abe Dillon wrote: > >>I've also argued that the very form of lambda expressions is noisier > than it > >>otherwise needs to be. It's not like noise is only distracting to novice > >>developers. > > If we wanted to be true to the original we should call > them "caret expressions" and write > > ^(x, y): x + y > > Nice and quiet! > > -- > Greg > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From j.van.dorp at deonet.nl Thu Aug 23 03:04:46 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Thu, 23 Aug 2018 09:04:46 +0200 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: <475de31f-1ed6-bdaa-b667-a69fdc754629@kynesim.co.uk> References: <20180822015502.GE24160@ando.pearwood.info> <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> <475de31f-1ed6-bdaa-b667-a69fdc754629@kynesim.co.uk> Message-ID: I think it would have been better to use def from the start instead of lambda. The only thing JS does right is using the same "function" keyword for both of these. However, changing it now doesn't seem that important to me. (And I've used lambda's as default argument - I was moving data from one database to another, and wanted a generic method to switch out column names that defaulted to the same header. So it became a lambda x:x function by default, but you can provide any function that takes and returns a string and change the column names. This was last week.) And lets be real - adding a new keyword is something to be done extremely sparingly. lambda could have been avoided by re-using def. And no, it being the same keyword is an advantage, as they do the exact same - they create a function. It's the same reason as we use if condition: -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephanh42 at gmail.com Thu Aug 23 03:40:15 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Thu, 23 Aug 2018 09:40:15 +0200 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> <475de31f-1ed6-bdaa-b667-a69fdc754629@kynesim.co.uk> Message-ID: Op do 23 aug. 2018 09:06 schreef Jacco van Dorp : > I think it would have been better to use def from the start instead of > lambda. The only thing JS does right is using the same "function" keyword > for both of these. > Seriously? Consider how the following code function f() { return 42; } may or may not bind the function to f, depending on if it appears in expression or statement context. Just Google and find all the newbies who get confused about this. And the proposed def syntax is almost as terrible: def greet: print("hello'') This would then be legal, and leave the newbie confused why greet remains undefined. Please don't repurpose def. Repurposing for and if inside comprehensions is already confusing to newbies. Stephan > > However, changing it now doesn't seem that important to me. > > (And I've used lambda's as default argument - I was moving data from one > database to another, and wanted a generic method to switch out column names > that defaulted to the same header. So it became a lambda x:x function by > default, but you can provide any function that takes and returns a string > and change the column names. This was last week.) > > And lets be real - adding a new keyword is something to be done extremely > sparingly. lambda could have been avoided by re-using def. And no, it being > the same keyword is an advantage, as they do the exact same - they create a > function. It's the same reason as we use if condition: > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From j.van.dorp at deonet.nl Thu Aug 23 04:23:21 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Thu, 23 Aug 2018 10:23:21 +0200 Subject: [Python-ideas] A simple proposal concerning lambda In-Reply-To: References: <20180822015502.GE24160@ando.pearwood.info> <36923708-0fc4-f4cc-85e9-6beb488bdf64@mgmiller.net> <475de31f-1ed6-bdaa-b667-a69fdc754629@kynesim.co.uk> Message-ID: Op do 23 aug. 2018 om 09:40 schreef Stephan Houben : > Op do 23 aug. 2018 09:06 schreef Jacco van Dorp : > >> I think it would have been better to use def from the start instead of >> lambda. The only thing JS does right is using the same "function" keyword >> for both of these. >> > > > Seriously? > > Consider how the following code > > function f() { return 42; } > > may or may not bind the function to f, depending on if it appears in > expression or statement context. Just Google and find all the newbies who > get confused about this. > > And the proposed def syntax is almost as terrible: > > def greet: print("hello'') > > This would then be legal, and leave the newbie confused why greet remains > undefined. > > Please don't repurpose def. > Repurposing for and if inside comprehensions is already confusing to > newbies. > The only thing I seriously think they did better is exact keyword choice. Nothing else. So an expression def would still be def :, like it is with lambda now. JS remains a clusterfuck of terrible choices, as you can tell by the existence of http://www.jsfuck.com/ . An alternative livible solution to your def greet would be to require parens around the parameter list. Nobody would take the following for a statement: def (greet):print("hello") (Also, you could conceivably drop the colon, which might make some people happy who care about the 1001 uses that a colon has in python. ) I also believe I explicitly advocated against making changes now, just saying that it might have been a better idea at some point in the past. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Thu Aug 23 07:11:16 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 21:11:16 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <20180822174406.GO24160@ando.pearwood.info> Message-ID: <20180823111116.GS24160@ando.pearwood.info> On Wed, Aug 22, 2018 at 06:28:45PM -0500, Abe Dillon wrote: [Steve -- that's me] > > But whatever it is, do you still think it is obvious that people > > will recognise "None" to mean a function without having to backtrack? > > > It's not clear what you mean by backtracking at this point. Yes, I accept that's not clear. Sorry. What I mean is that moment of having to reinterpret what you're reading. I start to read code, see that its assigning None to a parameter, and then a moment later have to re-interpret what we just read: None is not the argument, but the body of the function which is the argument. In linguistics that sort of thing is called a "garden path sentence" and research demonstrates readers take longer to comprehend them than sentences which don't require backtracking (re-interpretation). https://en.wikipedia.org/wiki/Garden-path_sentence Sometimes that's a good thing, if you're making a joke. But in general, they're not great for readability. Since your argument hinges on readability, that's a problem. > cleanup=None > with() requires no more backtracking than any other compound expression. > cleanup=children.oldest().room doesn't tell you what kind of object is > being assigned to cleanup. Is it a function? Who knows? Even if you know > what > 'children' is and what the 'oldest' method returns, you still don't know > what's being assigned to cleanup without reading the entire expression. But at no point in reading "children.oldest().room" do you have to go backwards and re-intepret what you thought you saw. Even if the expression involves right-associative operators: children ** oldest ** room the worst that you have to do is defer thinking about children (push it onto the stack of short-term memory) until after you've thought about oldest**room. Now human memory has a very shallow stack. We struggle to hold more than approximately "seven plus or minus two" items in memory at a time. And of course people often forget that ** is right-associative (I know I do). But syntactically, there's no mental backtracking required. I'm not claiming that your suggested syntax is impossible in a LL(1) grammar like Python. I don't know. But I'm responding to your earlier assertion that it ought to always be obvious in context that you are looking at the body of a function, before you see the "with" keyword. As evidence for this assertion, you give examples where it is obvious: sort(sequence, by=card.suit with card) Sure, any English speaker familiar with the English idiom "sort by ..." can probably guess the semantics. That's great. But its not representative. We don't always have the luxury of expressions which read like English phrases: threading.Thread(target=None ... looks like the target is None, not a function, and we don't realise its not until we keep reading and learn at the very end of the expression that everything we saw before that point was part of the function body. It's great for English speakers that "sort by" appears in our code, but have a thought for those to whom it might as well be "pteg xb". Python is not just a language for English speakers, and if we're going to claim a readability advantage, we ought to at least acknowledge that not everyone will have that advantage, and not exaggerate the magnitude of that advantage by using words like "almost always". > There has never been a guarantee that expressions evaluate left to right > simply by virtue of the fact that an order of operations exists. That's fine, because I never said they did. It would be pretty foolish of me if I did, given that exponentiation is right-associative, and that we have comprehensions and ternary if expressions. > > sm = difflib.SequenceMatcher(isjunk=x == ' ' with x, ...) > > The expression x==' ' doesn't look like a function to me. > > > You don't think that perhaps that's because it's brand new syntax? > x=='' doesn't look like a function because it's not a function. I know that. But you stated: "I was trying to say that the context almost always gives away that the reader should expect a function." The difflib example is a real, not made up, example that goes against that. The context "isjunk" sounds like it might be a flag, not a function, and the code x==' ' supports that interpretation right up to the moment you read "with x" part, at which point you have to re-interpret what you've been reading. > You could play the same game with literally any compound expression: > > >>> func = ", ".join > > ", " doesn't look like a function to me! Indeed. I don't deny that there are expressions where if you truncate at a certain point, the code up to that point looks like a valid (sub-) expression of a different type: spam ? eggs If you truncate just before the ? you get a valid subexpression "spam" which may not be the same as the expression "spam ? eggs". But there aren't many places in Python where after truncating just before ?, you interpret "spam" one way, but if you truncate after the ?, you intepret "spam" a different way. Normally spam is spam no matter what follows it. In your earlier example ", " is a string, regardless of whether you have read up to the dot or not. Of course we could do this (LL(1) parser permitting) but the point I'm making is that this isn't a small change, and I don't think it will have the benefit you believe it will. The contrary: I think it will hurt readability, not help it. I think the benefit of moving the body of the function to the front is less than you think, and the cost of moving the syntax which distinguishes it as a function to the end greater than you think. I don't have objective evidence for these opinions, but I've tried as best as I am able to give the reasons why I believe this, and not just make it an assertion. > If you honestly don't understand my position at all. [...] > then I guess I've never met anyone quite like you. I'm a unique and special snowflake. https://i.imgur.com/W3ljlBg.jpg > I don't > know how to communicate my point of view any better than I already have. I understand your position. I just disagree with it. > [Steven D'Aprano] > > You are judging that from the perspective of someone whose native > > language makes it easy to say "sorted by foo" (for some value of foo). > > This argument is such a tiring distraction. Please stop. If it's all just > random symbols to some non-english speaker, then > It doesn't matter either way to them. When you are claiming an advantage, if that advantage doesn't actually apply, then its not an advantage, is it? I'm not going to stop using a valid argument just because you don't like it. > [Steven D'Aprano] > > We shouldn't judge syntax proposals just on the cases that are carefully > > chosen to showcase them at their best. Especially not trivial cases. > > We can judge it by examining cases where it might be problematic, but > there's no way to keep people from abusing > coding constructs to produce unreadable code, so just throwing out random > chunks of code like > > a.b[c:d]-e**f(g, h=i) + {j & k, l*(m-n(o,p))} with e, k > > then saying "looks bad to me" offers no insight into the pros and cons of > the proposal. Good thing I didn't do anything like that. Abe, you are attacking a strawman. I didn't give made-up deliberately awful code. I took existing code from the standard library, and translated it to your proposed syntax. These "random chunks of code" are a non-issue. I never suggested examples like that, and I haven't seen anyone else do so either. -- Steve From steve at pearwood.info Thu Aug 23 07:40:12 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 23 Aug 2018 21:40:12 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <20180822174406.GO24160@ando.pearwood.info> Message-ID: <20180823114012.GT24160@ando.pearwood.info> On Wed, Aug 22, 2018 at 06:50:29PM +0000, Dan Sommers wrote: > On Thu, 23 Aug 2018 03:44:07 +1000, Steven D'Aprano wrote: > > > On Wed, Aug 22, 2018 at 12:11:40PM -0500, Abe Dillon wrote: > > > difflib tests include this call: > > > > sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', ...) [...] > When you talk about intent, I think about use cases. In the difflib > code I quoted above, is the intent to define a function, or to > instantiate a SequenceMatcher? Well, no, it's probably to compute some > sort of difference. Instatiating a SequenceMatcher and defining isjunk > are details. > > So you're both wrong. :-P > > Or you're both right. :-/ In this case, "intent" could refer to (for example): Should we accuse Fred Bloggs of plagarism or not? +- decide whether two documents came from the same source; +- decide whether the diff between two text strings falls within some threshold; +- initiate and use a SequenceMatcher object; +- provide an isjunk predicate function; +- implement a specific predicate function. Because we are talking about lambda syntax specifically, I didn't think the higher hierachies of intent were relevant, so I didn't mention them. I thought we could focus on the two relevant to the syntax we're discussing: Provide an isjunk predicate function; +- implement a specific predicate function. and take the higher levels as given. Given those two levels, "Provide a predicate function" is at a higher level than the implementation of that predicate function. I'm sorry if that wasn't clear. -- Steve From dan at tombstonezero.net Thu Aug 23 10:59:06 2018 From: dan at tombstonezero.net (Dan Sommers) Date: Thu, 23 Aug 2018 14:59:06 +0000 (UTC) Subject: [Python-ideas] Does jargon make learning more difficult? References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <20180822174406.GO24160@ando.pearwood.info> <20180823114012.GT24160@ando.pearwood.info> Message-ID: On Thu, 23 Aug 2018 21:40:12 +1000, Steven D'Aprano wrote: > On Wed, Aug 22, 2018 at 06:50:29PM +0000, Dan Sommers wrote: >> On Thu, 23 Aug 2018 03:44:07 +1000, Steven D'Aprano wrote: >> >> > On Wed, Aug 22, 2018 at 12:11:40PM -0500, Abe Dillon wrote: >> >> > difflib tests include this call: >> > >> > sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', ...) > [...] > >> When you talk about intent, I think about use cases. In the difflib >> code I quoted above, is the intent to define a function, or to >> instantiate a SequenceMatcher? Well, no, it's probably to compute some >> sort of difference. Instatiating a SequenceMatcher and defining isjunk >> are details. >> >> So you're both wrong. :-P >> >> Or you're both right. :-/ > > In this case, "intent" could refer to (for example): > > Should we accuse Fred Bloggs of plagarism or not? > +- decide whether two documents came from the same source; > +- decide whether the diff between two text strings falls > within some threshold; > +- initiate and use a SequenceMatcher object; > +- provide an isjunk predicate function; > +- implement a specific predicate function. > > > Because we are talking about lambda syntax specifically, I didn't think > the higher hierachies of intent were relevant, so I didn't mention them. > I thought we could focus on the two relevant to the syntax we're > discussing: > > Provide an isjunk predicate function; > +- implement a specific predicate function. > > and take the higher levels as given. Given those two levels, "Provide a > predicate function" is at a higher level than the implementation of that > predicate function. > > I'm sorry if that wasn't clear. Yes, the discussion is/was about lambda syntax, and about how quickly I (or someone else) can recognize that isjunk is being defined as an anonymous function. Perhaps I missed that the larger context had already been established. To focus my argument within your clarification: if I have all of that context, then I don't have to parse the code to know that the isjunk parameter is a function. And if parsing the anonymous function gives you (the generic you) that much trouble, then please break it out into a def statement instead. Flat is better than nested. IIRC, you push for named functions in all but the most trivial cases anyway (and I tend to agree). Dan From python at mrabarnett.plus.com Thu Aug 23 11:01:04 2018 From: python at mrabarnett.plus.com (MRAB) Date: Thu, 23 Aug 2018 16:01:04 +0100 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: On 2018-08-23 03:10, Abe Dillon wrote: > [Chris Angelico] > > Because your form cannot possibly work without some additional > information. > > > That isn't my form. That's PSEUDO CODE. Just like I wrote above it. > You're the one who's not listening. > > ?The alternative I've suggested, for the thousanth time, is: > > hand = sorted(cards, by=card.suit with card) > > or > > hand = sorted(cards, by=card.suit with(card)) > > The noise compared to the PSEUDO CODE looks like this: > > hand = sorted(cards, by=card.suit ##########) > > Which, to me, is preferable to: > > hand = sorted(cards, ke#=#############card.suit) > > You need me to type that out a few dozen more times? > You're complaining that it's "noise", but I think you need a bit of noise to tell you that it's defining a function, otherwise you'll see an expression and think it's evaluated immediately, but then you'll see the "with" at the end telling you "oh, by the way, this is a function, so don't evaluate it now". You gave an example in JavaScript and said that students had "very little trouble" with it, but notice how the function itself began with a reserved word. If you're complaining about the word "lambda", that's fine, but if you're complaining about where the arguments should go, then I'm afraid I'd have to say you're wrong. From steve at pearwood.info Thu Aug 23 11:02:31 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 24 Aug 2018 01:02:31 +1000 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B7E4C41.4060306@canterbury.ac.nz> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7E4C41.4060306@canterbury.ac.nz> Message-ID: <20180823150231.GU24160@ando.pearwood.info> On Thu, Aug 23, 2018 at 05:55:13PM +1200, Greg Ewing wrote: > Chris Angelico wrote: > >for those who > >know Greek, it's like calling something an "S-expression", which is > >fairly obviously an abbreviation for something. ("Symbolic > >expression", I think? Someone might correct me there.) > > Yes, except that lambda is an even more arbitrary choice of > letter -- as far as I know, it doesn't stand for anything. If you go back far enough, pretty much all words and written symbols are arbitrary. The word "dict" can be traced back to the Latin for "to say". Where did the Romans get their "dico" from? Linguists have extrapolated back to the hypothesised Proto-Indo-European word d?y?ti (?to show, point out?). At this point, we can't even begin to guess where that word came from, but we can be sure that at some stage of human pre-history, it began as an arbitrary set of sounds. Many thousands of years later, it now means a hash table in Python. The only difference between dict and lambda is time. Lambda's arbitrariness is less than a century ago, while dict's is lost in the mists of prehistory. Why should that make a difference to anyone but a linguist? As I posted earlier, lambda has become a standard term, used by boring, staid, non-functional languages like Java and C++. There's nothing function-like about "lambda", but there's nothing function-like about "function" either. -- Steve From mike_barnett at hotmail.com Thu Aug 23 14:49:48 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Thu, 23 Aug 2018 18:49:48 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike Message-ID: Python has dropped the GUI ball, at least for beginners (in my opinion) While the Python language is awesomely compact, the GUI code is far from compact. Tkinter will create a nice looking GUI, but you've got to be skilled to use it. A student in their first week of Python programming is not going to be working with tkinter. It would be nice if beginners could double click a .py file and have it launch straight into a GUI, like most of the programs people are used to using. I think I've stumbled onto a framework that could work very well for creating fairly complex custom-layout GUIs. A package was released recently that uses this framework. It's called PySimpleGUI. It is a wrapper for tkinter so that it'll run on almost any system Python will run on. There are no other dependencies and it's a single file so that it can be easily dropped into someone's project folder for immediate use without messing with pip installs. You can read more: PySimpleGUI Tutorial PySimpleGUI Cookbook PySimpleGUI Reverence Document A bunch of screenshots I am not seeking fame, recognition, or any other personal gain. I could care less if my name is associated with this design. My goal is to get Python off the command line and onto the screen. I am, however, making a serious in my attempt to get serious Python community members to weigh in on the best approach for getting acceptance. A sizeable user-base is likely a requirement. Interest has been brisk over the past few weeks with the basic GitHub stats having made great strides toward the EasyGUI values. It's not a competition, but rather a benchmark to check progress. Comments, suggestions, pointers in new directions are all welcomed. Thank you very much for your time. I have not been a part of this mailing list in the past, so I hope I'm using it within the guidelines. Someone pointed me in this direction to get feedback and into the process. @mike -------------- next part -------------- An HTML attachment was scrubbed... URL: From abedillon at gmail.com Thu Aug 23 15:54:12 2018 From: abedillon at gmail.com (Abe Dillon) Date: Thu, 23 Aug 2018 14:54:12 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180823150231.GU24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7E4C41.4060306@canterbury.ac.nz> <20180823150231.GU24160@ando.pearwood.info> Message-ID: [Steven D'Aprano] > If you go back far enough, pretty much all words and written symbols are > arbitrary. I think this is wandering into nihilistic pedantry. Go back or forward far enough (or zoom in or out far enough) and nothing means anything. When I first learned Python, I had never heard the word "tuple" but as soon as I saw it, it made sense to me. It comes from the latin suffix for adjectives relating to multiples of things: "-uple" It's been around long enough to make its way into many common words (triple, tuplet, multiple) and many languages. That context makes it easy to remember. My guess is: even if you've only learned basic English, you have a far greater chance of being able to remember the meaning "tuple" over "lambda". Possibly even if you've never learned English, your chances of being able to relate "tuple" to relevant concepts is higher than being able to anchor "lambda" to anything relevant. [Steven D'Aprano] > As I posted earlier, lambda has become a standard term I would agree that it's become a known term among computer scientists and maybe even the majority of professional programmers, but: 1) There are several terms commonly used interchangeably for the same concept including 'anonymous function', 'function literal', even 'deferred expression' works in the context of Python because the implementation only allows for a single expression (or implicit return statement?). So I don't think it has been standardized in the sense that it's the one, agreed upon, term. 2) being known of, does not equate to being well known. I've heard of a "busy beaver", but I couldn't tell you off the top of my head what it is. Lay people have heard of and talk about DNA or genes or genetics, but if you ask them what a codon is, most people's faces will go blank. The jargon of genetics is known about only in vague terms. 3) You've provided documentation from several languages to show that the term is used, but have you compared that to the usage of other terms? 4) Sometimes standardized terms can still be warty. There are plenty of terms in Science and Engineering that have confused roots and confusing consequences, but are too ingrained to abandon. The term "Rare Earth Metals" was coined in the late 18th century even though many of the elements are quite plentiful. Anonymous function or function literal are actually descriptive. Why not back those horses? [Steven D'Aprano] > There's nothing function-like about "lambda", but there's nothing > function-like about "function" either. I'm not sure what you mean by that. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 23 16:14:25 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 23 Aug 2018 21:14:25 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: Hi Mike Thank you for your message. I agree, in broad terms, with your statement of goals, and welcome their being discussed here. Python has important roots are in education. We benefit from taking care of them. Here is what I take to be your statement of goals. > While the Python language is awesomely compact, the GUI code is far from > compact. Tkinter will create a nice looking GUI, but you?ve got to be > skilled to use it. A student in their first week of Python programming is > not going to be working with tkinter. My preferred approach to solve this problem is to use a web browser as the GUI platform, and communicate with it using a simple local server. I've been learning about http://elm-lang.org/. It impresses me. Here's some URLs. http://elm-lang.org/ https://guide.elm-lang.org/ https://ellie-app.com/37gXN5G4T2sa1 http://elm-lang.org/blog/time-travel-made-easy However, I don't want to have this thread turn into a discussion of elm. Rather, I'm putting forward using HTML5 in a browser as the GUI platform, rather than tkinter. And elm is one of several examples we can learn from. Thank you for your work on PySimpleGUI, and for your statement of goals. with best regards Jonathan From mike_barnett at hotmail.com Thu Aug 23 16:59:27 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Thu, 23 Aug 2018 20:59:27 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: Maybe we're on different planes? I'm talking about 5 lines of Python code to get a custom layout GUI on the screen: import PySimpleGUI as sg form = sg.FlexForm('Simple data entry form') # begin with a blank form layout = [ [sg.Text('Please enter your Name, Address, Phone')], [sg.Text('Name', size=(15, 1)), sg.InputText('1', key='name')], [sg.Text('Address', size=(15, 1)), sg.InputText('2', key='address')], [sg.Text('Phone', size=(15, 1)), sg.InputText('3', key='phone')], [sg.Submit(), sg.Cancel()] ] button, values = form.LayoutAndRead(layout) gets you this window: https://user-images.githubusercontent.com/13696193/43934091-8100e29a-9c1b-11e8-8d0a-9bd2d13e6d8e.jpg @mike -----Original Message----- From: Jonathan Fine Sent: Thursday, August 23, 2018 4:14 PM To: Mike Barnett Cc: python-ideas at python.org Subject: Re: [Python-ideas] A GUI for beginners and experts alike Hi Mike Thank you for your message. I agree, in broad terms, with your statement of goals, and welcome their being discussed here. Python has important roots are in education. We benefit from taking care of them. Here is what I take to be your statement of goals. > While the Python language is awesomely compact, the GUI code is far > from compact. Tkinter will create a nice looking GUI, but you?ve got > to be skilled to use it. A student in their first week of Python > programming is not going to be working with tkinter. My preferred approach to solve this problem is to use a web browser as the GUI platform, and communicate with it using a simple local server. I've been learning about https://nam01.safelinks.protection.outlook.com/?url=http%3A%2F%2Felm-lang.org%2F&data=02%7C01%7C%7Ceb7eab650615436dbeb108d609350659%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636706520676613184&sdata=pD2CihHk00chVTBlKHlIUDSwGBzpgVJZ9%2BoVdSgbI1k%3D&reserved=0. It impresses me. Here's some URLs. https://nam01.safelinks.protection.outlook.com/?url=http%3A%2F%2Felm-lang.org%2F&data=02%7C01%7C%7Ceb7eab650615436dbeb108d609350659%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636706520676613184&sdata=pD2CihHk00chVTBlKHlIUDSwGBzpgVJZ9%2BoVdSgbI1k%3D&reserved=0 https://nam01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fguide.elm-lang.org%2F&data=02%7C01%7C%7Ceb7eab650615436dbeb108d609350659%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636706520676613184&sdata=uhkgRZy1FAk%2B9QipthduzIFuhn5o8tnpD9svIUEcGPE%3D&reserved=0 https://nam01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fellie-app.com%2F37gXN5G4T2sa1&data=02%7C01%7C%7Ceb7eab650615436dbeb108d609350659%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636706520676613184&sdata=Ffq7dCPKpMgN3VjtvjhM4xXMIxo%2BwsZaIc8JOVD%2F6a8%3D&reserved=0 https://nam01.safelinks.protection.outlook.com/?url=http%3A%2F%2Felm-lang.org%2Fblog%2Ftime-travel-made-easy&data=02%7C01%7C%7Ceb7eab650615436dbeb108d609350659%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636706520676613184&sdata=WYoUZzQZmyZ7IEiMWBNnZQhai50G18ExTIEu0BrKL%2Fc%3D&reserved=0 However, I don't want to have this thread turn into a discussion of elm. Rather, I'm putting forward using HTML5 in a browser as the GUI platform, rather than tkinter. And elm is one of several examples we can learn from. Thank you for your work on PySimpleGUI, and for your statement of goals. with best regards Jonathan From jfine2358 at gmail.com Thu Aug 23 17:15:28 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 23 Aug 2018 22:15:28 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: Hi Mike Thank you for your prompt response. You wrote > Maybe we're on different planes? > > I'm talking about 5 lines of Python code to get a custom layout GUI on the screen: > > import PySimpleGUI as sg > > form = sg.FlexForm('Simple data entry form') # begin with a blank form > > layout = [ > [sg.Text('Please enter your Name, Address, Phone')], > [sg.Text('Name', size=(15, 1)), sg.InputText('1', key='name')], > [sg.Text('Address', size=(15, 1)), sg.InputText('2', key='address')], > [sg.Text('Phone', size=(15, 1)), sg.InputText('3', key='phone')], > [sg.Submit(), sg.Cancel()] > ] > > button, values = form.LayoutAndRead(layout) The execution of this code, depends on PySimpleGUI, which in turn depends on tkinter, which is in turn a thin layer on top of Tcl/Tk. And Tcl/Tk provides the GUI layer. (See https://docs.python.org/3/library/tk.html.) I'm suggest that sometimes it may be better to use HTML5 to provide the GUI layer. I pointed to Elm, to show how powerful HTML5 has become. Put another way, I'm suggesting that instead of > import PySimpleGUI as sg we are able to use > import HtmlSimpleGUI as sg for a module HtmlSimpleGUI that, sadly, hasn't been written yet! However, mine is just one voice, and I have little more to say. If you don't mind, I'll leave this conversation now. with best regards Jonathan -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Thu Aug 23 17:25:32 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Fri, 24 Aug 2018 09:25:32 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <20180823150231.GU24160@ando.pearwood.info> References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> <5B7E4C41.4060306@canterbury.ac.nz> <20180823150231.GU24160@ando.pearwood.info> Message-ID: <5B7F264C.6020001@canterbury.ac.nz> Steven D'Aprano wrote: > The only difference between dict and lambda is time. Well, "more arbitrary" was perhaps a rather loose way of saying it. What I meant was that the chain of associations is shorter for "lambda" than for "s-expression", because the "s" refers to a word the reader is probably already familiar with, but "lambda" doesn't refer to anything pre-existing that's semantically related. Not that there's anything wrong with that -- mathematicians love to endlessly re-use the same rather small set of symbols, so sometimes they have to make a completely arbitrary choice. -- Greg From abedillon at gmail.com Thu Aug 23 17:39:19 2018 From: abedillon at gmail.com (Abe Dillon) Date: Thu, 23 Aug 2018 16:39:19 -0500 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <20180822163417.GK24160@ando.pearwood.info> Message-ID: Let me preface this by saying: I've already addressed the possibility of a form that tells you up-front that it's a function Granted it was 8 replies ago and at the end of a long-winded response, so I'll summarize here: A format like [] would, in my view, be preferable to a format that puts the signature first. An example might be: hand = sorted(cards, by=def card.suit with card) hand = sorted(cards, by=return card.suit from card) hand = sorted(cards, by=(:card.suit with card)) # the happiest form! hand = sorted(cards, by==>card.suit :: card) # eh... etc... There are many possibilities. [MRAB] > You're complaining that it's "noise", but I think you need a bit of > noise to tell you that it's defining a function I feel like the pseudo code example shows that at least isn't *always* true. Yes, the noise is neccessary for the computer's sake, but it doesn't have to go in-front of the logic. It's usually not that important for the reader. The intent is to sort cards by suit, not to declare a function that gets the suit of a card. The fact that you have to declare a function is secondary to the intent. If it were up to me, I'd make "by" the keyword for a key-function in sorted, sort, min, max, etc. and have special secondary keywords for simple, common cases: >>> hand = sorted(cards, by_attr="suit") >>> exam_grades.sort(by_item=-1) etc... [MRAB] > otherwise you'll see an expression and think it's evaluated immediately, > but then you'll see the > "with" at the end telling you "oh, by the way, this is a function, > so don't evaluate it now". That's true of most expressions: >>> grades = {"Sally": 92, "Jimmy": 83, "Beth": 87, "Alex": 98} >>> best_student = max(grades, key=grades.get) >>> print(best_student) 'Alex' Assuming you know that grades.get is a method, you don't know that the expression passed to 'key' is a function until you read the whole expression. If you don't know what grades.get is, you don't know what kind of object is being passed to key: >>> best_student = max(spam, key=spam.eggs) Is it catastrophic that you don't know what ham.eggs is? Is it something to do with card.suit with card being a literal that makes you demand to know what type of thing is being passed before you finish reading the expression? Because that clearly isn't true in the case of variables. Besides; you usually have several context clues leading up to the 'with' : 1) The function (if you're familiar with it) 2) The name of the function (if it's well named and you are familiar with the name) e.g. add_callback, add_handler, on_mouseover, etc.. 3) The name of a keyword parameter (if it's well named and you're familiar with the name) e.g. key, callback, handler, event_handler, filter, etc... 4) The usage of a variable that has yet to be declared (just like in generator/comprehension expressions) example: def best_hand(cards): hand = sorted(cards, key=card.suit with card) ... My hunch is that the vast majority of cases satisfy enough of those that reading a 'with' would rarely be all that surprising. I also assert that some of those conditions are far more critical to comprehending code, so if they're missing, your comprehension ends long before you're "surprised" by the appearance of a 'with'. All of the arguments in the following are clearly declared literals: foo = bar.baz(100, True, ham="spam") Can you read that? In a sense, yes. Can you comprehend it? No! What if I asked you "where's the bug?". Nope. Another example (from D'Aprano): sm = difflib.SequenceMatcher(isjunk=True) t = threading.Thread(target="hello") Now imagine that none of the 4 context clues above are true. Can you read those? Can you see the bugs? Is there even a point to reading beyond where your comprehension stops? If you don't know anything about what's expected for "target" or "isjunk" than reading any further isn't helpful. Knowing that "hello" is a string right away saves you no pain. The paramount problem is that you don't know that it's supposed to be a function. You need to stop when you loose comprehension and read the docs. Then when you come back, you'll know that 'isjunk' should be a function. The counter that there may be cases where none of the 4 context clues above exist indicates a more urgent problem than knowing the types of literals being passed (immediately or otherwise). Also, by the time you hit the "with" it's not like the "new information" requires you to look back and re-examine anything. It's just new information like any other compound statement: >>> spam.eggs(ham)[parrot] # it's the value of 'spam'... # or rather the attribute 'eggs' of 'spam'... # or rather the result of calling the method 'eggs' of 'spam' with 'ham'... # or rather it's the 'parrot'th item of the result of calling the method 'eggs' of 'spam' with 'ham' [MRAB] > You gave an example in JavaScript and said that students had "very > little trouble" with it, but notice how the function itself began with a > reserved word. > If you're complaining about the word "lambda", that's fine, Yes, that was the context of the discussion I was referencing. Just the word "lambda". In this ongoing discussion I've declared on two separate gripes: 1) the word itself and 2) the format. I think a different format opens up other possible word choices, but that's not really important. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hugo.fisher at gmail.com Thu Aug 23 18:14:26 2018 From: hugo.fisher at gmail.com (Hugh Fisher) Date: Fri, 24 Aug 2018 08:14:26 +1000 Subject: [Python-ideas] A GUI for beginners and experts alike (Mike Barnett) In-Reply-To: References: Message-ID: > Date: Thu, 23 Aug 2018 18:49:48 +0000 > From: Mike Barnett > > Python has dropped the GUI ball, at least for beginners (in my opinion) > > While the Python language is awesomely compact, the GUI code is far from compact. Tkinter will create a nice looking GUI, but you've got to be skilled to use it. A student in their first week of Python programming is not going to be working with tkinter. > > It would be nice if beginners could double click a .py file and have it launch straight into a GUI, like most of the programs people are used to using. > > I think I've stumbled onto a framework that could work very well for creating fairly complex custom-layout GUIs... Have you looked at PySide2? It's the latest Python wrapper for the QT cross platform GUI framework. A graphical "hello world" in QT is only half a dozen or less lines of code in total, so meets the simplicity requirement. The big drawback of QT for Python until now has been building the thing, but now it's on PyPI so "pip install" (should) Just Work. -- cheers, Hugh Fisher From turnbull.stephen.fw at u.tsukuba.ac.jp Thu Aug 23 20:29:01 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Fri, 24 Aug 2018 09:29:01 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <20180822061154.GF24160@ando.pearwood.info> <20180822174406.GO24160@ando.pearwood.info> Message-ID: <23423.20813.587616.964166@turnbull.sk.tsukuba.ac.jp> Dan Sommers writes: > Given x = the width of a widget and y = the price of that widget, > let f(x, y) be x + y. Lordy, there are tapes! I hope that wasn't an economist! From turnbull.stephen.fw at u.tsukuba.ac.jp Thu Aug 23 20:34:14 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Fri, 24 Aug 2018 09:34:14 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: References: <5B71FF06.2070407@canterbury.ac.nz> <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <23420.55144.2677.692751@turnbull.sk.tsukuba.ac.jp> Message-ID: <23423.21126.208348.743032@turnbull.sk.tsukuba.ac.jp> Abe Dillon writes: > That's interesting. So the parser can see one token past, for instance; > what would be the end of an expression, see "if", and know to expand the > AST? Yes, if you want to think about it that way. I think about it in terms of the parser receiving tokens one at a time, using to revise the AST, until it can't. Like a five-year-old building a fort by piling up pillows. She's done when she's out of pillows, or the whole thing falls over due to imbalance. She doesn't have a grand plan, she just puts pillows wherever they fit. At the point where no work can be done, the parser either has a token in hand, which is a syntax error, or it's at end of input. In the latter case, it either has a complete syntactically correct AST, or it's a syntax error. In the end it works the same as your description, but I don't think of it in terms of the parser knowing "where" it is in the program, but rather in terms of whether it can do more work on the AST with the token (or EOF) in hand. Only when it runs out of input does it "look at" what it's built so far to check if it's done. If you think of expressions having their own subparser, the model is a little more subtle. I think of the subparsers as being coroutines receiving tokens via (yield) from their parent. This implies that when the subparser actually returns an AST, the parent already has the token that the subparser balked at. In some sense, there's no lookahead in the sense of something you save away to fully process later, or pass to another actor to process. You're always operating on a current token. Steve From steve at pearwood.info Thu Aug 23 20:44:27 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 24 Aug 2018 10:44:27 +1000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: <20180824004427.GV24160@ando.pearwood.info> Hi Mike, and welcome! On Thu, Aug 23, 2018 at 06:49:48PM +0000, Mike Barnett wrote: > Python has dropped the GUI ball, at least for beginners (in my opinion) Sadly I think that GUIs is one area where Python has not excelled. > While the Python language is awesomely compact, the GUI code is far > from compact. Tkinter will create a nice looking GUI, but you've got > to be skilled to use it. A student in their first week of Python > programming is not going to be working with tkinter. I've been using Python for 20 years, and I'm still intimidated by Tkinter's learning curve, let alone products like wxPython. > I think I've stumbled onto a framework that could work very well for > creating fairly complex custom-layout GUIs. > > A package was released recently that uses this framework. It's called > PySimpleGUI. It is a > wrapper for tkinter so that it'll run on almost any system Python will > run on. Provided they have tkinter. > I am not seeking fame, recognition, or any other personal gain. Good, because you won't get it :-) > I am, however, making a serious in my attempt to get serious Python > community members to weigh in on the best approach for getting > acceptance. Acceptance for *what* precisely? I appreciate your enthusiasm, but I think you forgot to actually make a proposal. Is this an attempt to draw people's attention to PySimpleGUI? To start a dialog about finding something better? Do you want PySimpleGUI to be added to the Python standard library? (If so, then I don't understand the comment about pip install and dropping the PySimpleGUI into people's project folder -- that isn't necessary if its a std lib module.) If this is about adding PySimpleGUI to the std lib, then there's a few things to keep in mind: * We don't conscript library authors; they have to volunteer, or at least agree, to donate their library to the Python std lib. Have you approached the author of PySimpleGUI to see what he or she has to think about this idea? * Even if they are agreeable, we don't take software until it has proven itself, both that there is a need for it and that it is the right solution. Being in the std lib is not for every project. It means following Python's release cycle, which is too slow for some projects and too fast for others. It also means being limited by some rather hard backwards- compatibility constraints, and a cultural reluctance to grow libraries beyond a certain size. Sometimes even adding a single function to a library can be controversial. Projects in their early days that are still experimenting with their interfaces, or intending to add new functionality, are generally not a good fit to the std lib. There's a saying that the standard library is where good libraries go to die. While that's somewhat of an exaggeration (there's plenty of life left in the std lib) it is true that libraries in the std lib should offer a stable interface and functionality. -- Steve From mike_barnett at hotmail.com Thu Aug 23 21:04:17 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Fri, 24 Aug 2018 01:04:17 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: <20180824004427.GV24160@ando.pearwood.info> References: <20180824004427.GV24160@ando.pearwood.info> Message-ID: Wow, Thank you Steve! This is exactly the kind of information I was hoping for!! > Acceptance for *what* precisely? That is a great question... you're right shoulda asked a specific question. I would like to see if become something official so that it gets out to people automatically. Perhaps a stdlib module. I should have also mentioned I'm the author. That 3rd person thing didn't sound right. Definitely want to stress that the current implementation is a prototype for something official. It would need to be rewritten should it be submitted. As it is now it likely needs refactoring to get the interface to be PEP8 compliant. If it's possible to look past some of those blemishes and more at what the interface accomplishes and how it goes about doing it. There are a number of Python-like aspects of the project that fit within a learning environment. These concepts are all touched upon in a natural way: * The use of Lists, Dictionaries for return values. * The window/form is specified using a List layout that visibly resembles the GUI layout. * Widgets are configured in place by using optional parameters. * The calls collapse down into a single-line of Python code for a custom GUI should you want to write it that way. The other questions: Is this an attempt to draw people's attention to PySimpleGUI? To start a dialog about finding something better? Yes - I want to begin the process of getting some attention... get some ideas on how I can get in front of audiences that may be interested. I don't want to spam the Python world, but I do want to help people add a nice front-end to their programs. (.... then I don't understand the comment about pip install and dropping the PySimpleGUI into people's project folder -- that isn't necessary if its a std lib module.) The single-file aspect is a detail about today's implementation. Thank you for asking helpful questions. @mike From gadgetsteve at live.co.uk Fri Aug 24 00:58:46 2018 From: gadgetsteve at live.co.uk (Steve Barnes) Date: Fri, 24 Aug 2018 04:58:46 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <20180824004427.GV24160@ando.pearwood.info> Message-ID: On 24/08/2018 02:04, Mike Barnett wrote: > Wow, Thank you Steve! > > > This is exactly the kind of information I was hoping for!! > > > >> Acceptance for *what* precisely? > > That is a great question... you're right shoulda asked a specific question. > > I would like to see if become something official so that it gets out to people automatically. Perhaps a stdlib module. > > I should have also mentioned I'm the author. That 3rd person thing didn't sound right. > > Definitely want to stress that the current implementation is a prototype for something official. It would need to be rewritten should it be submitted. As it is now it likely needs refactoring to get the interface to be PEP8 compliant. If it's possible to look past some of those blemishes and more at what the interface accomplishes and how it goes about doing it. > > There are a number of Python-like aspects of the project that fit within a learning environment. These concepts are all touched upon in a natural way: > * The use of Lists, Dictionaries for return values. > * The window/form is specified using a List layout that visibly resembles the GUI layout. > * Widgets are configured in place by using optional parameters. > * The calls collapse down into a single-line of Python code for a custom GUI should you want to write it that way. > > The other questions: > > Is this an attempt to draw people's attention to PySimpleGUI? > To start a dialog about finding something better? > > Yes - I want to begin the process of getting some attention... get some ideas on how I can get in front of audiences that may be interested. I don't want to spam the Python world, but I do want to help people add a nice front-end to their programs. > > > (.... then I don't understand the comment about pip install and > dropping the PySimpleGUI into people's project folder -- that isn't > necessary if its a std lib module.) > > The single-file aspect is a detail about today's implementation. > > > Thank you for asking helpful questions. > > > > @mike > > Mike, A couple of points: 1. If you were to package PySimpleGUI into a pip installable library then this allows anybody who pip installs it to import and use it without copying it anywhere, (just like it being in the stdlib other than the pip step). 2. You can add a package to pypi, and improve on it & its documentation, without needing a PEP or any of the rigmarole needed to get it into the stdlib. 3. Once a pypi package gets a) stable & b) the traction for mass use it may be considered to inclusion into the standard lib, (or go there to die as any changes become very slow & constrained. 4. Python Ideas is probably not the best channel to publicise such a package. So all in all I would suggest concentrating on that initially. There are already 2 ways of turning a python program that uses argparse into a GUI, (Gooey for wx & Quicken for QT IIRC), with minimal modification. There are a lot of good arguments for teaching people to use argparse and to write their code to be able to run from the command line but there is not a mechanism that I am aware of for turning argparse based code into a TK GUI this might be a fruitful area to look at. It might even be a really great idea to get in touch with the authors of the two package mentioned to see if it might not be possible to come up with a unified library that allowed something like: ``` import pyUniGUI as gui gui.set_backend(tk) # or qt or wx (maybe others) @gui.from_argparse def parse_args(): """ Parse command line arguments (also defines GUI). """ ... ``` Can I also suggest taking a look at the Enthought Traits & TraitsUI (https://github.com/enthought/traitsui) packages to see what can be done for automating GUI generation. TraitsUI can use wx or QT (via various bindings) as GUI backends, (I know that is an unusual turn of phrase), but adding a TK backend would be a great move. -- 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. https://www.avg.com From jab at math.brown.edu Fri Aug 24 01:03:26 2018 From: jab at math.brown.edu (jab at math.brown.edu) Date: Thu, 23 Aug 2018 22:03:26 -0700 (PDT) Subject: [Python-ideas] Fwd: Replacing Infinite while Loops with an Iterator: async edition In-Reply-To: <5B302D90.3040506@canterbury.ac.nz> References: <5B2EECC1.1090602@canterbury.ac.nz> <59344505-2604-46A6-B1B6-92A1BB6645BC@gmail.com> <5B302D90.3040506@canterbury.ac.nz> Message-ID: <3ee63fcc-1878-4a4c-b132-8c40c80eabe2@googlegroups.com> On Sunday, June 24, 2018 at 7:48:34 PM UTC-4, Greg Ewing wrote: > > j... at math.brown.edu wrote: > > On Jun 23, 2018, at 21:11, Nathaniel Smith > > wrote: > > > > He's asking for an async version of the 'iter' builtin, presumably > > something like: > > async def aiter(async_callable, sentinel): > > while True: > > value = await async_callable() > > if value == sentinel: > > break > > yield value > > -n > > > > Yes, exactly (thanks, Nathaniel). Wouldn't that be a useful built-in? > > Ah, sorry, I misunderstood. > > I'm surprised this doesn't exist already -- it seems like an > obvious thing to have along with the other async features. > > -- > Greg > Just submitted a PR: https://github.com/python/cpython/pull/8895 -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Fri Aug 24 03:14:10 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Fri, 24 Aug 2018 19:14:10 +1200 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <23423.21126.208348.743032@turnbull.sk.tsukuba.ac.jp> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <23420.55144.2677.692751@turnbull.sk.tsukuba.ac.jp> <23423.21126.208348.743032@turnbull.sk.tsukuba.ac.jp> Message-ID: <5B7FB042.6010201@canterbury.ac.nz> Stephen J. Turnbull wrote: > Abe Dillon writes: > > > That's interesting. So the parser can see one token past, for instance; > > what would be the end of an expression, see "if", and know to expand the > > AST? > > Yes, if you want to think about it that way. For understanding what kinds of things an LL parser can parse, it helps to have gone through the exercise of implementing a recursive descent parser. The classic way to do that is to write a function for each production in the grammar. E.g. if you have a production expr ::= term ['+' expr] then you would write a function structured like this: def parse_expr(): parse_term() if current_token == '+': next_token() parse_expr() What other stuff you do in it depends on what you want the parser to accomplish. If you want it to build a parse tree, you could do something like this: def parse_expr(): result = parse_term() if current_token == '+': next_token() operand2 = parse_expr() result = BinopNode(result, operand2) return result > I don't think of > it in terms of the parser knowing "where" it is in the program, but > rather in terms of whether it can do more work on the AST with the > token (or EOF) in hand. Not so much where it is in the program, but where it is in the *grammar*. For example, if parse_term() gets called, it knows it must be looking at the beginning of a term. If the current token is not one of the ones that can begin a term, then there is a syntax error. The fact that a recursive descent parser always knows where it is in the grammar is useful, because it can be used to produce helpful error messages. For example, if it gets stuck in parse_term() it can say something like "I was expecting a term here, but this token doesn't look like the beginning of a term." Unfortunately, Python's parser doesn't seem to make much use of this. :-( > If you think of expressions having their own subparser, the model is a > little more subtle. I think of the subparsers as being coroutines That's kind of the way an LR parser works. An LR parser is more powerful than an LL parser, because it can effectively explore several possible parsings in parallel until one of them succeeds. But I don't think Python uses an LR parser, because its grammar is required to be LL(1). If you're interested in this stuff, I recommend either taking a computer science course or reading a good book about the theory of parsing. It will bring a lot of these concepts into sharp focus. -- Greg From contact at brice.xyz Fri Aug 24 03:34:47 2018 From: contact at brice.xyz (Brice Parent) Date: Fri, 24 Aug 2018 09:34:47 +0200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: <0cd6bc17-5754-a367-58a2-ff0aa59707eb@brice.xyz> > > The execution of this code, depends on PySimpleGUI, which in turn > depends on tkinter, which is in turn a thin layer on top of Tcl/Tk. > And Tcl/Tk provides the GUI layer. > (See https://docs.python.org/3/library/tk.html.) > > I'm suggest that sometimes it may be better to use HTML5 to provide > the GUI layer. I pointed to Elm, to show how powerful HTML5 has become. > > Put another way, I'm suggesting that instead of > > import PySimpleGUI as sg > > we are able to use > > import HtmlSimpleGUI as sg > > for a module HtmlSimpleGUI that, sadly, hasn't been written yet! > > However, mine is just one voice, and I have little more to say. If you > don't mind, I'll leave this conversation now. For me, it would even make more sense to split the project into two parts: - the description library, which could roughly enable the syntax you propose (but with another import) to define what your interface should look like. - rendering plugins to display the form in specific formats/type of displays. So you would have a tkinter (or whatever) plugin for a simple GUI, an bottle/html plugin (for example) to display your interface in a web browser, a plugin with a mix of those two to display the html form in a webview component, a plugin to display the form on a tiny touch enabled screen attached to your raspberry pi's GPIO pins or to your micropython module, etc. And if it makes sense (you didn't use any form element that is not compatible with a text-only display), a plugin to display your form in the CLI. This would allow to detach the content from the presentation, and allow to make a project evolve depending on the needs without having to rewrite everything. -Brice -------------- next part -------------- An HTML attachment was scrubbed... URL: From wes.turner at gmail.com Fri Aug 24 04:12:42 2018 From: wes.turner at gmail.com (Wes Turner) Date: Fri, 24 Aug 2018 04:12:42 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On Thursday, August 23, 2018, Jonathan Fine wrote: > Hi Mike > > Thank you for your prompt response. You wrote > > > Maybe we're on different planes? > > > > I'm talking about 5 lines of Python code to get a custom layout GUI on > the screen: > > > > import PySimpleGUI as sg > > > > form = sg.FlexForm('Simple data entry form') # begin with a blank form > > > > layout = [ > > [sg.Text('Please enter your Name, Address, Phone')], > > [sg.Text('Name', size=(15, 1)), sg.InputText('1', key='name')], > > [sg.Text('Address', size=(15, 1)), sg.InputText('2', > key='address')], > > [sg.Text('Phone', size=(15, 1)), sg.InputText('3', > key='phone')], > > [sg.Submit(), sg.Cancel()] > > ] > > > > button, values = form.LayoutAndRead(layout) > > The execution of this code, depends on PySimpleGUI, which in turn depends > on tkinter, which is in turn a thin layer on top of Tcl/Tk. And Tcl/Tk > provides the GUI layer. > (See https://docs.python.org/3/library/tk.html.) > > I'm suggest that sometimes it may be better to use HTML5 to provide the > GUI layer. I pointed to Elm, to show how powerful HTML5 has become. > BeeWare uses Toga (a widget toolkit) and Briefcase (a build tool) to build native GUIs and SPA web apps > Write your apps in Python and release them on iOS, Android, Windows, MacOS, Linux, Web, and tvOS using rich, native user interfaces. One codebase. Multiple apps. Briefcase can build Django apps. https://pybee.org https://pybee.org/project/using/ https://briefcase.readthedocs.io/en/latest/tutorial/tutorial-0.html https://toga.readthedocs.io/en/latest/tutorial/tutorial-0.html It's definitely not a single file module, though. Bottle is a single file web framework ('microframework'); but it doesn't have a widget toolkit. Web development is not as easy to learn as a simple GUI api for beginners (and then learning what to avoid in terms of websec is a lot to learn). There was a thread about deprecating Tk awhile back. There also I think I mentioned that asyncio event loop support would be great for real world apps. -------------- next part -------------- An HTML attachment was scrubbed... URL: From wes.turner at gmail.com Fri Aug 24 04:17:20 2018 From: wes.turner at gmail.com (Wes Turner) Date: Fri, 24 Aug 2018 04:17:20 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: https://docs.python-guide.org/scenarios/gui/ lists a bunch of great GUI projects for Python. https://github.com/realpython/python-guide/blob/master/docs/scenarios/gui.rst On Friday, August 24, 2018, Wes Turner wrote: > > > On Thursday, August 23, 2018, Jonathan Fine wrote: > >> Hi Mike >> >> Thank you for your prompt response. You wrote >> >> > Maybe we're on different planes? >> > >> > I'm talking about 5 lines of Python code to get a custom layout GUI on >> the screen: >> > >> > import PySimpleGUI as sg >> > >> > form = sg.FlexForm('Simple data entry form') # begin with a blank form >> > >> > layout = [ >> > [sg.Text('Please enter your Name, Address, Phone')], >> > [sg.Text('Name', size=(15, 1)), sg.InputText('1', >> key='name')], >> > [sg.Text('Address', size=(15, 1)), sg.InputText('2', >> key='address')], >> > [sg.Text('Phone', size=(15, 1)), sg.InputText('3', >> key='phone')], >> > [sg.Submit(), sg.Cancel()] >> > ] >> > >> > button, values = form.LayoutAndRead(layout) >> >> The execution of this code, depends on PySimpleGUI, which in turn depends >> on tkinter, which is in turn a thin layer on top of Tcl/Tk. And Tcl/Tk >> provides the GUI layer. >> (See https://docs.python.org/3/library/tk.html.) >> >> I'm suggest that sometimes it may be better to use HTML5 to provide the >> GUI layer. I pointed to Elm, to show how powerful HTML5 has become. >> > > BeeWare uses Toga (a widget toolkit) and Briefcase (a build tool) to build > native GUIs and SPA web apps > > > Write your apps in Python and release them on iOS, Android, Windows, > MacOS, Linux, Web, and tvOS using rich, native user interfaces. One > codebase. Multiple apps. > > Briefcase can build Django apps. > > https://pybee.org > https://pybee.org/project/using/ > https://briefcase.readthedocs.io/en/latest/tutorial/tutorial-0.html > https://toga.readthedocs.io/en/latest/tutorial/tutorial-0.html > > It's definitely not a single file module, though. > > Bottle is a single file web framework ('microframework'); but it doesn't > have a widget toolkit. > > Web development is not as easy to learn as a simple GUI api for beginners > (and then learning what to avoid in terms of websec is a lot to learn). > > There was a thread about deprecating Tk awhile back. There also I think I > mentioned that asyncio event loop support would be great for real world > apps. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tjreedy at udel.edu Fri Aug 24 04:52:35 2018 From: tjreedy at udel.edu (Terry Reedy) Date: Fri, 24 Aug 2018 04:52:35 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On 8/24/2018 4:12 AM, Wes Turner wrote: > There was a thread about deprecating Tk awhile back. That was an intentionally annoying troll post, not a serious proposal. Please don't refer to it as if it were. > asyncio event loop support would be great for real world apps. This is unclear. Any app that wants to use asyncio can import it. Easily using async and await *without* using asyncio is a different matter. -- Terry Jan Reedy From mike_barnett at hotmail.com Fri Aug 24 10:52:05 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Fri, 24 Aug 2018 14:52:05 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: I saw this list prior to writing PySimpleGUI. My goal is for this architecture to be on that list down the road. Don?t care if it?s this package, only that something similar exist and is known in the community. There is a gaping hole between command line and a simple GUI on the screen. It?s a huge chasm. Here?s a fun Python-like way of using the package. You can collapse a custom form down to a single line of (readable) code. button, (filename,) = sg.FlexForm('Get filename example'). LayoutAndRead([[sg.Text('Filename')], [sg.Input(), sg.FileBrowse()], [sg.OK(), sg.Cancel()] ]) Or maybe break it up: button, (filename,) = sg.FlexForm('Get filename example').LayoutAndRead( [[sg.Text('Filename')], [sg.Input(), sg.FileBrowse()], [sg.OK(), sg.Cancel()]]) Can a few of you with the vast amount of GUI experience you have, spend 5 minutes and run one of the examples? This will get you started: pip install PySimpleGUI Then copy and paste a Recipe from the Cookbook. https://pysimplegui.readthedocs.io/en/latest/cookbook/ For someone with a dev environment running, it?s a 2 minute exercise. It will make for more focused comments. I?m asking that it actually be tried because I don?t think anything like it has been proposed as a GUI framework. @mike From: Wes Turner Sent: Friday, August 24, 2018 4:17 AM To: Jonathan Fine Cc: Mike Barnett ; python-ideas at python.org Subject: Re: [Python-ideas] A GUI for beginners and experts alike https://docs.python-guide.org/scenarios/gui/ lists a bunch of great GUI projects for Python. https://github.com/realpython/python-guide/blob/master/docs/scenarios/gui.rst -------------- next part -------------- An HTML attachment was scrubbed... URL: From wes.turner at gmail.com Fri Aug 24 11:07:51 2018 From: wes.turner at gmail.com (Wes Turner) Date: Fri, 24 Aug 2018 11:07:51 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On Friday, August 24, 2018, Terry Reedy wrote: > On 8/24/2018 4:12 AM, Wes Turner wrote: > > There was a thread about deprecating Tk awhile back. >> > > That was an intentionally annoying troll post, not a serious proposal. > Please don't refer to it as if it were. stdlib inclusion entails years of support commitment, backwards incompatibility, waiting for a Python release to occur, and withstanding phd-level challenges. > > asyncio event loop support would be great for real world apps. >> > > This is unclear. Any app that wants to use asyncio can import it. > Easily using async and await *without* using asyncio is a different matter. asyncio support is only so useful when the GUI widget toolkit blocks (doesn't use async or await > > -- > Terry Jan Reedy > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Fri Aug 24 11:12:41 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Fri, 24 Aug 2018 16:12:41 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On Fri, 24 Aug 2018 at 15:53, Mike Barnett wrote: > Can a few of you with the vast amount of GUI experience you have, spend 5 minutes and run one of the examples? I don't have a "vast" amount of GUI experience. But nevertheless I gave it a go. It took less than 5 minutes (which is good). > This will get you started: > > pip install PySimpleGUI Worked. > Then copy and paste a Recipe from the Cookbook. > > https://pysimplegui.readthedocs.io/en/latest/cookbook/ I went for the simple GUI form. It worked pretty much as expected. The code looks quite nice. > For someone with a dev environment running, it?s a 2 minute exercise. It will make for more focused comments. I?m asking that it actually be tried Agreed, it was simple to use, and pick up a canned example. > because I don?t think anything like it has been proposed as a GUI framework. I don't know if that's true, there's a lot of GUI frameworks and I certainly can't say I've tried all of them. This looks nice for simple usages, and would certainly be useful as a project on PyPI (like it is at the moment). I doubt it's mature enough for the stdlib, and I'm certain it's not stable enough (yet) for the stdlib - you'll want to make changes, add features, etc, and once it's in the stdlib that's going to be a lot harder. What's the rush? As far as things I think I'd like to see (and these are just off the top of my head, I've done nothing more than I said above): 1. More documentation - reference docs specifically. I don't see documentation of the call signature for sg.Text, for example. 2. Advanced features - how would I extend it if I have a need that it doesn't cover? For example, a canvas object or an image? 3. It doesn't seem to use native widgets (the buttons have a non-standard look on my Windows PC). Don't feel like you need to do anything about these comments - I rarely if ever use a GUI library, and I've no idea if I'd use this one in future, but if you want "focused comments" beyond "it looks neat and seems like a fine project to go onto PyPI, but I don't think it's necessarily something that should go in the stdlib", then those were what I thought of off the cuff. Hope this is useful, Paul From mike_barnett at hotmail.com Fri Aug 24 11:27:53 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Fri, 24 Aug 2018 15:27:53 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: Liking the comments Paul! Backing up to the beginning, I know I'm far far far away from attempting to become a part of stdlib. However, that does not mean I can't set that as the target and begin to understand the path to get there. My initial post was an attempt to understand this path. I've been getting lots of good information on how to get there, what happens where you do get there, etc. I like it!! Thank you for taking the time to both try it and write your thoughts. Answering a couple of specific questions / remarks: 1. More documentation - reference docs specifically. I don't see documentation of the call signature for sg.Text, for example. A little confused by this one. There are quite a bit of documentation. Did you see the readme on the GitHub and here: https://pysimplegui.readthedocs.io/en/latest/ It has the call information about the Text widget and all the others. Is this what you mean by a Signature? Text(Text, scale=(None, None), size=(None, None), auto_size_text=None, font=None, text_color=None, justification=None) . Text - The text that's displayed size - Element's size auto_size_text - Bool. Change width to match size of text font - Font name and size to use text_color - text color justification - Justification for the text. String - 'left', 'right', 'center' I don't have all of the newest features in there, like the Update method because the doc is for version 2.9 on PyPI. I don't yet have the latest GitHub release in there just yet. You'll find that information instead on the Wiki: https://github.com/MikeTheWatchGuy/PySimpleGUI/wiki/PySimpleGUI-Wiki 2. Advanced features - how would I extend it if I have a need that it doesn't cover? For example, a canvas object or an image? I have Images. Don't have Canvas. Any particular operations desired for the Canvas Element should I have one? 3. It doesn't seem to use native widgets (the buttons have a non-standard look on my Windows PC). The defaults can be easily changed. The default buttons are the one widget that I modify from the system default. The reason was that the system default is a gray button. It pretty much matches the background. If you want your buttons to all look like the system default, slip this line of code at the top: sg.SetOptions(button_color=sg.COLOR_SYSTEM_DEFAULT) Thank you again Paul... I learn something new from every reply ? @mike -----Original Message----- From: Paul Moore Sent: Friday, August 24, 2018 11:13 AM To: mike_barnett at hotmail.com Cc: Wes Turner ; Jonathan Fine ; Python-Ideas Subject: Re: [Python-ideas] A GUI for beginners and experts alike On Fri, 24 Aug 2018 at 15:53, Mike Barnett wrote: > Can a few of you with the vast amount of GUI experience you have, spend 5 minutes and run one of the examples? I don't have a "vast" amount of GUI experience. But nevertheless I gave it a go. It took less than 5 minutes (which is good). > This will get you started: > > pip install PySimpleGUI Worked. > Then copy and paste a Recipe from the Cookbook. > > https://eur04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpysi > mplegui.readthedocs.io%2Fen%2Flatest%2Fcookbook%2F&data=02%7C01%7C > %7C854fc59de69e4b1c93bc08d609d41047%7C84df9e7fe9f640afb435aaaaaaaaaaaa > %7C1%7C0%7C636707203735494935&sdata=2Pc7s%2BsqtF0vOfi55TG0cJRrNb3O > 7ENRfuFxTjqN1K0%3D&reserved=0 I went for the simple GUI form. It worked pretty much as expected. The code looks quite nice. > For someone with a dev environment running, it?s a 2 minute exercise. > It will make for more focused comments. I?m asking that it actually be > tried Agreed, it was simple to use, and pick up a canned example. > because I don?t think anything like it has been proposed as a GUI framework. I don't know if that's true, there's a lot of GUI frameworks and I certainly can't say I've tried all of them. This looks nice for simple usages, and would certainly be useful as a project on PyPI (like it is at the moment). I doubt it's mature enough for the stdlib, and I'm certain it's not stable enough (yet) for the stdlib - you'll want to make changes, add features, etc, and once it's in the stdlib that's going to be a lot harder. What's the rush? As far as things I think I'd like to see (and these are just off the top of my head, I've done nothing more than I said above): 1. More documentation - reference docs specifically. I don't see documentation of the call signature for sg.Text, for example. 2. Advanced features - how would I extend it if I have a need that it doesn't cover? For example, a canvas object or an image? 3. It doesn't seem to use native widgets (the buttons have a non-standard look on my Windows PC). Don't feel like you need to do anything about these comments - I rarely if ever use a GUI library, and I've no idea if I'd use this one in future, but if you want "focused comments" beyond "it looks neat and seems like a fine project to go onto PyPI, but I don't think it's necessarily something that should go in the stdlib", then those were what I thought of off the cuff. Hope this is useful, Paul From barry at barrys-emacs.org Fri Aug 24 11:07:31 2018 From: barry at barrys-emacs.org (Barry Scott) Date: Fri, 24 Aug 2018 16:07:31 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: > On 23 Aug 2018, at 19:49, Mike Barnett wrote: > > Python has dropped the GUI ball, at least for beginners (in my opinion) > > While the Python language is awesomely compact, the GUI code is far from compact. Tkinter will create a nice looking GUI, but you?ve got to be skilled to use it. A student in their first week of Python programming is not going to be working with tkinter. > > It would be nice if beginners could double click a .py file and have it launch straight into a GUI, like most of the programs people are used to using. > > I think I?ve stumbled onto a framework that could work very well for creating fairly complex custom-layout GUIs. > > A package was released recently that uses this framework. It?s calledPySimpleGUI . It is a wrapper for tkinter so that it?ll run on almost any system Python will run on. There are no other dependencies and it?s a single file so that it can be easily dropped into someone?s project folder for immediate use without messing with pip installs. > > You can read more: > PySimpleGUI Tutorial > PySimpleGUI Cookbook > PySimpleGUI Reverence Document > A bunch of screenshots > > I am not seeking fame, recognition, or any other personal gain. I could care less if my name is associated with this design. My goal is to get Python off the command line and onto the screen. > > I am, however, making a serious in my attempt to get serious Python community members to weigh in on the best approach for getting acceptance. > > A sizeable user-base is likely a requirement. Interest has been brisk over the past few weeks with the basic GitHub stats having made great strides toward the EasyGUI values. It?s not a competition, but rather a benchmark to check progress. > > Comments, suggestions, pointers in new directions are all welcomed. I think that this is a very interesting project. Having a simple way to do GUI's is great for beginners and experienced people. What I'd suggest is that this would be better if you could extent beyond the simple using the underlying toolkit. But I'd not use tk as the base I'd use PyQt, IMHO, its the best toolkit for building GUIs with python. I'd love to start with the simple and build on top the complex stuff only when I need it. Barry > > Thank you very much for your time. I have not been a part of this mailing list in the past, so I hope I?m using it within the guidelines. Someone pointed me in this direction to get feedback and into the process. > > @mike > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From barry at barrys-emacs.org Fri Aug 24 11:17:41 2018 From: barry at barrys-emacs.org (Barry Scott) Date: Fri, 24 Aug 2018 16:17:41 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike (Mike Barnett) In-Reply-To: References: Message-ID: <8DF84B47-39EF-42E8-8710-5055F6200BB5@barrys-emacs.org> > On 23 Aug 2018, at 23:14, Hugh Fisher wrote: > >> Date: Thu, 23 Aug 2018 18:49:48 +0000 >> From: Mike Barnett >> >> Python has dropped the GUI ball, at least for beginners (in my opinion) >> >> While the Python language is awesomely compact, the GUI code is far from compact. Tkinter will create a nice looking GUI, but you've got to be skilled to use it. A student in their first week of Python programming is not going to be working with tkinter. >> >> It would be nice if beginners could double click a .py file and have it launch straight into a GUI, like most of the programs people are used to using. >> >> I think I've stumbled onto a framework that could work very well for creating fairly complex custom-layout GUIs... > > Have you looked at PySide2? It's the latest Python wrapper for the QT > cross platform > GUI framework. Or indeed PyQt5 that works great as a Qt python interface. Last time I looked PySide2 had a lot of catching up to do to match PyQt's API coverage. > A graphical "hello world" in QT is only half a dozen or less lines of > code in total, so > meets the simplicity requirement. I think 2 lines is simple, 12 is not really simple, is it? > The big drawback of QT for Python > until now has > been building the thing, but now it's on PyPI so "pip install" > (should) Just Work. You may have needed to build pySide2 yourself, however PyQt4 and PyQt5 have been pip installable for a long time. pip install PyQt5 Barry From andre.roberge at gmail.com Fri Aug 24 12:02:37 2018 From: andre.roberge at gmail.com (Andre Roberge) Date: Fri, 24 Aug 2018 13:02:37 -0300 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On Fri, Aug 24, 2018 at 12:42 PM Barry Scott wrote: > > > On 23 Aug 2018, at 19:49, Mike Barnett wrote: > > Python has dropped the GUI ball, at least for beginners (in my opinion) > > > snip > > I think that this is a very interesting project. Having a simple way to do > GUI's is great for beginners and experienced people. > > What I'd suggest is that this would be better if you could extent beyond > the simple using the underlying toolkit. > But I'd not use tk as the base I'd use PyQt, IMHO, its the best toolkit > for building GUIs with python. > While I agree that PyQt is better than tkinter, and I even wrote a simple interface for it (https://github.com/aroberge/easygui_qt), I think that any "single install, easy to use" GUI toolkit should be based on what's in the standard library and, for better or for worse, that is tkinter. So I think that the right choice was made for PySimpleGUI. Andr? > > I'd love to start with the simple and build on top the complex stuff only > when I need it. > > Barry > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Fri Aug 24 12:12:26 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Fri, 24 Aug 2018 17:12:26 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On Fri, 24 Aug 2018 at 16:27, Mike Barnett wrote: > 1. More documentation - reference docs specifically. I don't see > documentation of the call signature for sg.Text, for example. > > A little confused by this one. There are quite a bit of documentation. > Did you see the readme on the GitHub and here: > https://pysimplegui.readthedocs.io/en/latest/ Yes, I saw that. It has the call information about the Text widget and all the others. If it does, I didn't spot it. I did say I was skimming - and there's certainly a good amount of documentation. To some extent, I'm being picky here because while I like examples, I have found projects in the past that provide plenty of narrative and examples, but then when you start to want to do something more complicated, the details and specifics are missing. > Is this what you mean by a Signature? > > Text(Text, > scale=(None, None), > size=(None, None), > auto_size_text=None, > font=None, > text_color=None, > justification=None) > . > > Text - The text that's displayed > size - Element's size > auto_size_text - Bool. Change width to match size of text > font - Font name and size to use > text_color - text color > justification - Justification for the text. String - 'left', 'right', > 'center' > Yes, precisely. Apologies that I missed it. I don't have all of the newest features in there, like the Update method > because the doc is for version 2.9 on PyPI. I don't yet have the latest > GitHub release in there just yet. You'll find that information instead on > the Wiki: > https://github.com/MikeTheWatchGuy/PySimpleGUI/wiki/PySimpleGUI-Wiki > > > 2. Advanced features - how would I extend it if I have a need that it > doesn't cover? For example, a canvas object or an image? > I have Images. > Don't have Canvas. Any particular operations desired for the Canvas > Element should I have one? > Nope. I don't even have a need for a canvas. But what I have found in the past is that *anything* which is a "simple wrapper over X" always ends up in a situation where you need some feature from X that the simple wrapper doesn't cover, and you're left with the unpalatable choice of whether to omit functionality you want to provide, or rewrite your code to use X directly. So my question is more about "if you hit a need for something PySimpleGUI doesn't cover, what are your options? > 3. It doesn't seem to use native widgets (the buttons have a non-standard > look on my Windows PC). > The defaults can be easily changed. The default buttons are the one > widget that I modify from the system default. The reason was that the > system default is a gray button. It pretty much matches the background. > > If you want your buttons to all look like the system default, slip this > line of code at the top: > > sg.SetOptions(button_color=sg.COLOR_SYSTEM_DEFAULT) > OK. Personally, I'd argue quite strongly that "match the OS default" is the right default for a GUI library, but that's a hugely subjective area, and you're never going to please everyone. So do whatever works for you. Thank you again Paul... I learn something new from every reply ? No problem - glad it helped. Paul -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 24 12:50:49 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Fri, 24 Aug 2018 09:50:49 -0700 Subject: [Python-ideas] A GUI for beginners and experts alike (Mike Barnett) In-Reply-To: <8DF84B47-39EF-42E8-8710-5055F6200BB5@barrys-emacs.org> References: <8DF84B47-39EF-42E8-8710-5055F6200BB5@barrys-emacs.org> Message-ID: On Fri, Aug 24, 2018 at 8:17 AM, Barry Scott wrote: > > A graphical "hello world" in QT is only half a dozen or less lines of > > code in total, so > > meets the simplicity requirement. > > I think 2 lines is simple, 12 is not really simple, is it? > well, if all you need is a single dialog box with one or two entry fields, then yes, 2-4 lines is better than 12-14 lines -- but a lot. But if you are building an actual application, I'm not sure that the extra ten lines of startup code matters at all. And if those ten lines are essentially boilerplate that you can copy and paste from somewhere (Or have a gui-builder write for you), then even less so. That's not to say that the GUI toolkit slike wxPython, PySide, pyGTK aren't a bit more complex than they need to be, but much of that complex is there to support complex needs. I do think there is a place for tools that make "the easy stuff easy", but make sure that the complex stuff is still possible. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From python at mrabarnett.plus.com Fri Aug 24 13:07:35 2018 From: python at mrabarnett.plus.com (MRAB) Date: Fri, 24 Aug 2018 18:07:35 +0100 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: <21ee5060-8d8a-81c3-875c-de00f97ff0b8@mrabarnett.plus.com> On 2018-08-24 16:27, Mike Barnett wrote: > Liking the comments Paul! > [snip] > It has the call information about the Text widget and all the others. Is this what you mean by a Signature? > > Text(Text, > scale=(None, None), > size=(None, None), > auto_size_text=None, > font=None, > text_color=None, > justification=None) > . > > Text - The text that's displayed > size - Element's size > auto_size_text - Bool. Change width to match size of text > font - Font name and size to use > text_color - text color > justification - Justification for the text. String - 'left', 'right', 'center' > Static text is usually called a "label" in the GUIs I've used, including tkinter. [snip] > 2. Advanced features - how would I extend it if I have a need that it doesn't cover? For example, a canvas object or an image? > I have Images. > Don't have Canvas. Any particular operations desired for the Canvas Element should I have one? > A canvas can contain images, lines and shapes, which is useful for diagrams and drawings. > 3. It doesn't seem to use native widgets (the buttons have a non-standard look on my Windows PC). > The defaults can be easily changed. The default buttons are the one widget that I modify from the system default. The reason was that the system default is a gray button. It pretty much matches the background. > > If you want your buttons to all look like the system default, slip this line of code at the top: > > sg.SetOptions(button_color=sg.COLOR_SYSTEM_DEFAULT) > Looking at the page on PyPI, those coloured buttons do look odd to me. I think the default should be the system default. Also, I think those buttons labelled "Submit" should be labelled "OK". From wes.turner at gmail.com Fri Aug 24 13:16:01 2018 From: wes.turner at gmail.com (Wes Turner) Date: Fri, 24 Aug 2018 13:16:01 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike (Mike Barnett) In-Reply-To: References: <8DF84B47-39EF-42E8-8710-5055F6200BB5@barrys-emacs.org> Message-ID: Accessibility is a very real advantage of Qt solutions. http://doc.qt.io/qt-5/accessible.html """ [...] applications usable for people with different abilities. It is important to take different people's needs into account, for example, in case of low vision, hearing, dexterity, or cognitive problems. Some examples of accessibility measures are keyboard shortcuts, a high-contrast user interface that uses specially selected colors and fonts, or support for assistive tools such as screen readers and braille displays. A basic checklist that any application should aim for: - Usability - Usability and user centric design generally lead to more usable applications, including improvements for people with various abilities. - Fonts - Font settings should follow the system/platform. This allows users to select fonts for readability and increasing the font size. - Colors - Provide enough contrast and consider the most common cases of low vision and color blindness. Make sure that the application is usable, for example, for people with red/green blindness, and don't depend on colors only. - Scalable UI - A user interface that works in various sizes and properly supports different fonts and accommodates size changes. - Sounds - Do not exclusively rely on sound notifications, provide a visual alternative when a sound signal is imperative to using the application. - Spelling - Offer spell checking wherever it makes sense, even when only a single word is expected. - Assistive Technology - Support the use of assistive tools (AT). Either use standard widgets/controls which support ATs out of the box, or make sure that your custom widgets and controls support accessibility properly. """ Does anyone have any experience with building accessible native GUI apps with something other than Qt? Most of this a11y (accessibility) information is focused on web apps (that don't need an installer/updater to quickly respond to security issues): https://github.com/brunopulis/awesome-a11y On Friday, August 24, 2018, Chris Barker via Python-ideas < python-ideas at python.org> wrote: > On Fri, Aug 24, 2018 at 8:17 AM, Barry Scott > wrote: > >> > A graphical "hello world" in QT is only half a dozen or less lines of >> > code in total, so >> > meets the simplicity requirement. >> >> I think 2 lines is simple, 12 is not really simple, is it? >> > > well, if all you need is a single dialog box with one or two entry > fields, then yes, 2-4 lines is better than 12-14 lines -- but a lot. > > But if you are building an actual application, I'm not sure that the extra > ten lines of startup code matters at all. And if those ten lines are > essentially boilerplate that you can copy and paste from somewhere (Or have > a gui-builder write for you), then even less so. > > That's not to say that the GUI toolkit slike wxPython, PySide, pyGTK > aren't a bit more complex than they need to be, but much of that complex is > there to support complex needs. > > I do think there is a place for tools that make "the easy stuff easy", but > make sure that the complex stuff is still possible. > > -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 at noaa.gov > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 24 13:39:19 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Fri, 24 Aug 2018 10:39:19 -0700 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: A couple thoughts: You're essentially writing a new API on top of tkINter, you could probably have multiple "back-ends" -- i.e. be able to use the same code with wxPython or PySide behind it. In fact, there was an effort along these lines a few years back: http://www.cosc.canterbury.ac.nz/greg.ewing/python_gui/ I don't know that it's seen much development lately. Nope. I don't even have a need for a canvas. But what I have found in the > past is that *anything* which is a "simple wrapper over X" always ends up > in a situation where you need some feature from X that the simple wrapper > doesn't cover, and you're left with the unpalatable choice of whether to > omit functionality you want to provide, or rewrite your code to use X > directly. So my question is more about "if you hit a need for something > PySimpleGUI doesn't cover, what are your options? > This is key -- and one of the real issues around wrapping multiple GUI back-ends -- you end up having to do a lot of re-implementation of details. In fact, I always thought Pyton_guiu above really suffered from that conceptually. For example, if you used pyton-gui with a wxPython back end, you had: A python wrapper around a python wrapper around a C++ wrapper around each native toolkit. That's a lot of layers! So it's probably better to have a simpler stack -- and at the bottom, you probably need something with at least some C/C++ in it. And there are two options there: 1) re-implement widgets with native basic drawing and event handling. - this is what QT GTK, and TK do 2) Wrap the native widgets - this is what wxWidgets does The advantage of (1) is that most of your code is the same on all platform, widgets behave the same on all platforms, and there is less code to write to support a new platform. The advantage of (2) is that you get more native results -- the widgets ARE native. And it's easier to support the first platform -- you aren't writing a while GUI toolkit. But there is a lot more wrapper code to write for each new platform. And the results ARE going to be a bit platform-dependent in some places (though I've found that I need to write very little platform dependent code with wx) TK is essentially (1), though AIUI, it was originally written for X-windows, and the other platform have an X-windows emulation layer, and then all the TK code works with that. But the issue with TK is that it's really pretty old and krufty. It's great that it comes with the standard library, but now that yu can pip install pySide and wxPython, I'd consider working with one of those. I'd also make sure that you CAN "drop down" into the lower level toolkit fairly smoothly, if you do need something more complex that the basics. Finally -- I'm not sure the desktop is dead, but there is a heck of a lot going on in the browser. And if someone could write a simple GUI for a desktop app, and then easily prt that to a WebApp -- that would be great. I'm sure there are toolkits that do maybe it possible to write pure-python, and have all the javascript pre-written (Or generated) for you. While its not a complete solution, Jupyter Widgets does this within the Jupyter framework, for instance. -CHB > > >> 3. It doesn't seem to use native widgets (the buttons have a non-standard >> look on my Windows PC). >> The defaults can be easily changed. The default buttons are the one >> widget that I modify from the system default. The reason was that the >> system default is a gray button. It pretty much matches the background. >> >> If you want your buttons to all look like the system default, slip this >> line of code at the top: >> >> sg.SetOptions(button_color=sg.COLOR_SYSTEM_DEFAULT) >> > > OK. Personally, I'd argue quite strongly that "match the OS default" is > the right default for a GUI library, but that's a hugely subjective area, > and you're never going to please everyone. So do whatever works for you. > > Thank you again Paul... I learn something new from every reply ? > > > No problem - glad it helped. > > Paul > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- 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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 24 13:40:14 2018 From: chris.barker at noaa.gov (Chris Barker) Date: Fri, 24 Aug 2018 10:40:14 -0700 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: <21ee5060-8d8a-81c3-875c-de00f97ff0b8@mrabarnett.plus.com> References: <21ee5060-8d8a-81c3-875c-de00f97ff0b8@mrabarnett.plus.com> Message-ID: On Fri, Aug 24, 2018 at 10:07 AM, MRAB wrote: > A canvas can contain images, lines and shapes, which is useful for > diagrams and drawings. And the TK Canvas is kinda the "killer app" of TK. -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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From mike_barnett at hotmail.com Fri Aug 24 15:13:24 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Fri, 24 Aug 2018 19:13:24 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: Yea, software evolves. Things get layered on top of other things. It?s kind of how software works. Perhaps the point is getting lost here on my request to comment on the overall construct and simplicity. Let?s try a different approach? How about a quick example that you code up in your favorite GUI? Try and make it simple enough for a beginner to grasp as much as possible. Here we go: Take 3 numbers as input (A, B, C). Add them together. Display the result in a simple pop-up window. That?s a pretty typical kind of problem for the first few weeks of beginning programming. Maybe first few days. Let?s say I want my program to look and work like other windows programs. I want to show my friends, mom and dad that I can write software too. In this example, I would expect that kind of reasoning that would drive a desire for a GUI. @mike From: Chris Barker Sent: Friday, August 24, 2018 1:39 PM To: Paul Moore Cc: Mike Barnett ; Python-Ideas Subject: Re: [Python-ideas] A GUI for beginners and experts alike A couple thoughts: You're essentially writing a new API on top of tkINter, you could probably have multiple "back-ends" -- i.e. be able to use the same code with wxPython or PySide behind it. In fact, there was an effort along these lines a few years back: http://www.cosc.canterbury.ac.nz/greg.ewing/python_gui/ I don't know that it's seen much development lately. Nope. I don't even have a need for a canvas. But what I have found in the past is that *anything* which is a "simple wrapper over X" always ends up in a situation where you need some feature from X that the simple wrapper doesn't cover, and you're left with the unpalatable choice of whether to omit functionality you want to provide, or rewrite your code to use X directly. So my question is more about "if you hit a need for something PySimpleGUI doesn't cover, what are your options? This is key -- and one of the real issues around wrapping multiple GUI back-ends -- you end up having to do a lot of re-implementation of details. In fact, I always thought Pyton_guiu above really suffered from that conceptually. For example, if you used pyton-gui with a wxPython back end, you had: A python wrapper around a python wrapper around a C++ wrapper around each native toolkit. That's a lot of layers! So it's probably better to have a simpler stack -- and at the bottom, you probably need something with at least some C/C++ in it. And there are two options there: 1) re-implement widgets with native basic drawing and event handling. - this is what QT GTK, and TK do 2) Wrap the native widgets - this is what wxWidgets does The advantage of (1) is that most of your code is the same on all platform, widgets behave the same on all platforms, and there is less code to write to support a new platform. The advantage of (2) is that you get more native results -- the widgets ARE native. And it's easier to support the first platform -- you aren't writing a while GUI toolkit. But there is a lot more wrapper code to write for each new platform. And the results ARE going to be a bit platform-dependent in some places (though I've found that I need to write very little platform dependent code with wx) TK is essentially (1), though AIUI, it was originally written for X-windows, and the other platform have an X-windows emulation layer, and then all the TK code works with that. But the issue with TK is that it's really pretty old and krufty. It's great that it comes with the standard library, but now that yu can pip install pySide and wxPython, I'd consider working with one of those. I'd also make sure that you CAN "drop down" into the lower level toolkit fairly smoothly, if you do need something more complex that the basics. Finally -- I'm not sure the desktop is dead, but there is a heck of a lot going on in the browser. And if someone could write a simple GUI for a desktop app, and then easily prt that to a WebApp -- that would be great. I'm sure there are toolkits that do maybe it possible to write pure-python, and have all the javascript pre-written (Or generated) for you. While its not a complete solution, Jupyter Widgets does this within the Jupyter framework, for instance. -CHB 3. It doesn't seem to use native widgets (the buttons have a non-standard look on my Windows PC). The defaults can be easily changed. The default buttons are the one widget that I modify from the system default. The reason was that the system default is a gray button. It pretty much matches the background. If you want your buttons to all look like the system default, slip this line of code at the top: sg.SetOptions(button_color=sg.COLOR_SYSTEM_DEFAULT) OK. Personally, I'd argue quite strongly that "match the OS default" is the right default for a GUI library, but that's a hugely subjective area, and you're never going to please everyone. So do whatever works for you. Thank you again Paul... I learn something new from every reply ? No problem - glad it helped. Paul _______________________________________________ Python-ideas mailing list Python-ideas at python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/ -- 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 at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Fri Aug 24 15:25:37 2018 From: rosuav at gmail.com (Chris Angelico) Date: Sat, 25 Aug 2018 05:25:37 +1000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: On Sat, Aug 25, 2018 at 5:13 AM, Mike Barnett wrote: > Here we go: > > Take 3 numbers as input (A, B, C). Add them together. Display the result in a simple pop-up window. > > That?s a pretty typical kind of problem for the first few weeks of beginning programming. Maybe first few days. > Do you mean "beginning GUI programming", or are you saying that this kind of thing should be in someone's first few days of programming overall? I disagree with the latter; for the first days of a programmer's basic training, the REPL is ample. No GUI needed, don't even need input() at that stage. While I would generally teach input() before any GUI toolkit, the opposite decision is also valid, but definitely neither is needed right off the bat. For someone's earliest forays into GUI programming, I would actually *still* not word the challenge that way. I would keep everything in a SINGLE window, because that showcases a major strength of a GUI - that you can interact with it multiple times, rather than being forced into a linear workflow. So here's my alternative challenge: Take two numbers as inputs. Add them together and display them in a third field. Whenever either input is changed, recalculate the output. This requires proper event handling, so it's less likely to create a useless one-liner that has no bearing on real-world code. ChrisA From mike_barnett at hotmail.com Fri Aug 24 15:35:46 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Fri, 24 Aug 2018 19:35:46 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: So here's my alternative challenge: Take two numbers as inputs. Add them together and display them in a third field. Whenever either input is changed, recalculate the output. This requires proper event handling, so it's less likely to create a useless one-liner that has no bearing on real-world code. ------------------------------------ Sure thing... post yours. I'll go ahead and post mine first. Here's the window this code produces. https://user-images.githubusercontent.com/13696193/44604157-02a2ac00-a7b3-11e8-928b-f67c5f2b3961.jpg And here's the code in a more readable form since the email formatting sucks. https://user-images.githubusercontent.com/13696193/44604220-2cf46980-a7b3-11e8-86c5-ad3051222eaf.jpg It's rather, uhm, simple to do.... import PySimpleGUI as gui output = gui.Text('') layout = [ [gui.Text('Enter 2 numbers')], [gui.Text('A'), gui.InputText()], [gui.Text('B'), gui.InputText()], [gui.Text('Answer = '), output], ] form = gui.FlexForm('Realtime Updates', return_keyboard_events=True) form.LayoutAndRead(layout) while True: button, (a,b) = form.Read() try: answer = int(a) + int(b) output.Update(answer) except: pass @mike From mike_barnett at hotmail.com Fri Aug 24 16:38:29 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Fri, 24 Aug 2018 20:38:29 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: I should have mentioned that you need the GitHub version of the code in order to get the keyboard events. Rather than do a pip install you can download this file and put it in your project folder: https://github.com/MikeTheWatchGuy/PySimpleGUI/blob/master/PySimpleGUI.py Sorry for any confusion. I also got a question if this code blocks or is in a spin-loop. The answer is that the posted version blocks until some kind of form input. Should you want to turn the program into one that polls instead of blocks, the loop changes slightly to enable form close detection. It's basically the same with the Read call being replaced by ReadNonBlocking. while True: button, values = form.ReadNonBlocking() if button is None and values is None: break a, b = values try: output.Update(int(a) + int(b)) except: pass @mike -----Original Message----- From: Mike Barnett Sent: Friday, August 24, 2018 3:36 PM To: Chris Angelico ; Python-Ideas Subject: RE: [Python-ideas] A GUI for beginners and experts alike So here's my alternative challenge: Take two numbers as inputs. Add them together and display them in a third field. Whenever either input is changed, recalculate the output. This requires proper event handling, so it's less likely to create a useless one-liner that has no bearing on real-world code. ------------------------------------ Sure thing... post yours. I'll go ahead and post mine first. Here's the window this code produces. https://user-images.githubusercontent.com/13696193/44604157-02a2ac00-a7b3-11e8-928b-f67c5f2b3961.jpg And here's the code in a more readable form since the email formatting sucks. https://user-images.githubusercontent.com/13696193/44604220-2cf46980-a7b3-11e8-86c5-ad3051222eaf.jpg It's rather, uhm, simple to do.... import PySimpleGUI as gui output = gui.Text('') layout = [ [gui.Text('Enter 2 numbers')], [gui.Text('A'), gui.InputText()], [gui.Text('B'), gui.InputText()], [gui.Text('Answer = '), output], ] form = gui.FlexForm('Realtime Updates', return_keyboard_events=True) form.LayoutAndRead(layout) while True: button, (a,b) = form.Read() try: answer = int(a) + int(b) output.Update(answer) except: pass @mike From cpitclaudel at gmail.com Fri Aug 24 17:28:37 2018 From: cpitclaudel at gmail.com (=?UTF-8?Q?Cl=c3=a9ment_Pit-Claudel?=) Date: Fri, 24 Aug 2018 17:28:37 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: <583a6357-b286-7c30-4ebe-04347b68548c@gmail.com> Hi Mike, Thanks, this code is nice and short. Is adding 'if button is None: break' to the 'Read' version of your code the right way to make it exit when the main window is closed? (On my machine it enters an infinite loop after I close the main window). For comparison, I tried doing this with PyGObject. I created the UI with glade, which auto-generated the attached XML file. Then I had to write the following code (I had never used Glade or PyGObject before, so apologies if there are mistakes in the following): import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk def main(): builder = Gtk.Builder() builder.add_from_file("sum.glade") get = builder.get_object a, b, answer, window = get("a"), get("b"), get("answer"), get("window") def update_sum(_entry): try: tanswer = int(a.get_text()) + int(b.get_text()) answer.set_text(str(tanswer)) except ValueError: pass a.connect("changed", update_sum) b.connect("changed", update_sum) window.connect("destroy", Gtk.main_quit) window.show_all() Gtk.main() if __name__ == '__main__': main() Having a visual editor for the UI feels like a plus, and I find the resulting XML verbose but acceptably readable. On the other hand, I like the conciseness of your UI specs. Cheers, Cl?ment. On 2018-08-24 16:38, Mike Barnett wrote: > I should have mentioned that you need the GitHub version of the code in order to get the keyboard events. Rather than do a pip install you can download this file and put it in your project folder: > > https://github.com/MikeTheWatchGuy/PySimpleGUI/blob/master/PySimpleGUI.py > > Sorry for any confusion. > > I also got a question if this code blocks or is in a spin-loop. The answer is that the posted version blocks until some kind of form input. Should you want to turn the program into one that polls instead of blocks, the loop changes slightly to enable form close detection. It's basically the same with the Read call being replaced by ReadNonBlocking. > > while True: > button, values = form.ReadNonBlocking() > if button is None and values is None: > break > a, b = values > try: > output.Update(int(a) + int(b)) > except: > pass > > > > @mike > > -----Original Message----- > From: Mike Barnett > Sent: Friday, August 24, 2018 3:36 PM > To: Chris Angelico ; Python-Ideas > Subject: RE: [Python-ideas] A GUI for beginners and experts alike > > > So here's my alternative challenge: > > Take two numbers as inputs. Add them together and display them in a third field. Whenever either input is changed, recalculate the output. > > This requires proper event handling, so it's less likely to create a useless one-liner that has no bearing on real-world code. > > ------------------------------------ > > > > Sure thing... post yours. I'll go ahead and post mine first. > > Here's the window this code produces. > > https://user-images.githubusercontent.com/13696193/44604157-02a2ac00-a7b3-11e8-928b-f67c5f2b3961.jpg > > And here's the code in a more readable form since the email formatting sucks. > https://user-images.githubusercontent.com/13696193/44604220-2cf46980-a7b3-11e8-86c5-ad3051222eaf.jpg > > It's rather, uhm, simple to do.... > > > import PySimpleGUI as gui > > output = gui.Text('') > > layout = [ [gui.Text('Enter 2 numbers')], > [gui.Text('A'), gui.InputText()], > [gui.Text('B'), gui.InputText()], > [gui.Text('Answer = '), output], > ] > > form = gui.FlexForm('Realtime Updates', return_keyboard_events=True) > form.LayoutAndRead(layout) > while True: > button, (a,b) = form.Read() > try: > answer = int(a) + int(b) > output.Update(answer) > except: > pass > > > @mike > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- A non-text attachment was scrubbed... Name: sum.glade Type: application/x-glade Size: 2781 bytes Desc: not available URL: From moiein2000 at gmail.com Fri Aug 24 19:51:04 2018 From: moiein2000 at gmail.com (Matthew Einhorn) Date: Fri, 24 Aug 2018 19:51:04 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: <583a6357-b286-7c30-4ebe-04347b68548c@gmail.com> References: <583a6357-b286-7c30-4ebe-04347b68548c@gmail.com> Message-ID: Hi Mike I'm not sure this thread is python-ideas appropriate, but since the challenge is out, here it is using Kivy. The code and result is at https://gist.github.com/matham/45c4f1fbd8c3fccf6557b3b48356cd50 (image https://gist.githubusercontent.com/matham/45c4f1fbd8c3fccf6557b3b48356cd50/raw/dbbf74f17ad4beab49f022bbf43fcc72ff725084/kivy_gui.png). The code is also inlined below. I wrote it to be one file so I used the string version (load_string) for defining the GUI, but the GUI definition could have been written as a separate kv file. I could also have written it using pure python, but that is more verbose and less intuitive. Also, Kivy works on pretty much all platforms (windows, linux, osx, android, ios) and is written in pure python (and cython) on top of opengl. All the best, Matt P.S. here's the inlined code: from kivy.lang import Builder from kivy.app import runTouchApp runTouchApp(Builder.load_string(''' #:import Factory kivy.factory.Factory BoxLayout: orientation: 'vertical' padding: "12dp" spacing: "12dp" Label: text: "Please enter 3 numbers" BoxLayout: spacing: "10dp" Entry: id: a hint_text: "A" Entry: id: b hint_text: "B" Entry: id: c hint_text: "C" Label: text: "The sum is {}".format(a.val + b.val + c.val) : input_filter: "float" val: float(self.text) if self.text else 0 ''')) On Fri, Aug 24, 2018 at 5:28 PM Cl?ment Pit-Claudel wrote: > Hi Mike, > > Thanks, this code is nice and short. Is adding 'if button is None: break' > to the 'Read' version of your code the right way to make it exit when the > main window is closed? (On my machine it enters an infinite loop after I > close the main window). > > For comparison, I tried doing this with PyGObject. > I created the UI with glade, which auto-generated the attached XML file. > Then I had to write the following code (I had never used Glade or PyGObject > before, so apologies if there are mistakes in the following): > > import gi > gi.require_version('Gtk', '3.0') > from gi.repository import Gtk > > def main(): > builder = Gtk.Builder() > builder.add_from_file("sum.glade") > > get = builder.get_object > a, b, answer, window = get("a"), get("b"), get("answer"), get("window") > > def update_sum(_entry): > try: > tanswer = int(a.get_text()) + int(b.get_text()) > answer.set_text(str(tanswer)) > except ValueError: > pass > > a.connect("changed", update_sum) > b.connect("changed", update_sum) > window.connect("destroy", Gtk.main_quit) > > window.show_all() > Gtk.main() > > if __name__ == '__main__': > main() > > Having a visual editor for the UI feels like a plus, and I find the > resulting XML verbose but acceptably readable. > On the other hand, I like the conciseness of your UI specs. > > Cheers, > Cl?ment. > > On 2018-08-24 16:38, Mike Barnett wrote: > > I should have mentioned that you need the GitHub version of the code in > order to get the keyboard events. Rather than do a pip install you can > download this file and put it in your project folder: > > > > > https://github.com/MikeTheWatchGuy/PySimpleGUI/blob/master/PySimpleGUI.py > > > > Sorry for any confusion. > > > > I also got a question if this code blocks or is in a spin-loop. The > answer is that the posted version blocks until some kind of form input. > Should you want to turn the program into one that polls instead of blocks, > the loop changes slightly to enable form close detection. It's basically > the same with the Read call being replaced by ReadNonBlocking. > > > > while True: > > button, values = form.ReadNonBlocking() > > if button is None and values is None: > > break > > a, b = values > > try: > > output.Update(int(a) + int(b)) > > except: > > pass > > > > > > > > @mike > > > > -----Original Message----- > > From: Mike Barnett > > Sent: Friday, August 24, 2018 3:36 PM > > To: Chris Angelico ; Python-Ideas < > python-ideas at python.org> > > Subject: RE: [Python-ideas] A GUI for beginners and experts alike > > > > > > So here's my alternative challenge: > > > > Take two numbers as inputs. Add them together and display them in a > third field. Whenever either input is changed, recalculate the output. > > > > This requires proper event handling, so it's less likely to create a > useless one-liner that has no bearing on real-world code. > > > > ------------------------------------ > > > > > > > > Sure thing... post yours. I'll go ahead and post mine first. > > > > Here's the window this code produces. > > > > > https://user-images.githubusercontent.com/13696193/44604157-02a2ac00-a7b3-11e8-928b-f67c5f2b3961.jpg > > > > And here's the code in a more readable form since the email formatting > sucks. > > > https://user-images.githubusercontent.com/13696193/44604220-2cf46980-a7b3-11e8-86c5-ad3051222eaf.jpg > > > > It's rather, uhm, simple to do.... > > > > > > import PySimpleGUI as gui > > > > output = gui.Text('') > > > > layout = [ [gui.Text('Enter 2 numbers')], > > [gui.Text('A'), gui.InputText()], > > [gui.Text('B'), gui.InputText()], > > [gui.Text('Answer = '), output], > > ] > > > > form = gui.FlexForm('Realtime Updates', return_keyboard_events=True) > > form.LayoutAndRead(layout) > > while True: > > button, (a,b) = form.Read() > > try: > > answer = int(a) + int(b) > > output.Update(answer) > > except: > > pass > > > > > > @mike > > _______________________________________________ > > Python-ideas mailing list > > Python-ideas at python.org > > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Fri Aug 24 19:56:16 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Sat, 25 Aug 2018 11:56:16 +1200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: <5B809B20.70407@canterbury.ac.nz> Chris Barker via Python-ideas wrote: > In fact, there was an effort along these lines a few years back: > > http://www.cosc.canterbury.ac.nz/greg.ewing/python_gui/ > > I don't know that it's seen much development lately. It hasn't, sorry to say. Turns out that writing and maintaining what is effectively 3 complete GUI toolkits takes a more copious supply of round tuits than I have at the moment. :-( > In fact, I always thought Pyton_guiu above really suffered from that > conceptually. For example, if you used pyton-gui with a wxPython back > end, you had: > > A python wrapper around a python wrapper around a C++ wrapper around > each native toolkit. If you're talking about my PyGUI project, using it with wPython doesn't really make sense. I specifically wanted to avoid the multiple-wrapper problem, so I decided *not* to wrap any existing cross-platform GUI toolkit. The goal is to provide exactly one high-quality implementation for each platform, with as few layers as practicable between the Python API and the platform's native GUI facilities. One result of that is that PyGUI is not really structured as a "front end" and "back end" with a defined interface between them. There is generic code and platform-specific code, but they're fairly closely intertwined. Implementations on top of wxPython, Qt etc. could probably be created, but I won't be doing it myself, because it would take a lot of work and I don't think it would be necessary or desirable. > 1) re-implement widgets with native basic drawing and event handling. > - this is what QT GTK, and TK do > 2) Wrap the native widgets > - this is what wxWidgets does PyGUI does (2). > TK is essentially (1), though AIUI, it was originally written for > X-windows, and the other platform have an X-windows emulation layer, and > then all the TK code works with that. Yeah, X Windows is a bit special, because there is no such thing os a "native" look and feel for widgets on X -- there have been multiple GUI toolkits for X from the beginning, each with its own style. So Tk inventing a new one all of its own wasn't really a bad thing at the time. > I'd also make sure that you CAN "drop down" into the lower level toolkit > fairly smoothly, if you do need something more complex that the basics. PyGUI provides everything you need to create a custom widget, without needing to go down to a lower level. You could also create a wrapper for a native widget that PyGUI doesn't already provide, but the techniques for doing so are currently undocumented and might change between releases. > > Finally -- I'm not sure the desktop is dead, but there is a heck of a > lot going on in the browser. And if someone could write a simple GUI for > a desktop app, and then easily prt that to a WebApp -- that would be great. Pyjamas seems to be something like that: https://pypi.org/project/Pyjamas/ -- Greg From chris.barker at noaa.gov Fri Aug 24 20:07:11 2018 From: chris.barker at noaa.gov (Chris Barker - NOAA Federal) Date: Fri, 24 Aug 2018 20:07:11 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: while True: button, (a,b) = form.Read() try: answer = int(a) + int(b) output.Update(answer) except: pass Whoa! You really want people to write their own event loop? That seems like a bad idea to me. If you want people to not have to think about events much, maybe look at traitsui for ideas. http://docs.enthought.com/traitsui/ -CHB -------------- next part -------------- An HTML attachment was scrubbed... URL: From mike_barnett at hotmail.com Fri Aug 24 20:20:51 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Sat, 25 Aug 2018 00:20:51 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <583a6357-b286-7c30-4ebe-04347b68548c@gmail.com> Message-ID: Nice Matt! Thanks for taking the time to code it up! It?s great to see examples like these. @mike From: Python-ideas On Behalf Of Matthew Einhorn Sent: Friday, August 24, 2018 7:51 PM To: python-ideas at python.org Subject: Re: [Python-ideas] A GUI for beginners and experts alike Hi Mike I'm not sure this thread is python-ideas appropriate, but since the challenge is out, here it is using Kivy. The code and result is at https://gist.github.com/matham/45c4f1fbd8c3fccf6557b3b48356cd50 (image https://gist.githubusercontent.com/matham/45c4f1fbd8c3fccf6557b3b48356cd50/raw/dbbf74f17ad4beab49f022bbf43fcc72ff725084/kivy_gui.png). The code is also inlined below. I wrote it to be one file so I used the string version (load_string) for defining the GUI, but the GUI definition could have been written as a separate kv file. I could also have written it using pure python, but that is more verbose and less intuitive. Also, Kivy works on pretty much all platforms (windows, linux, osx, android, ios) and is written in pure python (and cython) on top of opengl. All the best, Matt P.S. here's the inlined code: from kivy.lang import Builder from kivy.app import runTouchApp runTouchApp(Builder.load_string(''' #:import Factory kivy.factory.Factory BoxLayout: orientation: 'vertical' padding: "12dp" spacing: "12dp" Label: text: "Please enter 3 numbers" BoxLayout: spacing: "10dp" Entry: id: a hint_text: "A" Entry: id: b hint_text: "B" Entry: id: c hint_text: "C" Label: text: "The sum is {}".format(a.val + b.val + c.val) : input_filter: "float" val: float(self.text) if self.text else 0 ''')) On Fri, Aug 24, 2018 at 5:28 PM Cl?ment Pit-Claudel > wrote: Hi Mike, Thanks, this code is nice and short. Is adding 'if button is None: break' to the 'Read' version of your code the right way to make it exit when the main window is closed? (On my machine it enters an infinite loop after I close the main window). For comparison, I tried doing this with PyGObject. I created the UI with glade, which auto-generated the attached XML file. Then I had to write the following code (I had never used Glade or PyGObject before, so apologies if there are mistakes in the following): import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk def main(): builder = Gtk.Builder() builder.add_from_file("sum.glade") get = builder.get_object a, b, answer, window = get("a"), get("b"), get("answer"), get("window") def update_sum(_entry): try: tanswer = int(a.get_text()) + int(b.get_text()) answer.set_text(str(tanswer)) except ValueError: pass a.connect("changed", update_sum) b.connect("changed", update_sum) window.connect("destroy", Gtk.main_quit) window.show_all() Gtk.main() if __name__ == '__main__': main() Having a visual editor for the UI feels like a plus, and I find the resulting XML verbose but acceptably readable. On the other hand, I like the conciseness of your UI specs. Cheers, Cl?ment. On 2018-08-24 16:38, Mike Barnett wrote: > I should have mentioned that you need the GitHub version of the code in order to get the keyboard events. Rather than do a pip install you can download this file and put it in your project folder: > > https://github.com/MikeTheWatchGuy/PySimpleGUI/blob/master/PySimpleGUI.py > > Sorry for any confusion. > > I also got a question if this code blocks or is in a spin-loop. The answer is that the posted version blocks until some kind of form input. Should you want to turn the program into one that polls instead of blocks, the loop changes slightly to enable form close detection. It's basically the same with the Read call being replaced by ReadNonBlocking. > > while True: > button, values = form.ReadNonBlocking() > if button is None and values is None: > break > a, b = values > try: > output.Update(int(a) + int(b)) > except: > pass > > > > @mike > > -----Original Message----- > From: Mike Barnett > > Sent: Friday, August 24, 2018 3:36 PM > To: Chris Angelico >; Python-Ideas > > Subject: RE: [Python-ideas] A GUI for beginners and experts alike > > > So here's my alternative challenge: > > Take two numbers as inputs. Add them together and display them in a third field. Whenever either input is changed, recalculate the output. > > This requires proper event handling, so it's less likely to create a useless one-liner that has no bearing on real-world code. > > ------------------------------------ > > > > Sure thing... post yours. I'll go ahead and post mine first. > > Here's the window this code produces. > > https://user-images.githubusercontent.com/13696193/44604157-02a2ac00-a7b3-11e8-928b-f67c5f2b3961.jpg > > And here's the code in a more readable form since the email formatting sucks. > https://user-images.githubusercontent.com/13696193/44604220-2cf46980-a7b3-11e8-86c5-ad3051222eaf.jpg > > It's rather, uhm, simple to do.... > > > import PySimpleGUI as gui > > output = gui.Text('') > > layout = [ [gui.Text('Enter 2 numbers')], > [gui.Text('A'), gui.InputText()], > [gui.Text('B'), gui.InputText()], > [gui.Text('Answer = '), output], > ] > > form = gui.FlexForm('Realtime Updates', return_keyboard_events=True) > form.LayoutAndRead(layout) > while True: > button, (a,b) = form.Read() > try: > answer = int(a) + int(b) > output.Update(answer) > except: > pass > > > @mike > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > _______________________________________________ Python-ideas mailing list Python-ideas at python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.barker at noaa.gov Fri Aug 24 20:28:18 2018 From: chris.barker at noaa.gov (Chris Barker - NOAA Federal) Date: Fri, 24 Aug 2018 20:28:18 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: <5B809B20.70407@canterbury.ac.nz> References: <5B809B20.70407@canterbury.ac.nz> Message-ID: > If you're talking about my PyGUI project, using it with > wPython doesn't really make sense. Now that you say that, I think I?m mingling memories ? there was another project that attempted to wrap TKInter, wxPython, QT .. I always thought that was ill advised. > The goal is to provide exactly one high-quality > implementation for each platform, with as few layers as > practicable between the Python API and the platform's native > GUI facilities. So kinda like wxWidgets but in Python ? which would be nice. wxPython definitely suffers from its C++ underpinnings. > Implementations on top > of wxPython, Qt etc. could probably be created, QT might make some sense? you need something on top of X, don?t you? >> I'd also make sure that you CAN "drop down" into the lower level toolkit fairly smoothly, if you do need something more complex that the basics. > > PyGUI provides everything you need to create a custom widget, > without needing to go down to a lower level. In that context, I was thinking about the OP?s concept? very high level, pretty much declarative. It?s going to run into limitations fast. So there should be s way to customize user interaction. Too bad all the cool kids are doing web dev these days ? hard to get help with a desktop GUI project :-( > Pyjamas seems to be something like that: > > https://pypi.org/project/Pyjamas/ Or it was 6 years ago :-( -CHB From stephanh42 at gmail.com Fri Aug 24 21:06:56 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Sat, 25 Aug 2018 03:06:56 +0200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <5B809B20.70407@canterbury.ac.nz> Message-ID: Op za 25 aug. 2018 02:28 schreef Chris Barker - NOAA Federal via Python-ideas : > > > Too bad all the cool kids are doing web dev these days ? hard to get > help with a desktop GUI project :-( > Pywebview seems interesting, uses a platform webview to put up the UI; https://github.com/r0x0r/pywebview But not so newbie-friendly I am afraid... Stephan > > Pyjamas seems to be something like that: > > > > https://pypi.org/project/Pyjamas/ > > Or it was 6 years ago :-( > > -CHB > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Fri Aug 24 21:15:05 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Sat, 25 Aug 2018 13:15:05 +1200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <5B809B20.70407@canterbury.ac.nz> Message-ID: <5B80AD99.9050003@canterbury.ac.nz> Chris Barker - NOAA Federal wrote: > Now that you say that, I think I?m mingling memories ? there was > another project that attempted to wrap TKInter, wxPython, QT .. I > always thought that was ill advised. You're probably thinking of "anygui" (named in the spirit of "anydbm"). As far as I remember, it never really got off the ground. > QT might make some sense? you need something on top of X, don?t you? Linux is currently covered by a Gtk implementation, which seems to be about as close as you get to a "native" GUI toolkit on Linux. X-based systems without Gtk are currently out ofscope -- but contributions are always welcome! -- Greg From mike_barnett at hotmail.com Fri Aug 24 21:16:57 2018 From: mike_barnett at hotmail.com (Mike Barnett) Date: Sat, 25 Aug 2018 01:16:57 +0000 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <5B809B20.70407@canterbury.ac.nz> Message-ID: It?s fascinating just how many packages are being dragged out for examination or clobbering other than the one that I asked for assistance/help on. I see the code of conduct link in the thread. Perhaps a review would be helpful. Unsubscribing from this mess. ?Python Ideas? ? @mike From: Python-ideas On Behalf Of Stephan Houben Sent: Friday, August 24, 2018 9:07 PM To: Chris Barker Cc: Python-Ideas Subject: Re: [Python-ideas] A GUI for beginners and experts alike Op za 25 aug. 2018 02:28 schreef Chris Barker - NOAA Federal via Python-ideas >: Too bad all the cool kids are doing web dev these days ? hard to get help with a desktop GUI project :-( Pywebview seems interesting, uses a platform webview to put up the UI; https://github.com/r0x0r/pywebview But not so newbie-friendly I am afraid... Stephan > Pyjamas seems to be something like that: > > https://pypi.org/project/Pyjamas/ Or it was 6 years ago :-( -CHB _______________________________________________ Python-ideas mailing list Python-ideas at python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Fri Aug 24 21:20:35 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Sat, 25 Aug 2018 13:20:35 +1200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: <5B80AEE3.4020103@canterbury.ac.nz> Here are some PyGUI versions of the ABC Challenge. #---------------- Modal -------------------- from GUI import ModalDialog, Label, TextField, Row, Column, Grid from GUI.StdButtons import DefaultButton, CancelButton from GUI.Alerts import note_alert a = TextField(width = 100) b = TextField(width = 100) c = TextField(width = 100) buttons = Row([DefaultButton(), CancelButton()]) dlog = ModalDialog(title = "ABC Challenge") dlog.add(Column([ Grid([ [Label("A"), a], [Label("B"), b], [Label("C"), c], ]), buttons], padding = (10, 10))) dlog.shrink_wrap() if dlog.present(): note_alert("Sum = %s" % (int(a.text) + int(b.text) + int(c.text))) #---------------- Non-Modal ------------------ from GUI import Window, Label, TextField, Grid, application def update(): try: c.text = str(int(a.text) + int(b.text)) except ValueError: c.text = "" a = TextField(width = 100, text_changed_action = update) b = TextField(width = 100, text_changed_action = update) c = TextField(width = 100, editable = False) win = Window(title = "ABC Challenge") win.add( Grid([ [Label("A"), a], [Label("B"), b], [Label("A + B"), c], ], padding = (10, 10))) win.shrink_wrap() win.show() application().run() -- Greg From greg.ewing at canterbury.ac.nz Fri Aug 24 21:47:13 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Sat, 25 Aug 2018 13:47:13 +1200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <5B809B20.70407@canterbury.ac.nz> Message-ID: <5B80B521.9000709@canterbury.ac.nz> Mike Barnett wrote: > Unsubscribing from this mess. ?Python Ideas? ? We didn't mean to drive you away! Python discussions have a tendency to roam far and wide. It doesn't mean we're not interested in what you have to say. Any new package is naturally going to invite comparisons with similar things that have been done before. That's not a bad thing -- it's always good to see what others have done in the same field. Although your package is unlikely to be put into the stdlib any time soon, it would be a fine thing to have on PyPI, and I'm sure there are people here willing to help you develop it. You may just need to be prepared to ignore some digressions. -- Greg From cody.piersall at gmail.com Fri Aug 24 23:37:01 2018 From: cody.piersall at gmail.com (Cody Piersall) Date: Fri, 24 Aug 2018 22:37:01 -0500 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <20180824004427.GV24160@ando.pearwood.info> Message-ID: On Thu, Aug 23, 2018 at 11:59 PM Steve Barnes wrote: > There are already 2 ways of turning a python program that uses argparse > into a GUI, (Gooey for wx & Quicken for QT IIRC), with minimal > modification. There are a lot of good arguments for teaching people to > use argparse and to write their code to be able to run from the command > line but there is not a mechanism that I am aware of for turning > argparse based code into a TK GUI this might be a fruitful area to look > at. I started working on a project that does that a few years ago. It requires that you provide a function that takes an argparse.Namespace, and then it can make a GUI using tkinter. The code is on GitHub: https://github.com/codypiersall/cligui. The license is MIT. Example script using cligui: ``` # Makes a GUI appear. How fortunate! import argparse import cligui def get_parser(): """Create a parser that does all the best things.""" p = argparse.ArgumentParser(description='such a good program') p.add_argument('infile') p.add_argument('outfile') return p def do_the_best_things(args): """This does the best things. Note: "args" is an argparse.Namespace -- the thing you get back whenever you call argparse.ArgumentParser().parse_args(). """ print('got args', args) def main(): """This incredible function will make a GUI appear. Remarkable!""" p = get_parser() # call cligui.CliGui with the parser, and a function that takes an # argparse.Namespace as its argument. cligui.CliGui(p, do_the_best_things) if __name__ == '__main__': main() ``` For background: the goal was to be able to let my less-technical coworkers use scripts that I had written; but then I got a job elsewhere and stopped working on this. Cody From wes.turner at gmail.com Sat Aug 25 00:47:03 2018 From: wes.turner at gmail.com (Wes Turner) Date: Sat, 25 Aug 2018 00:47:03 -0400 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: Message-ID: ipywidgets and toga* implementations of the ABC demo: | source: https://github.com/westurner/guidemo # ipywidgetsdemo/ipywidgets_abc_demo.py (.ipynb) # # ipywidgets ABC demo # - Update an output widget with the sum of two input widgets when the 'change' event fires # In[1]: # https://ipywidgets.readthedocs.io/en/latest/examples/Using%20Interact.html # https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html from ipywidgets import interact import ipywidgets as widgets def add(x, y): return sum((x,y)) widget_x = widgets.IntText(value=0, description='#1') widget_y = widgets.IntText(value=0, description='#2') interact(add, x=widget_x, y=widget_y) # In[2]: # https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html#Registering-callbacks-to-trait-changes-in-the-kernel from IPython.display import display from ipywidgets import interact import ipywidgets as widgets widget_x = widgets.IntText(value=0, description='#1') widget_y = widgets.IntText(value=0, description='#2') widget_sigma = widgets.IntText(value=0, description='sum') def add_event(event): widget_sigma.value = sum((widget_x.value, widget_y.value)) widget_x.observe(add_event, names='value') widget_y.observe(add_event, names='value') display(widgets.HBox([widget_x, widget_y, widget_sigma])) # togaabcdemo/app.py import toga from toga.style import Pack from toga.style.pack import COLUMN, ROW class TogaAbcDemo(toga.App): def add_numbers(self, widget): # TODO: validate that n*_input.value are numbers n1, n2 = self.n1_input.value, self.n2_input.value n3 = sum(n1, n2) if ((n1 is not None) and (n2 is not None)) else None print("%r + %r = %r" % (n1, n2, n3)) self.n3_input.value = n3 def startup(self): # Create a main window with a name matching the app self.main_window = toga.MainWindow(title=self.name) # Create a main content box main_box = toga.Box() self.n1_input = toga.TextInput( placeholder='#1', on_change=self.add_numbers) self.n2_input = toga.TextInput( placeholder='#2', on_change=self.add_numbers) self.n3_input = toga.TextInput( placeholder='Sum', readonly=True) main_box.add(self.n1_input) main_box.add(self.n2_input) main_box.add(self.n3_input) # Add the content on the main window self.main_window.content = main_box # Show the main window self.main_window.show() def main(): return TogaAbcDemo('Toga ABC Demo', 'org.westurner.togaabcdemo.togaabcdemo') On Fri, Aug 24, 2018 at 4:12 AM Wes Turner wrote: > > > On Thursday, August 23, 2018, Jonathan Fine wrote: > >> Hi Mike >> >> Thank you for your prompt response. You wrote >> >> > Maybe we're on different planes? >> > >> > I'm talking about 5 lines of Python code to get a custom layout GUI on >> the screen: >> > >> > import PySimpleGUI as sg >> > >> > form = sg.FlexForm('Simple data entry form') # begin with a blank form >> > >> > layout = [ >> > [sg.Text('Please enter your Name, Address, Phone')], >> > [sg.Text('Name', size=(15, 1)), sg.InputText('1', >> key='name')], >> > [sg.Text('Address', size=(15, 1)), sg.InputText('2', >> key='address')], >> > [sg.Text('Phone', size=(15, 1)), sg.InputText('3', >> key='phone')], >> > [sg.Submit(), sg.Cancel()] >> > ] >> > >> > button, values = form.LayoutAndRead(layout) >> >> The execution of this code, depends on PySimpleGUI, which in turn depends >> on tkinter, which is in turn a thin layer on top of Tcl/Tk. And Tcl/Tk >> provides the GUI layer. >> (See https://docs.python.org/3/library/tk.html.) >> >> I'm suggest that sometimes it may be better to use HTML5 to provide the >> GUI layer. I pointed to Elm, to show how powerful HTML5 has become. >> > > BeeWare uses Toga (a widget toolkit) and Briefcase (a build tool) to build > native GUIs and SPA web apps > > > Write your apps in Python and release them on iOS, Android, Windows, > MacOS, Linux, Web, and tvOS using rich, native user interfaces. One > codebase. Multiple apps. > > Briefcase can build Django apps. > > https://pybee.org > https://pybee.org/project/using/ > https://briefcase.readthedocs.io/en/latest/tutorial/tutorial-0.html > https://toga.readthedocs.io/en/latest/tutorial/tutorial-0.html > > It's definitely not a single file module, though. > > Bottle is a single file web framework ('microframework'); but it doesn't > have a widget toolkit. > > Web development is not as easy to learn as a simple GUI api for beginners > (and then learning what to avoid in terms of websec is a lot to learn). > > There was a thread about deprecating Tk awhile back. There also I think I > mentioned that asyncio event loop support would be great for real world > apps. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Sat Aug 25 04:04:45 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Sat, 25 Aug 2018 10:04:45 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> Message-ID: Hi, @Paul Moore: thanks for pointing out that many people are not familiar with design-by-contract. I was not aware of that. Let me give you a very short introduction into contracts and what they are good for. I'll review some existing libraries and highlight what features we missed (and why we developed our own library). I will finally conclude with why all these solutions (including our own one) are not a replacement for a proper support of design-by-contract in the language. Design-by-Contract Design-by-contract was gradually introduced as a concept by Bertrand Meyer in the 1980ies to provide a formal and verifiable interface specification between the software components. Up to then the interfaces were usually defined formally in terms of abstract data types (think of records / structs and classes). He extended abstract data types by adding "contract" conditions that should hold at different points during the execution of a program. The contracts allow you to formally write down your expectations about the program (as opposed to writing it informally in documentation of a class or a function). Hence we can automatically test that they hold either statically or during the execution of the program. This gives us many-fold benefits: - contracts prevent code rot (since they can be checked by a compiler or a static analysis tool such as mypy), - allow us to have much more sophisticated automatic generation of unit tests and automatic formal proofs of a program, - make the documentation explicit, accurate and verifiable and - accelerate the development since errors are caught early. The contracts are categorized as follows depending on at which point in the program they are verified: - Preconditions are contracts that should hold before the execution of a function. The *caller* is responsible to fulfill the preconditions. - Postconditions are contracts that should hold after the execution of a function. The *callee* is responsible to fulfill the postconditions. - Invariants should hold throughout the execution of the program. There are two types of invariants: loop invariants and class invariants. - Loop invariants should hold before and after each iteration step of a loop. - Class invariants should hold throughout the life time of a class ( *i.e.* between the calls to the public methods). The class invariants are suspended during the construction of an instance and in private methods to avoid cycles. You can think of the constructor method and public methods being responsible to fulfill the class invariants. The concept of design-by-contract is not limited only to concrete classes, but can be also applied to class hierarchies. Preconditions, postconditions and invariants are inherited. They can be also modified in the following ways: - The child class needs to fulfill all the invariants of its antecedent classes and its own ones. - The preconditions of a function of a child class can "weaken" or "relax" the preconditions of the parent class. In other words, it needs to fulfill *either* the preconditions of the parent class *or *its own set of preconditions. This is reflected in Eiffel by using the keyword *require else.* - The postconditions of a a child class can "strengthen" or "tighten" the postconditions of the parent class. The function needs to fulfill all the postconditions of the parent class' function *and *its own set of postconditions. In Eiffel, this is designated with *ensure then* keyword. Invariants operate only on the values of instance properties. Preconditions operate on both function arguments and instance properties. Postconditions need yet one more instrument: they operate on function arguments, instance properties and the result of a function, but can access all these values both at their *old* state, before the function call, and their *new *state, after the function call. In Eiffel, you use the keyword *old* to indicate the value before the function call. Let me illustrate the concepts by adapting the examples from https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions and https://www.eiffel.org/doc/eiffel/ET-_Inheritance. I will paraphrase the example code in Python assuming that invariant, require, ensure and old were introduced as keywords. *class *Account: *def *__init__(self, balance: int) -> *None*: self.balance = balance self.deposits = [] *# type: List[int] **def *update(self, sum: int)->*None*: require: sum >= 0 self.balance += sum self.deposits.append(sum) ensure: len(self.deposits) = len(old self.deposits) + 1, *"one more deposit" *ensure: self.balance = old self.balance + sum, *"updated" *invariant: *not *self.deposits *or *self.balance == sum(self.deposits), *"consistent balance" *invariant: self.deposits *or *self.balance == 0, *"zero if no deposits" class *CheckingAccount(Account): *def *update(self, sum: int) -> *None*: require *else*: self.balance >= sum self.balance += sum self.deposits.append(sum) invariant: self.balance >= 0 For more examples and details, please see the before-mentioned two web pages on Eiffel. Current Implementations A series of open-sourced libraries have been developed to bring design-by-contract to Python. *PyContracts* (https://pypi.org/project/PyContracts/) introduced the preconditions and postconditions as special annotations: @contract def my_function(a : 'int,>0', b : 'list[N],N>0') -> 'list[N]': # Requires b to be a nonempty list, and the return # value to have the same length. ... new_contract('valid_name', lambda s: isinstance(s, str) and len(s)>0) @contract(names='dict(int: (valid_name, int))') def process_accounting(records): ... I personally find these annotations hard to read. The contracts seem mostly focused on type checks and on single arguments. Moreover, without support in IDEs and static analysis tools, annotations are susceptible to code rot if not verified by a linter (as far as I could find out, there are not linters that check pycontracts -- please correct me if I'm wrong). I also don't see how you could elegantly implement a check based on multiple arguments (*e.g., *sum >= balance in the CheckingAccount example). *Dpcontracts* (https://pypi.org/project/dpcontracts/) is a library based on decorators. It encapsulates the arguments of a function and its result as the arguments of the condition function: >>> @require("`i` must be a positive integer", ... lambda args: isinstance(args.i, int) and args.i > 0) ... @require("`j` must be a positive integer", ... lambda args: isinstance(args.j, int) and args.j > 0) ... @ensure("the result must be greater than either `i` or `j`", ... lambda args, result: result > args.i and result > args.j) ... def add2(i, j): ... if i == 7: ... i = -7 # intentionally broken for purposes of example ... return i + j It also supports invariants: >>> @invariant("inner list can never be empty", lambda self: len(self.lst) > 0) ... @invariant("inner list must consist only of integers", ... lambda self: all(isinstance(x, int) for x in self.lst)) ... class NonemptyList: ... @require("initial list must be a list", lambda args: isinstance(args.initial, list)) ... @require("initial list cannot be empty", lambda args: len(args.initial) > 0) ... @ensure("the list instance variable is equal to the given argument", ... lambda args, result: args.self.lst == args.initial) ... @ensure("the list instance variable is not an alias to the given argument", ... lambda args, result: args.self.lst is not args.initial) ... def __init__(self, initial): ... self.lst = initial[:] ... ... def get(self, i): ... return self.lst[i] ... ... def pop(self): ... self.lst.pop() ... ... def as_string(self): ... # Build up a string representation using the `get` method, ... # to illustrate methods calling methods with invariants. ... return ",".join(str(self.get(i)) for i in range(0, len(self.lst))) Contracts (https://pypi.org/project/contracts/), pyadbc ( https://pypi.org/project/pyadbc/) and pcd (https://pypi.org/project/pcd/) are similar in terms of features to dpcontracts, but seem not to be maintained any more. We found that all the presented methods were a bit impractical to use in everyday programming. Pycontracts forces the programmer to learn a new syntax which is not statically checked. While we liked the features provided by dpcontracts, we found that exception messages thrown at contract breach were uninformative. The programmer is forced to repeat every condition in text if s/he is to make any use of the error once it happens. This can lead to mismatch between the messages and code (similar how the comments tend to rot) and can make debugging and tracing bugs very hard. Moreover, it is tedious and repetitive to document the conditions twice which makes programmers sometimes reluctant to adopt it and apply it widely. We therefore developed *icontract* (https://pypi.org/project/icontract/). We decided to leave out class invariants for practical reasons (we rarely use classes in our applications and we needed conditions in production for which the invariants are often impractical), but invariants can be easily added if there is a demand. icontract is based on decorators and uses lambda functions for the conditions that match the argument names of the function. The argument *result* is reserved for the result of the function in postconditions. Here is the example usage: >>> @icontract.pre(lambda x: x > 3)... def some_func(x: int, y: int = 5)->None:... pass... >>> some_func(x=5) # Pre-condition violation>>> some_func(x=1)Traceback (most recent call last): ...icontract.ViolationError: Precondition violated: x > 3: x was 1 >>> @icontract.post(lambda result, x: result > x)... def some_func(x: int, y: int = 5) -> int:... return x - y...>>> some_func(x=10)Traceback (most recent call last): ...icontract.ViolationError: Post-condition violated: result > x:result was 5x was 10 Mind that there is no mandatory description in the contract yet the message is informative. We achieve that by re-executing the condition function and tracing the values by examining its abstract syntax tree. The re-computation can also deal with more complex expressions and outer scope: >>> class B:... def __init__(self) -> None:... self.x = 7...... def y(self) -> int:... return 2...... def __repr__(self) -> str:... return "instance of B"...>>> class A:... def __init__(self)->None:... self.b = B()...... def __repr__(self) -> str:... return "instance of A"...>>> SOME_GLOBAL_VAR = 13>>> @icontract.pre(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR)... def some_func(a: A) -> None:... pass...>>> an_a = A()>>> some_func(an_a)Traceback (most recent call last): ...icontract.ViolationError: Precondition violated: (a.b.x + a.b.y()) > SOME_GLOBAL_VAR:SOME_GLOBAL_VAR was 13a was instance of Aa.b was instance of Ba.b.x was 7a.b.y() was 2 We found informative messages to be a tremendous booster when debugging since you often immediately see what caused the contract breach and not only that it was broken. This often points you directly to the cause of the bug. Moreover, conditions are much more readable when not cluttered by redundant descriptions. This is important when you use them as part of the documentation that you inspect with an IDE (*e.g., *in PyCharm). By our subjective impression, other solutions resulted in hard-to-read documentation in PyCharm. While descriptions can also be added to the icontract conditions, we rarely find that necessary since most conditions are self-explanatory. Insufficiencies of the Current Libraries All the libraries described here were not trivial to implement and come with a substantial computational overhead. In one of our benchmarks, we found that having a precondition made a function run at least 6x slower (we traced the slow-down to an additional function invocation which is costly in Python). I don't think that it is possible to implement *old *keyword for most practical applications since the execution would be even slower. I found no library so far that supports inheritance, strengthening (ensure then) and weakening (*require else)* of the contracts out-of-the-box. My intuition tells me that it is possible to implement such a feature in a library, but the implementation will definitely be very complex. Apart from computational efficiency and complexity of implementation, I also see the variety of libraries as a problem for the adoption of design-by-contract. With multiple solutions and each team having their own preferences there is a dilemma which solution to choose. Without a wide adoption of a single solution we can not expect an emergence of tools such as automatic test generators built on top of the contracts which is where the actual tremendous benefits really await. A standard solution would allow us to have uniform, widely-adopted and efficient design-by-contracts in Python which no library by itself can achieve. Sketch of a Solution Instead of introducing new keywords, Python could introduce a built-in module based on decorators. The interpreters could be extended such as that they in-line the code directly into the function whenever the decorators of this built-in module is encountered. This would substantially reduce the computational overhead while it would allow us to avoid changes to language syntax. However, before we even start looking at a solution, I see it necessary that we first discuss more to which degree contracts should be introduced to Python and what the use cases would look like. Cheers, Marko -------------- next part -------------- An HTML attachment was scrubbed... URL: From jamtlu at gmail.com Sat Aug 25 13:56:20 2018 From: jamtlu at gmail.com (James Lu) Date: Sat, 25 Aug 2018 13:56:20 -0400 Subject: [Python-ideas] Unpacking iterables for augmented assignment Message-ID: I propose we apply PEP 3132 to PEP 203. That is, for every statement where " = " is valid I propose "lhs += rhs" should also be valid. Simple example: a = 0 b = 0 a, b += 1, 2 # a is now 1 # b is now 2 -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Sat Aug 25 17:14:27 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sat, 25 Aug 2018 22:14:27 +0100 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: Message-ID: Hi James Thank you for the simple example. It makes discussing your proposal much easier. I hope you don't mind, I'll modify it a little to make the semantics clearer, at least to me. Here it is. init = (10, 20) incr = (1, 2) (a, b) = init # Now, (a, b) == (10, 20) a, b += incr # Now (a, b) == (11, 22) However, I'm not sure your suggestion sits well with the following >>> (10, 20) + (1, 2) (10, 20, 1, 2) >>> x = [10, 20] >>> x += [1, 2] >>> x [10, 20, 1, 2] By the way, I was surprised to find that this is valid >>> [a, b] = 1, 2 with best regards Jonathan From turnbull.stephen.fw at u.tsukuba.ac.jp Sun Aug 26 07:52:38 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Sun, 26 Aug 2018 20:52:38 +0900 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: Message-ID: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> James Lu writes: > I propose we apply PEP 3132 to PEP 203. That is, for every statement where > " = " is valid I propose "lhs += rhs" should also be > valid. > > Simple example: > a = 0 > b = 0 > a, b += 1, 2 > # a is now 1 > # b is now 2 This isn't consistent with the normal behavior of Python sequences: $ python3.6 >>> (1,2) + (3,4) (1, 2, 3, 4) That is, "+" means something different for sequences. Furthermore, the thing on the LHS is tuple syntax. There's only one reasonable meaning to give to an ordinary assignment from a sequence on the RHS to a "tuple of variables". But in your expression, the thing on the LHS wants to be an object, which can only be a concrete tuple: >>> a = 0 >>> b = 0 >>> a, b (0, 0) which is itself immutable, as are its integer components in your example (which is not a toy, as complex expressions on the RHS would mean you could only fit two, maybe three on a line, which doesn't save much vertical space). You can argue that the same would hold for ordinary assignment, but doesn't, and that's true. However, ordinary assignment is a name-binding operation, while augmented assignment is a mutation of the underlying object. This is problematic for lists: >>> [a, b] = 1, 2 >>> a, b (1, 2) >>> c = [1, 2] >>> c += [3, 4] >>> c [1, 2, 3, 4] I don't think the list syntax has any use different from the tuple syntax. The example of list syntax makes me uncomfortable, though. I wonder if there are traps with other mutable objects. Finally, when I look at > a, b += 1, 2 as a once and future C programmer, I expect a value of (0, 1, 2) to be printed, with a == 0, and b == 1 at this point. (This is really minor; we like to avoid confusion with carryovers from other languages, but it's not enought to kill something useful.) That said, none of the above is sufficient reason to reject a useful syntax addition (augmented assignment to a tuple is currently an error). But it seems to me that compared to assignment by sequence unrolling, this generalization isn't very expressive. AIUI, one of the motivations for unrolling sequence-to-sequence assignment in this way is to provide the obvious notation for permutations: >>> a, b = 1, 2 >>> b, a = a, b >>> a, b (2, 1) and generalizing >>> a, b, c, d, e = 1, 2, 3, 4, 5 >>> a, b, c, d, e = \ ... e, a, b, c, d # the values "move up", so a bit unintuitive >>> a, b, c (5, 1, 2) You can't do any of the above without the sequence unrolling feature, without adding temporary variables. With augmented assignments, you can save some vertical space. Is there something else I'm missing? Steve From turnbull.stephen.fw at u.tsukuba.ac.jp Sun Aug 26 07:52:54 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Sun, 26 Aug 2018 20:52:54 +0900 Subject: [Python-ideas] Does jargon make learning more difficult? In-Reply-To: <5B7FB042.6010201@canterbury.ac.nz> References: <23419.40469.935968.871948@turnbull.sk.tsukuba.ac.jp> <20180821143121.GD24160@ando.pearwood.info> <23420.55144.2677.692751@turnbull.sk.tsukuba.ac.jp> <23423.21126.208348.743032@turnbull.sk.tsukuba.ac.jp> <5B7FB042.6010201@canterbury.ac.nz> Message-ID: <23426.38038.226910.856663@turnbull.sk.tsukuba.ac.jp> Greg Ewing writes: > For understanding what kinds of things an LL parser can parse, > it helps to have gone through the exercise of implementing a > recursive descent parser. I deliberately decided not to go this route. I'm curious whether Abe found both posts useful. (Comparisons are invidious; please don't. ;-) > > I don't think of it in terms of the parser knowing "where" it is > > in the program, but rather in terms of whether it can do more > > work on the AST with the token (or EOF) in hand. > > Not so much where it is in the program, but where it is in > the *grammar*. [Concise useful description of what this means and why it's useful elided.] > Unfortunately, Python's parser doesn't seem to make much > use of this. :-( Indeed, and that's part of why I chose the route I did. But the main point is that in the context of the particular example (the lambda swallowing the if-else expression if the lambda is not parenthesized), the "keep going until you can't" aspect of subpattern matching (used for ambiguity resolution) is the cause of the need for parentheses here. From jamtlu at gmail.com Sun Aug 26 12:29:48 2018 From: jamtlu at gmail.com (James Lu) Date: Sun, 26 Aug 2018 12:29:48 -0400 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> Message-ID: Steve and Johnathan, it seems like we're on the same page. Currently, is = = = always equivalent to = ; = ; = ? When there are a tuple or list of names on the left hand side (ex. `a, b` or `(a, b)` or `[a, b]`), unpack the right hand side into values and perform the augmented assignment on each name on the left hand side. Borrowing Johnathan's example: a = b = 0 incr = (1, 2) a, b += incr # now (a, b) == (1, 2) concat = (-1, 0) concat += incr # existing behavior: now concat == (1, 2, 3, 4) Like Steve said, you can save vertical space and avoid creating temporary variables: temp_a, temp_b = simulate(new_deck) tally_a += temp_a tally_b += temp_b tally_a, tally_b = simulate(new_deck ) -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Sun Aug 26 13:19:36 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sun, 26 Aug 2018 18:19:36 +0100 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> Message-ID: Hi James Thank you for your message. I have some general, background comments. However, the question remains: Does your proposal sit well with the rest of Python? By the way, I've just found a nice article: http://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/ You wrote > Currently, is = = = always equivalent > to = ; = ; = ? It is very important, in this context, to know what we can assign to. We can assign to some expressions, but not others. Here are some examples >>> fn() = 4 SyntaxError: can't assign to function call >>> fn()[0] = 4 NameError: name 'fn' is not defined >>> 1 = 2 SyntaxError: can't assign to literal >>> None = None SyntaxError: can't assign to keyword When assigned to, the expression "(a, b)" has a special meaning. Strictly speaking, we are not assigning to a tuple. Hence >>> (fn()[1], a.b) = (0, 1) # Valid syntax. NameError: name 'fn' is not defined Finally, here's something that surprised me a little bit >>> x = [1, 2]; id(x) 140161160364616 >>> x += [3, 4]; id(x) 140161160364616 >>> x = (1, 2); id(x) 140161159928520 >>> x += (3, 4); id(x) 140161225906440 Notice that '+=' creates uses the same object when the object is a list, but creates a new object. This raises the question: Why and how does Python behave in this way? Finally, thank you for your stimulating idea. I think to take it forward you have to deal with two questions: 1. Does the proposal sit well with the rest of Python? 2. Does it IN PRACTICE bring sufficient benefits to users? Please note that Python deservedly has a reputation for being a readable language. Some will argue that allowing >>> (a, b) += (c, d) may bring benefits to the author of the line of code, but to the cost of the line of code. Somewhere, as I recall, I read that writing a = b = is preferable for reasons of clarity to a, b = , when the two assignments are unrelated. -- Jonathan From turnbull.stephen.fw at u.tsukuba.ac.jp Sun Aug 26 13:34:24 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Mon, 27 Aug 2018 02:34:24 +0900 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> Message-ID: <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> James Lu writes: > Currently, is = = = always equivalent > to = ; = ; = ? No. It's equivalent to = = = and the order matters because the s may have side effects. Not sure where the rest of your message was going; it mostly just seemed to repeat examples from earlier posts? Steve From steve at pearwood.info Sun Aug 26 13:45:46 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 27 Aug 2018 03:45:46 +1000 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> Message-ID: <20180826174546.GA24160@ando.pearwood.info> On Sun, Aug 26, 2018 at 06:19:36PM +0100, Jonathan Fine wrote: > Finally, here's something that surprised me a little bit > > >>> x = [1, 2]; id(x) > 140161160364616 > >>> x += [3, 4]; id(x) > 140161160364616 > >>> x = (1, 2); id(x) > 140161159928520 > >>> x += (3, 4); id(x) > 140161225906440 > > Notice that '+=' creates uses the same object when the object is a > list, but creates a new object. This raises the question: Why and how > does Python behave in this way? Lists are mutable and can be modified in place. Tuples are immutable and cannot be. By the way: it's not reliable to compare ID numbers for objects which don't necessarily exist similtaneously. The Python interpreter is permitted to re-use ID numbers. For example: py> s = [1, 4] py> id(s) 3080212620 py> del s py> s = [-1, 3] py> id(s) 3080212620 The only reliable use of ID numbers is to compare the ID of objects which are known to still exist. -- Steve From tim.peters at gmail.com Sun Aug 26 13:52:05 2018 From: tim.peters at gmail.com (Tim Peters) Date: Sun, 26 Aug 2018 12:52:05 -0500 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> Message-ID: [James Lu] > > Currently, is = = = always equivalent > > to = ; = ; = ? [Stephen J. Turnbull[ > No. It's equivalent to > > = > = > = > > and the order matters because the s may have side effects. This is tricky stuff. In fact the rightmost expression is evaluated once, and then the bindings are done left-to-right using the result of evaluating the rightmost expression. Like so: >>> def return2(): ... print("called return2") ... return 2 >>> xs = [10, 20, 30, 40] >>> i = xs[i] = return2() called return2 >>> xs [10, 20, 2, 40] >>> i 2 So James's account is closer to what's done, but is missing weasel words to make clear that is evaluated only once. Sane code doesn't rely on "left to right", but may well rely on "evaluated only once". -------------- next part -------------- An HTML attachment was scrubbed... URL: From kirillbalunov at gmail.com Sun Aug 26 14:48:59 2018 From: kirillbalunov at gmail.com (Kirill Balunov) Date: Sun, 26 Aug 2018 21:48:59 +0300 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> Message-ID: ??, 26 ???. 2018 ?. ? 14:53, Stephen J. Turnbull < turnbull.stephen.fw at u.tsukuba.ac.jp>: > [...] > > This isn't consistent with the normal behavior of Python sequences: > > $ python3.6 > >>> (1,2) + (3,4) > (1, 2, 3, 4) > > That is, "+" means something different for sequences. Furthermore, > the thing on the LHS is tuple syntax. There's only one reasonable > meaning to give to an ordinary assignment from a sequence on the RHS > to a "tuple of variables". > What do you mean by "consistent with the normal behavior of Python sequences"? Personally, I do not see any consistency. Currently, in Python 3.7: >>> a = [ 1, 2, 3] >>> b = ( 1, 2, 3) >>> a + b ... TypeError: can only concatenate list (not "tuple") to list But: >>> a += b [1, 2, 3, 1, 2, 3] As for me, Python has several historical artifacts (warts) which can not be fixed by now. I'm sure that someone, on the contrary, finds them as advantages (and I'm not interested that someone started to convince me in the opposite). Among them are: reversed order of arguments in `enumerate`, the absence of literals for `set` and `frozenset` types, all `bytes` story in Python 3, `+` operator overload for sequences and others. But for this particular case, `+` operator overload for concatenation, I think Python can do better and have the opportunity. Especially, taking into account the switch to generators for builtins in Python 3 and that in 30-40% times, rough estimation, `+` operator for sequences is used for throw away concatenation with unnecessary usage of resources in some cases. I like the way this problem was addressed and solved in Coconut language with `::` operator. Coconut uses the ` ::` operator for iterator chaining. Since Coconut is just a transpiler, it is the best they can do. I don't think that just wrapping sequences and iterators with chain is the right solution for Python and also it is not enough to introduce new operator into the language. I would like to see it in a generalized form, for example with the possibility to access items with slices and indices,.. .I understand that this is not so easy, but at least I think that this is the right direction for several reasons: it give a possibility for future pattern matching syntax/functionality in Python, it can be done lazily and, in my opinion, `+` operator overload for builtin sequence types is a historical design mistake. with kind regards, -gdg -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Sun Aug 26 14:50:49 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Sun, 26 Aug 2018 19:50:49 +0100 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: <20180826174546.GA24160@ando.pearwood.info> References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <20180826174546.GA24160@ando.pearwood.info> Message-ID: Hi James and Steve Myself and Steve wrote: >> Notice that '+=' creates uses the same object when the object is a >> list, but creates a new object. This raises the question: Why and how >> does Python behave in this way? > Lists are mutable and can be modified in place. Tuples are immutable and > cannot be. This correctly answers why this happens. Steve: I wanted James to think about this question. He learns more that way. (I already knew the answer.) James: Combining tuple assignment with increment assignment in a single statement will increase the cognitive burden on both writer and reader of the line of code. In other words, in most cases > a += > b += is easy to write and read than > a, b += , Now look at: > a, b += my_object.some_method(args) It is simpler than: > value = my_object.some_method(args) > a += value[0] > b += value[1] You can say that here the extra lines increase the cognitive burden. And I think I'd agree with you. But I think there's a code-smell here. Better, I think, is to introduce a type that supports augmented assignment. For example > vec = Vector(a, b) > inc = Vector(c, d) > vec += inc I hope this helps -- Jonathan From jamtlu at gmail.com Sun Aug 26 21:23:41 2018 From: jamtlu at gmail.com (James Lu) Date: Sun, 26 Aug 2018 21:23:41 -0400 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> Message-ID: Hi Johnathan I echo your points. Indeed, the PEP referenced to refers to a "tuple expression" in the grammatical and not the programmatic sense. Finally, here's something that surprised me a little bit >>> x = [1, 2]; id(x) 140161160364616 >>> x += [3, 4]; id(x) 140161160364616 >>> x = (1, 2); id(x) 140161159928520 >>> x += (3, 4); id(x) 140161225906440 Notice that '+=' creates uses the same object when the object is a list, but creates a new object. This raises the question: Why and how does Python behave in this way? It's because lists are mutable are tuples are immutable. There's a dunder iadd method and a dunder add method. iadd magic methods, operating on the left hand side, return None and modify the object in-place. add magic methods return the result and don't modify the object it's called on. iadd is mutable add, whereas add is "return a copy with the result added" >>> tuple.__iadd__ Traceback (most recent call last): File "", line 1, in AttributeError: type object 'tuple' has no attribute '__iadd__' type object 'tuple' has no attribute '__iadd__' >>> tuple.__add__ >>> list.__iadd__ >>> list.__add__ tuple1 = tuple1.__add__(tuple2) list1.__iadd__(list2) > Does it IN PRACTICE bring sufficient benefits to users? I found myself needing this when I was writing a monte-carlo simulation in python that required incrementing a tallying counter from a subroutine. Not sure where the rest of your message was going; it mostly just > seemed to repeat examples from earlier posts? > Yes, I just wanted to summarize the existing discussion. On Sun, Aug 26, 2018 at 1:52 PM Tim Peters wrote: > [James Lu] > > > Currently, is = = = always equivalent > > > to = ; = ; = ? > > [Stephen J. Turnbull[ > > No. It's equivalent to > > > > = > > = > > = > > > > and the order matters because the s may have side effects. > > This is tricky stuff. In fact the rightmost expression is evaluated once, > and then the bindings are done left-to-right using the result of evaluating > the rightmost expression. Like so: > > >>> def return2(): > ... print("called return2") > ... return 2 > >>> xs = [10, 20, 30, 40] > >>> i = xs[i] = return2() > called return2 > >>> xs > [10, 20, 2, 40] > >>> i > 2 > > So James's account is closer to what's done, but is missing weasel words > to make clear that is evaluated only once. > > Sane code doesn't rely on "left to right", but may well rely on "evaluated > only once". > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jamtlu at gmail.com Sun Aug 26 21:29:28 2018 From: jamtlu at gmail.com (James Lu) Date: Sun, 26 Aug 2018 21:29:28 -0400 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: Message-ID: [Kirill Balunov] It may be worth taking a look at + and +=. However, the semantic difference is due to the dunder add and dunder iadd methods- necessary for supporting both mutable and immutable sequences. See my earlier mail for discussion on this topic. By the way, > the absence of literals for `set` and `frozenset` types, > The literal for the set is {1, 2, 3, 4}. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Sun Aug 26 21:40:31 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 27 Aug 2018 11:40:31 +1000 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <20180826174546.GA24160@ando.pearwood.info> Message-ID: <20180827014031.GC24160@ando.pearwood.info> On Sun, Aug 26, 2018 at 07:50:49PM +0100, Jonathan Fine wrote: > Hi James and Steve > > Myself and Steve wrote: > > >> Notice that '+=' creates uses the same object when the object is a > >> list, but creates a new object. This raises the question: Why and how > >> does Python behave in this way? > > > Lists are mutable and can be modified in place. Tuples are immutable and > > cannot be. > > This correctly answers why this happens. > > Steve: I wanted James to think about this question. He learns more > that way. (I already knew the answer.) How do you know James doesn't already know the answer too? If you meant this as a lesson for James, you should have said so. You shouldn't have claimed to have been surprised by it: "Finally, here's something that surprised me a little bit" > James: Combining tuple assignment with increment assignment in a > single statement will increase the cognitive burden on both writer and > reader of the line of code. Each additional line we read has to be read as a separate operation. Moving things into a single operation can reduce the cognitive load, at least sometimes. Reducing the number of lines x += 1 y += 2 z += 3 down to one: x, y, z += 1, 2, 3 # Hypothetical syntax could also *decrease* the cognitive burden on the writer or reader if x, y, z form a logically connected group. Each additional line of code has its own cognitive load just by being an extra line to process. For a small number of simple targets, our brains can chunk the assignments into one conceptual operation: "assign x, y, z" instead of three: "assign x; then assign y; also assign z" Hence a reduced cognitive load on both reader and writer. I see no reason why this chunking can't also apply to augmented assignments: "increment x, y, z" but I do worry if it would only chunk effectively if the increment is the same: x, y, z += 1 # increment each of x, y, z by 1 but not if we have to specify each increment separately: x, y, z += 1, 1, 1 I don't have any proof of this concern. [...] > But I think there's a code-smell here. Better, I think, is to > introduce a type that supports augmented assignment. For example > > > vec = Vector(a, b) > > inc = Vector(c, d) > > vec += inc I would like to see Python increase its support for vectorized operations. Some years ago I tried adding vectorized support to the statistics module as an experiment, but I found that the performance hit was horrible, so I abandoned the experiment. YMMV. Julia includes syntax to automatically vectorize any operator or function: https://docs.julialang.org/en/v0.6.2/manual/functions/#man-vectorized-1 but that's moving away from the topic on hand. (Any responses to my vectorization comment, please start a new thread or at least change the subject line.) Back to the original topic... My gut feeling is that this suggested syntax would work well if there was a single value on the right hand side, so that: spam, eggs, cheese += foo is approximately equivalent to: # evaluate RHS only once _tmp = foo spam += _tmp eggs += _tmp cheese += _tmp but not so well if we add sequence unpacking on the RHS: spam, eggs, cheese += foo, bar, baz Without adding new syntax, I think we can only pick one set of semantics, not both: either a single RHS value, or multiple values. My intuition is that the first version (a single value on the RHS) is not only more useful, but also more readable, since it allows the reader to chunk the operation to "increment these three targets" while the second doesn't. That also leaves the door open in the future to adding a vectorized version of augmented assignment, if and when we add syntax for vectorizing operations a la Julia. So... a tentative +1 to allowing: spam, eggs += foo and an even more tentative -0 to: spam, eggs += foo, bar -- Steve From moiein2000 at gmail.com Mon Aug 27 01:29:14 2018 From: moiein2000 at gmail.com (Matthew Einhorn) Date: Mon, 27 Aug 2018 01:29:14 -0400 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> Message-ID: On Sun, Aug 26, 2018, 9:24 PM James Lu wrote: > Hi Johnathan > > I echo your points. Indeed, the PEP referenced to refers to a "tuple > expression" in the grammatical and not the programmatic sense. > > Finally, here's something that surprised me a little bit > > >>> x = [1, 2]; id(x) > 140161160364616 > >>> x += [3, 4]; id(x) > 140161160364616 > > >>> x = (1, 2); id(x) > 140161159928520 > >>> x += (3, 4); id(x) > 140161225906440 > > Notice that '+=' creates uses the same object when the object is > a > list, but creates a new object. This raises the question: Why and > how > does Python behave in this way? > > It's because lists are mutable are tuples are immutable. > There's a dunder iadd method and a dunder add method. > iadd magic methods, operating on the left hand side, return None and > modify the object in-place. add magic methods return the result and > don't modify the object it's called on. > iadd is mutable add, whereas add is "return a copy with the result > added" > > >>> tuple.__iadd__ > Traceback (most recent call last): > File "", line 1, in > AttributeError: type object 'tuple' has no attribute '__iadd__' > type object 'tuple' has no attribute '__iadd__' > >>> tuple.__add__ > > >>> list.__iadd__ > > >>> list.__add__ > > > > tuple1 = tuple1.__add__(tuple2) > > list1.__iadd__(list2) > > > Does it IN PRACTICE bring sufficient benefits to users? > > I found myself needing this when I was writing a monte-carlo > simulation in python that required incrementing a tallying counter > from a subroutine. > Wouldn't a numpy array be very suited for this kind of task? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Mon Aug 27 02:25:00 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Mon, 27 Aug 2018 07:25:00 +0100 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> Message-ID: James has suggested that Python be enhanced so that >>> a, b += c, d is a short-hand for >>> a += c >>> b += d Myself, James and Matthew wrote >> > Does it IN PRACTICE bring sufficient benefits to users? >> I found myself needing this when I was writing a monte-carlo >> simulation in python that required incrementing a tallying counter >> from a subroutine. > Wouldn't a numpy array be very suited for this kind of task? Perhaps, James, you might like to refactor your code so that >>> tally += simulation(args) does what you want. As Matthew points out, you could use numpy.array. Or code your own class, by providing __add__ and __iadd__ methods. >>> import numpy >>> a = numpy.array([1, 2]) >>> b = numpy.array([3, 4]) >>> a + b array([4, 6]) >>> a += b >>> a array([4, 6]) -- Jonathan From j.van.dorp at deonet.nl Mon Aug 27 03:04:21 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Mon, 27 Aug 2018 09:04:21 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> Message-ID: Total noob speaking here, but.... Those contracts are mostly important during development right ? Slowdown isn't that much of an issue during development. So you could make a debug mode that enforces the contracts, and a production mode that code users can use during production to stop the slowdown - in this case, your decorators can return their functions/classes unaltered. If they do end up with problems, you can always ask them to run the same inputs with debug mode on to see where it goes wrong. For the rest, i'm totally new to design by contract. I do get the draw of it, but im not sure if I'd ever really use it. I tend to solve my problems with a royal sprinkling of logger.debug(f"{val_i_need_to_check}"). -------------- next part -------------- An HTML attachment was scrubbed... URL: From levkivskyi at gmail.com Mon Aug 27 04:24:20 2018 From: levkivskyi at gmail.com (Ivan Levkivskyi) Date: Mon, 27 Aug 2018 09:24:20 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> Message-ID: TBH, I think one of the main points of design by contract is that contracts are verified statically. For runtime contract checking I would rather recommend hypothesis library (or similar). -- Ivan On Mon, 27 Aug 2018 at 08:05, Jacco van Dorp wrote: > Total noob speaking here, but.... > > Those contracts are mostly important during development right ? Slowdown > isn't that much of an issue during development. So you could make a debug > mode that enforces the contracts, and a production mode that code users can > use during production to stop the slowdown - in this case, your decorators > can return their functions/classes unaltered. If they do end up with > problems, you can always ask them to run the same inputs with debug mode on > to see where it goes wrong. > > For the rest, i'm totally new to design by contract. I do get the draw of > it, but im not sure if I'd ever really use it. I tend to solve my problems > with a royal sprinkling of logger.debug(f"{val_i_need_to_check}"). > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Mon Aug 27 06:23:08 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 27 Aug 2018 20:23:08 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> Message-ID: <20180827102308.GD24160@ando.pearwood.info> On Mon, Aug 27, 2018 at 09:04:21AM +0200, Jacco van Dorp wrote: > Total noob speaking here, but.... > > Those contracts are mostly important during development right ? That assumes that production code is free of bugs. Usual practice in the Eiffel world is, I believe, to disable post- condition checking and other assertions in production code, but leave pre-condition checks in place. Note: for those unfamiliar with Design By Contract, pre- and post- condition checks and assertions are NOT used to detect predictable error states, such as bad user input or IO errors. They are only used for testing program correctness. A failed contract or assertion can only mean a bug in the program. In a totally bug-free program contracts can safely be disabled. > Slowdown isn't that much of an issue during development. For many cases, it isn't an issue during production either. > So you could make a debug > mode that enforces the contracts, and a production mode that code > users can use during production to stop the slowdown In Eiffel, contracts can be disabled or enable globally, or on a class-by-class basis. > - in this case, your decorators > can return their functions/classes unaltered. If they do end up with > problems, you can always ask them to run the same inputs with debug mode on > to see where it goes wrong. > > For the rest, i'm totally new to design by contract. I do get the draw of > it, but im not sure if I'd ever really use it. I tend to solve my problems > with a royal sprinkling of logger.debug(f"{val_i_need_to_check}"). The differences between design by contract and sprinkling messages in the log include: - the compiler (or interpreter) never forgets to read the logs looking for failures; - when a failure occurs, the program halts, so you know its broken, rather than silently continuing and perhaps doing something unexpected; - you don't need to read the logs and try to remember why it is that you're printing the value of ``foo`` and whether its a good thing or a bad thing that it has the value you're seeing. Here's an introduction to design by contract: https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions -- Steve From steve at pearwood.info Mon Aug 27 06:35:06 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 27 Aug 2018 20:35:06 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> Message-ID: <20180827103506.GE24160@ando.pearwood.info> On Mon, Aug 27, 2018 at 09:24:20AM +0100, Ivan Levkivskyi wrote: > TBH, I think one of the main points of design by contract is that contracts > are verified statically. No, that's not correct. Contracts may be verified statically if the compiler is able to do so, but they are considered runtime checks. Static checks are an optimization. For example, the Eiffel docs describe one possible contract as "the graph contains no cycle" and can contain function calls. https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions -- Steven From levkivskyi at gmail.com Mon Aug 27 07:12:22 2018 From: levkivskyi at gmail.com (Ivan Levkivskyi) Date: Mon, 27 Aug 2018 12:12:22 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180827103506.GE24160@ando.pearwood.info> References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> Message-ID: On Mon, 27 Aug 2018 at 11:39, Steven D'Aprano wrote: > On Mon, Aug 27, 2018 at 09:24:20AM +0100, Ivan Levkivskyi wrote: > > TBH, I think one of the main points of design by contract is that > contracts > > are verified statically. > > No, that's not correct. Contracts may be verified statically if the > compiler is able to do so, but they are considered runtime checks. > Considered by whom? By people who prefer `assert isinstance(x, int)` over `x: int`? :-) Contract in 99% of cases is just another word for type (maybe a very complex type like `DAG[T] <: Graph[T]`). Everything else, like `x >= y` is better expressed as an explicit assert with an assert message. But again this is rather IMO, than any kind of definition. There is only one use case I see now where a dedicated syntax would give a large readability gain: something like `self.x >= self.y`. But on the other hand I think such situations are too rare to justify any _new_ syntax. -- Ivan -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Mon Aug 27 07:25:44 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Mon, 27 Aug 2018 12:25:44 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> Message-ID: Ivan and Steve wrote >> TBH, I think one of the main points of design by contract is that contracts >> are verified statically. > No, that's not correct. > https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions The page from Steve supplied (URL above) states > During development and testing, assertion monitoring should > be turned on at the highest possible level. Combined with > static typing and the immediate feedback of compilation techniques > [...] this permits the development process [...] > where errors are exterminated at birth. Based on the Eiffel docs, I find Ivan's opinion reasonable. He said it was "one of the main points". The goal is to detect errors immediately. Run-time assertion monitoring and static typing are two means towards that end. Our shared problem and goal is to have similar immediate detection of errors in Python (when the development process requires that degree of rigour). -- Jonathan From steve at pearwood.info Mon Aug 27 08:50:12 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 27 Aug 2018 22:50:12 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> Message-ID: <20180827125012.GF24160@ando.pearwood.info> On Mon, Aug 27, 2018 at 12:12:22PM +0100, Ivan Levkivskyi wrote: > On Mon, 27 Aug 2018 at 11:39, Steven D'Aprano wrote: > > > On Mon, Aug 27, 2018 at 09:24:20AM +0100, Ivan Levkivskyi wrote: > > > TBH, I think one of the main points of design by contract is that > > contracts > > > are verified statically. > > > > No, that's not correct. Contracts may be verified statically if the > > compiler is able to do so, but they are considered runtime checks. > > > > Considered by whom? By people who prefer `assert isinstance(x, int)` over > `x: int`? :-) No, considered by Bertrand Meyer, the inventor of Design By Contract and the programming language Eiffel. Contracts are not limited to the things which static type-checkers are capable of testing, but can and do involve checks which are impossible or impractical to test at compile-time, like "today is Tuesday" or "the account balance is greater than the amount you are trying to withdraw". > Contract in 99% of cases is just another word for type (maybe a very > complex type like `DAG[T] <: Graph[T]`). > Everything else, like `x >= y` is better expressed as an explicit assert > with an assert message. Contracts ARE assertions. They are assertions about the input a method expects, not merely the type but the value, what result it intends to return, and the invariants of the class after the method is called. Like assertions, they are called at runtime, and can be disabled. Using contracts to enforce type-correctness wouild be silly in Eiffel, because Eiffel already has a powerful static type system. Sybtax-wise, if you're interested in what is possible in a Python-like language, you could do worse than check out Cobra: http://cobra-language.com/trac/cobra/wiki/Contracts -- Steve From rosuav at gmail.com Mon Aug 27 09:00:22 2018 From: rosuav at gmail.com (Chris Angelico) Date: Mon, 27 Aug 2018 23:00:22 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180827125012.GF24160@ando.pearwood.info> References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> Message-ID: On Mon, Aug 27, 2018 at 10:50 PM, Steven D'Aprano wrote: > On Mon, Aug 27, 2018 at 12:12:22PM +0100, Ivan Levkivskyi wrote: >> Contract in 99% of cases is just another word for type (maybe a very >> complex type like `DAG[T] <: Graph[T]`). >> Everything else, like `x >= y` is better expressed as an explicit assert >> with an assert message. > > Contracts ARE assertions. They are assertions about the input a method > expects, not merely the type but the value, what result it intends to > return, and the invariants of the class after the method is called. Like > assertions, they are called at runtime, and can be disabled. Sometimes "type" doesn't mean the same thing to the language and to the human. Suppose you're trying to create a Python script that replicates a C program; you might want to declare that a variable is not of type "integer" but type "32-bit unsigned integer", with wrap-around. Or, wording it another way: "integer modulo 2**32". Is that an assertion of type, or of type and value? As a precondition to a function, requiring that a parameter be an integer no less than zero and no greater than 4294967295 is, in a sense, checking its type and its value; but it's kinda just asserting its type. AIUI, that's what Ivan meant by "complex type" - something that determines the domain of valid values as well as the concrete type. ChrisA From gcolombeau at hiphen-plant.com Mon Aug 27 09:49:20 2018 From: gcolombeau at hiphen-plant.com (Gallian Colombeau) Date: Mon, 27 Aug 2018 15:49:20 +0200 Subject: [Python-ideas] PEP 420: implicit namespace sub-package Message-ID: <5B840160.6080703@hiphen-plant.com> Hello, the PEP 420 (Implicit Namespace Packages) is quite descriptive about the problem and the solution implemented back in Python 3.3 but I feel there may be a part missing (but maybe this is categorized as an implementation detail). As I understand, for a package to allow being extended in this way, it must be a namespace package and not contain a marker file. As a matter of fact, no sub-package until the top level package can have a marker file: Lib/test/namespace_pkgs project1 parent child one.py project2 parent child two.py However, what is not discussed is "implicit namespace sub-package". In Python 3.6 (I guess since the first implementation), if you have this layout: Lib/test/namespace_pkgs project1 parent # Regular package __init__.py child # Namespace package one.py you get "parent" as a regular package and "parent.child" as a namespace package and it works (although now, every package data directory became namespace packages and are importable, which may or may not be desirable). The point is, does that add any value? I wasn't able to find any discussion about this and, as far as I can see, there is actually no use case for this as there is no possible way to contribute to the "parent.child" namespace. Is that an intended behavior of PEP 420? Again, I may have missed something or misinterpreted PEP 420 but this contributes to the "Implicit package directories introduce ambiguity into file system layouts." point by Nick Coghlan that was supposed to be addressed in PEP 395. Wouldn't it be more appropriate to enforce a sub-package to be a regular package if the parent package is a regular package? Gallian -- *Gallian Colombeau * *Software engineer * hiphen-plant-logo *Centre INRA PACA - UMR EMMAH* /228, route de l'a?rodrome - CS 40509 84914 Avignon - Cedex 9 - France / www.hiphen-plant.com -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: logo-hiphen-baseline-rvb-taille-2.jpg Type: image/jpeg Size: 66821 bytes Desc: not available URL: From steve at pearwood.info Mon Aug 27 09:53:50 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Mon, 27 Aug 2018 23:53:50 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> Message-ID: <20180827135350.GH24160@ando.pearwood.info> On Mon, Aug 27, 2018 at 11:00:22PM +1000, Chris Angelico wrote: > Sometimes "type" doesn't mean the same thing to the language and to > the human. Suppose you're trying to create a Python script that > replicates a C program; you might want to declare that a variable is > not of type "integer" but type "32-bit unsigned integer", with > wrap-around. Or, wording it another way: "integer modulo 2**32". Is > that an assertion of type, or of type and value? As a precondition to > a function, requiring that a parameter be an integer no less than zero > and no greater than 4294967295 is, in a sense, checking its type and > its value; but it's kinda just asserting its type. It is making an assertion about the value of an instance of type "int". Its not a separate type requiring an explicit coercion or cast. Its just a non-negative int less than 2**32. If the compiler supports the concept of a 32-bit unsigned integer type, then of course we can change our implementation to use that type instead of our regular ints. But we can't expect to pass such a 32-bit unsigned integer to a function which expects a regular int unless they are duck-type compatible, or the compiler performs automatic coercions. (So-called "weak typing"). A better example is the one I gave earlier, of a graph with no cycles. There is a deep fundamental difference between a *statically checked* DAG with no cycles (a graph which can never contain a cycle because the compiler won't let you create one) and a *dynamically checked* DAG that merely has no cycles *now* (it may have had cycles earlier, and it might have cycles later, but right now it has none). These are very different semantics, and Eiffel's contracts support the second kind: runtime value checks. -- Steve From wes.turner at gmail.com Mon Aug 27 11:01:21 2018 From: wes.turner at gmail.com (Wes Turner) Date: Mon, 27 Aug 2018 11:01:21 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180827135350.GH24160@ando.pearwood.info> References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> Message-ID: Runtime checks: data validation & code validation Compile-time checks: code validation What sort of data validation is appropriate for assert statements or contacts that may be skipped due to trading performance for more risk ('optimized out')? Checking the value of a Number? Checking that a large graph has no cycles? Checking that a database table exists and has the appropriate relations and constraints? assert statements are skipped at runtime with -O and -OO whether or not they're in [reorderable] aspects applied with decorators, at the beginning or end of a function, or in methods named something like setUp and tearDown. https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE https://docs.python.org/3/using/cmdline.html#cmdoption-o > -O > Remove assert statements and any code conditional on the value of __debug__ > PYTHONOPTIMIZE > If this is set to a non-empty string it is equivalent to specifying the -O option. If set to an integer, it is equivalent to specifying -O multiple times. On Monday, August 27, 2018, Steven D'Aprano wrote: > On Mon, Aug 27, 2018 at 11:00:22PM +1000, Chris Angelico wrote: > > > Sometimes "type" doesn't mean the same thing to the language and to > > the human. Suppose you're trying to create a Python script that > > replicates a C program; you might want to declare that a variable is > > not of type "integer" but type "32-bit unsigned integer", with > > wrap-around. Or, wording it another way: "integer modulo 2**32". Is > > that an assertion of type, or of type and value? As a precondition to > > a function, requiring that a parameter be an integer no less than zero > > and no greater than 4294967295 is, in a sense, checking its type and > > its value; but it's kinda just asserting its type. > > It is making an assertion about the value of an instance of type "int". > Its not a separate type requiring an explicit coercion or cast. Its just > a non-negative int less than 2**32. > > If the compiler supports the concept of a 32-bit unsigned integer type, > then of course we can change our implementation to use that type instead > of our regular ints. But we can't expect to pass such a 32-bit unsigned > integer to a function which expects a regular int unless they are > duck-type compatible, or the compiler performs automatic coercions. > (So-called "weak typing"). > > A better example is the one I gave earlier, of a graph with no cycles. > There is a deep fundamental difference between a *statically checked* > DAG with no cycles (a graph which can never contain a cycle because the > compiler won't let you create one) and a *dynamically checked* DAG that > merely has no cycles *now* (it may have had cycles earlier, and it might > have cycles later, but right now it has none). > > These are very different semantics, and Eiffel's contracts support the > second kind: runtime value checks. > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brett at python.org Mon Aug 27 12:24:36 2018 From: brett at python.org (Brett Cannon) Date: Mon, 27 Aug 2018 09:24:36 -0700 Subject: [Python-ideas] PEP 420: implicit namespace sub-package In-Reply-To: <5B840160.6080703@hiphen-plant.com> References: <5B840160.6080703@hiphen-plant.com> Message-ID: Basically it's too late to change this as I'm sure there's code out there somehow relying on these semantics. Plus the potential harm from someone accidentally having a namespace like this is negligible at best. But there is possible value if you mutate __path__ to have multiple entries and you want a namespace package for a sub-package. On Mon, 27 Aug 2018 at 06:50 Gallian Colombeau wrote: > Hello, > > the PEP 420 (Implicit Namespace Packages) is quite descriptive about the > problem and the solution implemented back in Python 3.3 but I feel there > may be a part missing (but maybe this is categorized as an implementation > detail). > > As I understand, for a package to allow being extended in this way, it > must be a namespace package and not contain a marker file. As a matter of > fact, no sub-package until the top level package can have a marker file: > > Lib/test/namespace_pkgs > project1 > parent > child > one.py > project2 > parent > child > two.py > > However, what is not discussed is "implicit namespace sub-package". In > Python 3.6 (I guess since the first implementation), if you have this > layout: > Lib/test/namespace_pkgs > project1 > parent # Regular package > __init__.py > child # Namespace package > one.py > > you get "parent" as a regular package and "parent.child" as a namespace > package and it works (although now, every package data directory became > namespace packages and are importable, which may or may not be desirable). > The point is, does that add any value? I wasn't able to find any discussion > about this and, as far as I can see, there is actually no use case for this > as there is no possible way to contribute to the "parent.child" namespace. > Is that an intended behavior of PEP 420? > > Again, I may have missed something or misinterpreted PEP 420 but this > contributes to the "Implicit package directories introduce ambiguity into > file system layouts." point by Nick Coghlan that was supposed to be > addressed in PEP 395. > > Wouldn't it be more appropriate to enforce a sub-package to be a regular > package if the parent package is a regular package? > > Gallian > -- > > * Gallian Colombeau * > * Software engineer * > > [image: hiphen-plant-logo] > *Centre INRA PACA - UMR EMMAH* > > * 228, route de l'a?rodrome - CS 40509 84914 Avignon - Cedex 9 - France * > www.hiphen-plant.com > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: logo-hiphen-baseline-rvb-taille-2.jpg Type: image/jpeg Size: 66821 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: logo-hiphen-baseline-rvb-taille-2.jpg Type: image/jpeg Size: 66821 bytes Desc: not available URL: From brett at python.org Mon Aug 27 12:58:06 2018 From: brett at python.org (Brett Cannon) Date: Mon, 27 Aug 2018 09:58:06 -0700 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <5B809B20.70407@canterbury.ac.nz> Message-ID: On Fri, 24 Aug 2018 at 18:18 Mike Barnett wrote: > It?s fascinating just how many packages are being dragged out for > examination or clobbering other than the one that I asked for > assistance/help on. > > > > I see the code of conduct link in the thread. Perhaps a review would be > helpful. > > > > Unsubscribing from this mess. ?Python Ideas? ? > So I code of conduct review of this thread would suggest that your opening email was inappropriate by being misleading thanks to sounding like you were a neutral third-party to your library (luckily you admit to this later, but it shouldn't have been done to begin with). The tone was okay, but you state a lot of opinions as if they are fact, e.g. "GUI code is far from compact", "you've got to be skilled to use it", etc. Those are all opinions expressed as facts which can be misleading and potentially insulting depending on who you're talking to (i.e. some of the people who have worked very hard to make tkinter even work are on this mailing list). Your initial email was also off-topic. This mailing list is about ideas to changing Python, not announcements. Once again you later mention you wanted to start a discussion about getting PySimpleGUI into the stdlib, but it would have been nicer to mention that from the beginning as people would have pointed you at https://devguide.python.org/stdlibchanges/#adding-a-new-module and that would have answered your question. But as part of getting a module into the stdlib, alternatives will be considered (especially GUI libraries as this topic is not a new one and there are many options available, all with their own approaches). So if you actual intent was to get PySimpleGUI into the stdlib some day then discussing other libraries isn't off-topic at all as you will eventually need to address why your library is better than others. Being upset that people are doing their due diligence by bringing up alternatives as part of your request about talking about eventually adding PySimpleGUI to the stdlib is not a CoC violation at all and honestly your tone in your last email is a much bigger concern and deserves the warning --which I am giving -- more than how anyone else has behaved. -Brett > > > > > > > *@mike* > > > > *From:* Python-ideas hotmail.com at python.org> *On Behalf Of *Stephan Houben > *Sent:* Friday, August 24, 2018 9:07 PM > *To:* Chris Barker > *Cc:* Python-Ideas > > > *Subject:* Re: [Python-ideas] A GUI for beginners and experts alike > > > > > > Op za 25 aug. 2018 02:28 schreef Chris Barker - NOAA Federal via > Python-ideas : > > > > Too bad all the cool kids are doing web dev these days ? hard to get > help with a desktop GUI project :-( > > > > Pywebview seems interesting, uses a platform webview to put up the UI; > > > > https://github.com/r0x0r/pywebview > > > > > But not so newbie-friendly I am afraid... > > > > Stephan > > > > > > Pyjamas seems to be something like that: > > > > https://pypi.org/project/Pyjamas/ > > > Or it was 6 years ago :-( > > -CHB > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jamtlu at gmail.com Mon Aug 27 17:18:37 2018 From: jamtlu at gmail.com (James Lu) Date: Mon, 27 Aug 2018 17:18:37 -0400 Subject: [Python-ideas] Python-ideas Digest, Vol 141, Issue 145 In-Reply-To: References: Message-ID: > As Matthew points out, you could use numpy.array. Or code your own > class, by providing __add__ and __iadd__ methods. > > >>> import numpy > >>> a = numpy.array([1, 2]) > >>> b = numpy.array([3, 4]) > >>> a + b > array([4, 6]) > >>> a += b > >>> a > array([4, 6]) I could, but I don't think that justifies not having this functionality in python standard. From the language experience perspective, numpy is often a pain to install on most systems. If I'm designing card games and I just want to run a quick monte carlo simulation, the experience should be as smooth as possible. This is something I think most students will expect while learning python, especially if they're implementing algorithms. On Mon, Aug 27, 2018 at 4:24 AM wrote: > Send Python-ideas mailing list submissions to > python-ideas at python.org > > To subscribe or unsubscribe via the World Wide Web, visit > https://mail.python.org/mailman/listinfo/python-ideas > or, via email, send a message with subject or body 'help' to > python-ideas-request at python.org > > You can reach the person managing the list at > python-ideas-owner at python.org > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of Python-ideas digest..." > > > Today's Topics: > > 1. Re: Unpacking iterables for augmented assignment (Matthew Einhorn) > 2. Re: Unpacking iterables for augmented assignment (Jonathan Fine) > 3. Re: Pre-conditions and post-conditions (Jacco van Dorp) > 4. Re: Pre-conditions and post-conditions (Ivan Levkivskyi) > > > ---------------------------------------------------------------------- > > Message: 1 > Date: Mon, 27 Aug 2018 01:29:14 -0400 > From: Matthew Einhorn > To: python-ideas at python.org > Subject: Re: [Python-ideas] Unpacking iterables for augmented > assignment > Message-ID: > yMM-FNYw3Bza2hJqsGmdgtrvBUa7XA at mail.gmail.com> > Content-Type: text/plain; charset="utf-8" > > On Sun, Aug 26, 2018, 9:24 PM James Lu wrote: > > > Hi Johnathan > > > > I echo your points. Indeed, the PEP referenced to refers to a "tuple > > expression" in the grammatical and not the programmatic sense. > > > > Finally, here's something that surprised me a little bit > > > > >>> x = [1, 2]; id(x) > > 140161160364616 > > >>> x += [3, 4]; id(x) > > 140161160364616 > > > > >>> x = (1, 2); id(x) > > 140161159928520 > > >>> x += (3, 4); id(x) > > 140161225906440 > > > > Notice that '+=' creates uses the same object when the object is > > a > > list, but creates a new object. This raises the question: Why and > > how > > does Python behave in this way? > > > > It's because lists are mutable are tuples are immutable. > > There's a dunder iadd method and a dunder add method. > > iadd magic methods, operating on the left hand side, return None and > > modify the object in-place. add magic methods return the result and > > don't modify the object it's called on. > > iadd is mutable add, whereas add is "return a copy with the result > > added" > > > > >>> tuple.__iadd__ > > Traceback (most recent call last): > > File "", line 1, in > > AttributeError: type object 'tuple' has no attribute '__iadd__' > > type object 'tuple' has no attribute '__iadd__' > > >>> tuple.__add__ > > > > >>> list.__iadd__ > > > > >>> list.__add__ > > > > > > > > tuple1 = tuple1.__add__(tuple2) > > > > list1.__iadd__(list2) > > > > > Does it IN PRACTICE bring sufficient benefits to users? > > > > I found myself needing this when I was writing a monte-carlo > > simulation in python that required incrementing a tallying counter > > from a subroutine. > > > > > Wouldn't a numpy array be very suited for this kind of task? > > > > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: < > http://mail.python.org/pipermail/python-ideas/attachments/20180827/a1c698af/attachment-0001.html > > > > ------------------------------ > > Message: 2 > Date: Mon, 27 Aug 2018 07:25:00 +0100 > From: Jonathan Fine > To: python-ideas > Subject: Re: [Python-ideas] Unpacking iterables for augmented > assignment > Message-ID: > Yf9B7ErXAnBvBXZ2yBjR4ZLeyv1tpHV7+U3ebO2sw08wPA at mail.gmail.com> > Content-Type: text/plain; charset="UTF-8" > > James has suggested that Python be enhanced so that > >>> a, b += c, d > is a short-hand for > >>> a += c > >>> b += d > > Myself, James and Matthew wrote > > >> > Does it IN PRACTICE bring sufficient benefits to users? > > >> I found myself needing this when I was writing a monte-carlo > >> simulation in python that required incrementing a tallying counter > >> from a subroutine. > > > Wouldn't a numpy array be very suited for this kind of task? > > Perhaps, James, you might like to refactor your code so that > >>> tally += simulation(args) > does what you want. > > As Matthew points out, you could use numpy.array. Or code your own > class, by providing __add__ and __iadd__ methods. > > >>> import numpy > >>> a = numpy.array([1, 2]) > >>> b = numpy.array([3, 4]) > >>> a + b > array([4, 6]) > >>> a += b > >>> a > array([4, 6]) > > -- > Jonathan > > > ------------------------------ > > Message: 3 > Date: Mon, 27 Aug 2018 09:04:21 +0200 > From: Jacco van Dorp > To: python-ideas > Subject: Re: [Python-ideas] Pre-conditions and post-conditions > Message-ID: > KZLVcH+6mK+imzvnCDf412QKpo4FOjmETLF2Euu9wgA at mail.gmail.com> > Content-Type: text/plain; charset="utf-8" > > Total noob speaking here, but.... > > Those contracts are mostly important during development right ? Slowdown > isn't that much of an issue during development. So you could make a debug > mode that enforces the contracts, and a production mode that code users can > use during production to stop the slowdown - in this case, your decorators > can return their functions/classes unaltered. If they do end up with > problems, you can always ask them to run the same inputs with debug mode on > to see where it goes wrong. > > For the rest, i'm totally new to design by contract. I do get the draw of > it, but im not sure if I'd ever really use it. I tend to solve my problems > with a royal sprinkling of logger.debug(f"{val_i_need_to_check}"). > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: < > http://mail.python.org/pipermail/python-ideas/attachments/20180827/e59ffdd2/attachment-0001.html > > > > ------------------------------ > > Message: 4 > Date: Mon, 27 Aug 2018 09:24:20 +0100 > From: Ivan Levkivskyi > To: j.van.dorp at deonet.nl > Cc: python-ideas > Subject: Re: [Python-ideas] Pre-conditions and post-conditions > Message-ID: > vNe9yHGFYjLg at mail.gmail.com> > Content-Type: text/plain; charset="utf-8" > > TBH, I think one of the main points of design by contract is that contracts > are verified statically. > For runtime contract checking I would rather recommend hypothesis library > (or similar). > > -- > Ivan > > > > On Mon, 27 Aug 2018 at 08:05, Jacco van Dorp wrote: > > > Total noob speaking here, but.... > > > > Those contracts are mostly important during development right ? Slowdown > > isn't that much of an issue during development. So you could make a debug > > mode that enforces the contracts, and a production mode that code users > can > > use during production to stop the slowdown - in this case, your > decorators > > can return their functions/classes unaltered. If they do end up with > > problems, you can always ask them to run the same inputs with debug mode > on > > to see where it goes wrong. > > > > For the rest, i'm totally new to design by contract. I do get the draw of > > it, but im not sure if I'd ever really use it. I tend to solve my > problems > > with a royal sprinkling of logger.debug(f"{val_i_need_to_check}"). > > _______________________________________________ > > Python-ideas mailing list > > Python-ideas at python.org > > https://mail.python.org/mailman/listinfo/python-ideas > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: < > http://mail.python.org/pipermail/python-ideas/attachments/20180827/5cdeae6c/attachment.html > > > > ------------------------------ > > Subject: Digest Footer > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > > > ------------------------------ > > End of Python-ideas Digest, Vol 141, Issue 145 > ********************************************** > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Mon Aug 27 20:03:40 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Tue, 28 Aug 2018 10:03:40 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> Message-ID: <20180828000340.GI24160@ando.pearwood.info> On Mon, Aug 27, 2018 at 11:01:21AM -0400, Wes Turner wrote: > Runtime checks: data validation & code validation > Compile-time checks: code validation > > What sort of data validation is appropriate for assert statements or > contacts that may be skipped due to trading performance for more risk > ('optimized out')? That depends on what you mean by "data validation". Testing for bad input, or testing for predictable error states such as I/O errors, missing files, permission errors, server down etc is not appropriate for assertions (which includes contracts). The rule I use is that assertions are for: (1) testing your program state, which is under your control; and (2) communicating the intention of your program as executable code rather than comments. The ultimate aim of contracts and assertions is to eventually disable them when the program is bug-free. The Eiffel docs say: It should be clear from the preceding discussion that contracts are not a mechanism to test for special conditions, for example erroneous user input. For that purpose, the usual control structures [...] are available [...] An assertion is instead a correctness condition governing the relationship between two software modules (not a software module and a human, or a software module and an external device). ... Bluntly: Rule -- Assertion Violation: A run-time assertion violation is the manifestation of a bug. https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions For detecting *external* error states (anything to do with data that comes from outside your program, like user input) you can never let your guard down and never disable the test, because servers can always go down, users can always give you bad data, files can always be corrupt. It is unsafe to disable these tests and so these should not be assertions. For a library function intended to be called by third-parties, the function arguments aren't under the control of the library author so should not be tested with assertions. But for an application where the author controls those function arguments, they are under the author's control and may be assertions or contracts. Design By Contract is partly a methodology and partly a set of syntax. Its a way of thinking about the design of your program. In practice, you don't have to buy 100% into DBC to get some benefit for it. A study done a few years back looked at 21 large projects in Eiffel, JML (Java) and Code Contracts for C# and found that 33% of the classes used contracts. http://se.ethz.ch/~meyer/publications/methodology/contract_analysis.pdf Like unit testing, you don't need 100% coverage to get benefit. 10% is better than nothing, and 20% is better than 10%. I wrote more about assertions here: https://import-that.dreamwidth.org/676.html -- Steve From wes.turner at gmail.com Mon Aug 27 21:18:59 2018 From: wes.turner at gmail.com (Wes Turner) Date: Mon, 27 Aug 2018 21:18:59 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180828000340.GI24160@ando.pearwood.info> References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> Message-ID: Thanks for the explanation. This may be a bit OT, but is there a good way to do runtime assertions (in particular for data validation) that's as easy as assert? - self.assertEqual (unittest.TestCase.assertEqual) is hardly usable in other class instances, - pytest can be used at runtime but has somewhat nontrivial overhead - I always end up writing e.g. _assert() and _assertEqual() that throw AssertionErrors and helpful error messages just like unittest. How do contracts differ from checking interfaces with e.g. zope.interface? https://zopeinterface.readthedocs.io/en/latest/verify.html I'll read up a bit more on design by contract. I seem to have conceptualized dbc as a composition approach with typed interfaces and type and value assertions, but that's not it? If the parameter value assertions in pycontracts aren't really contracts, and the mypy compile-time parameter and return type checks are not really contracts, and zope.interface verifications aren't really contracts; what does that leave in terms of abstract data types, preconditions, postconditions, and invariants? https://en.wikipedia.org/wiki/Design_by_contract On Monday, August 27, 2018, Steven D'Aprano wrote: > On Mon, Aug 27, 2018 at 11:01:21AM -0400, Wes Turner wrote: > > Runtime checks: data validation & code validation > > Compile-time checks: code validation > > > > What sort of data validation is appropriate for assert statements or > > contacts that may be skipped due to trading performance for more risk > > ('optimized out')? > > That depends on what you mean by "data validation". > > Testing for bad input, or testing for predictable error states such as > I/O errors, missing files, permission errors, server down etc is > not appropriate for assertions (which includes contracts). > > The rule I use is that assertions are for: > > (1) testing your program state, which is under your control; and > > (2) communicating the intention of your program as executable > code rather than comments. > > The ultimate aim of contracts and assertions is to eventually disable > them when the program is bug-free. > > The Eiffel docs say: > > It should be clear from the preceding discussion that contracts > are not a mechanism to test for special conditions, for example > erroneous user input. For that purpose, the usual control > structures [...] are available [...] An assertion is instead a > correctness condition governing the relationship between two > software modules (not a software module and a human, or a > software module and an external device). ... Bluntly: > > Rule -- Assertion Violation: A run-time assertion violation is > the manifestation of a bug. > > https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_ > %28tm%29%2C_Assertions_and_Exceptions > > For detecting *external* error states (anything to do with data that > comes from outside your program, like user input) you can never let your > guard down and never disable the test, because servers can always go > down, users can always give you bad data, files can always be corrupt. > It is unsafe to disable these tests and so these should not be > assertions. > > For a library function intended to be called by third-parties, the > function arguments aren't under the control of the library author so > should not be tested with assertions. But for an application where the > author controls those function arguments, they are under the author's > control and may be assertions or contracts. > > Design By Contract is partly a methodology and partly a set of syntax. > Its a way of thinking about the design of your program. In practice, you > don't have to buy 100% into DBC to get some benefit for it. A study done > a few years back looked at 21 large projects in Eiffel, JML (Java) and > Code Contracts for C# and found that 33% of the classes used contracts. > > http://se.ethz.ch/~meyer/publications/methodology/contract_analysis.pdf > > Like unit testing, you don't need 100% coverage to get benefit. 10% is > better than nothing, and 20% is better than 10%. > > I wrote more about assertions here: > > https://import-that.dreamwidth.org/676.html > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Tue Aug 28 01:46:02 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Tue, 28 Aug 2018 07:46:02 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> Message-ID: Hi, To clarify the benefits of the contracts, let me give you an example from our code base: @icontract.pre(lambda x: x >= 0) @icontract.pre(lambda y: y >= 0) @icontract.pre(lambda width: width >= 0) @icontract.pre(lambda height: height >= 0) @icontract.pre(lambda x, width, img: x + width <= pqry.opencv.width_of(img)) @icontract.pre(lambda y, height, img: y + height <= pqry.opencv.height_of(img)) @icontract.post(lambda self: (self.x, self.y) in self) @icontract.post(lambda self: (self.x + self.width - 1, self.y + self.height - 1) in self) @icontract.post(lambda self: (self.x + self.width, self.y + self.height) not in self) def __init__(self, img: np.ndarray, x: int, y: int, width: int, height: int) -> None: self.img = img[y:y + height, x:x + width].copy() self.x = x self.y = y self.width = width self.height = height def __contains__(self, xy: Tuple[int, int]) -> bool: x, y = xy return self.x <= x < self.x + self.width and \ self.y <= y < self.y + self.height We use mypy and type annotations for typing, and we don't need contracts for that. In this particular case, contracts are very handy to formulate how we deal with pixels. If you carefully look at the contracts, you will see: * pixels are indexed starting from 0 (as oppose to starting from 1) * region-of-interest needs to fit within an image. It can not be outside of its boundaries * pixels within the region-of-interest are in [x, x + width), [y, y + height) (where "[" means inclusive and ")" exclusive) *Why not types?* These constraints are either impossible or very hard to write as types. Moreover, I doubt that you could give such types meaningful names, and I expect the readability to suffer immensely. I suppose any constraints involving more than a couple of variables is hard to write as a type. *Benefits.* You could write all of this in human-readable informal docstring of a class, but then it would never be verified. This way we are sure that contracts are always there. Whenever we test, we can be sure that all the contracted properties hold. Mind that we do not test that they hold for that single test case -- we automatically test that they hold for all the test cases. This is, in my opinion, far superior to ambiguous human documentation or print statements (which are deleted after the debugging). I suppose *any* larger code base built by a team of more than one developer needs this kind of rigor. The contracts are not meant to be used only in high-risk applications -- they are meant to improve any code base. *Problem without standard support. *The current libraries (dpcontracts, icontract) can deal with pre and postconditions and class invariants of a concrete class. However, the current libraries break as soon as you have inheritance. There is no way in python to inherit the function decorators and to modify them. If we are to inherit from the above-mentioned class ROI, we need to make sure that the invariants of the parent class hold (*e.g., *what is contained in a ROI) as well as invariants of the child class. We might want to weaken the requirements (*e.g., *a ROI that can deal with pixels outside of an image) such that x and y can be an arbitrary numbers, not restricted to 0 <= x < img.width and 0 <= y < img.height respectively. Additionally, without standard approach, we do not know how to deal with contracts when we have a third-party tool that would like to use them (*e.g., *for automatic generation of unit tests, static testing or visualization in IDE or in documentation). @Wes Turner : If I understood you correctly, you are looking for a library that gives you verbose messages when a contract is breached. Please have a look at icontract library: https://github.com/Parquery/icontract We added informative messages particularly because we wanted to have verbose output when something goes wrong.This was helpful not only during the development, but also in production since failure cases were hard to reproduce and anticipate in the first place (otherwise, they wouldn't have made it into the production). Here is an example with an error message: >>> class B:... def __init__(self) -> None:... self.x = 7...... def y(self) -> int:... return 2...... def __repr__(self) -> str:... return "instance of B"...>>> class A:... def __init__(self)->None:... self.b = B()...... def __repr__(self) -> str:... return "instance of A"...>>> SOME_GLOBAL_VAR = 13>>> @icontract.pre(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR)... def some_func(a: A) -> None:... pass...>>> an_a = A()>>> some_func(an_a) Traceback (most recent call last): ... icontract.ViolationError: Precondition violated: (a.b.x + a.b.y()) > SOME_GLOBAL_VAR:SOME_GLOBAL_VAR was 13 a was instance of A a.b was instance of B a.b.x was 7 a.b.y() was 2 On Tue, 28 Aug 2018 at 03:19, Wes Turner wrote: > Thanks for the explanation. > > This may be a bit OT, > but is there a good way to do runtime assertions (in particular for data > validation) that's as easy as assert? > > - self.assertEqual (unittest.TestCase.assertEqual) is hardly usable in > other class instances, > - pytest can be used at runtime but has somewhat nontrivial overhead > - I always end up writing e.g. _assert() and _assertEqual() that throw > AssertionErrors and helpful error messages just like unittest. > > > How do contracts differ from checking interfaces with e.g. zope.interface? > https://zopeinterface.readthedocs.io/en/latest/verify.html > > I'll read up a bit more on design by contract. I seem to have > conceptualized dbc as a composition approach with typed interfaces and type > and value assertions, but that's not it? > > If the parameter value assertions in pycontracts aren't really contracts, > and the mypy compile-time parameter and return type checks are not really > contracts, and zope.interface verifications aren't really contracts; what > does that leave in terms of abstract data types, preconditions, > postconditions, and invariants? > > https://en.wikipedia.org/wiki/Design_by_contract > > On Monday, August 27, 2018, Steven D'Aprano wrote: > >> On Mon, Aug 27, 2018 at 11:01:21AM -0400, Wes Turner wrote: >> > Runtime checks: data validation & code validation >> > Compile-time checks: code validation >> > >> > What sort of data validation is appropriate for assert statements or >> > contacts that may be skipped due to trading performance for more risk >> > ('optimized out')? >> >> That depends on what you mean by "data validation". >> >> Testing for bad input, or testing for predictable error states such as >> I/O errors, missing files, permission errors, server down etc is >> not appropriate for assertions (which includes contracts). >> >> The rule I use is that assertions are for: >> >> (1) testing your program state, which is under your control; and >> >> (2) communicating the intention of your program as executable >> code rather than comments. >> >> The ultimate aim of contracts and assertions is to eventually disable >> them when the program is bug-free. >> >> The Eiffel docs say: >> >> It should be clear from the preceding discussion that contracts >> are not a mechanism to test for special conditions, for example >> erroneous user input. For that purpose, the usual control >> structures [...] are available [...] An assertion is instead a >> correctness condition governing the relationship between two >> software modules (not a software module and a human, or a >> software module and an external device). ... Bluntly: >> >> Rule -- Assertion Violation: A run-time assertion violation is >> the manifestation of a bug. >> >> >> https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions >> >> For detecting *external* error states (anything to do with data that >> comes from outside your program, like user input) you can never let your >> guard down and never disable the test, because servers can always go >> down, users can always give you bad data, files can always be corrupt. >> It is unsafe to disable these tests and so these should not be >> assertions. >> >> For a library function intended to be called by third-parties, the >> function arguments aren't under the control of the library author so >> should not be tested with assertions. But for an application where the >> author controls those function arguments, they are under the author's >> control and may be assertions or contracts. >> >> Design By Contract is partly a methodology and partly a set of syntax. >> Its a way of thinking about the design of your program. In practice, you >> don't have to buy 100% into DBC to get some benefit for it. A study done >> a few years back looked at 21 large projects in Eiffel, JML (Java) and >> Code Contracts for C# and found that 33% of the classes used contracts. >> >> http://se.ethz.ch/~meyer/publications/methodology/contract_analysis.pdf >> >> Like unit testing, you don't need 100% coverage to get benefit. 10% is >> better than nothing, and 20% is better than 10%. >> >> I wrote more about assertions here: >> >> https://import-that.dreamwidth.org/676.html >> >> >> -- >> Steve >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From j.van.dorp at deonet.nl Tue Aug 28 03:02:11 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Tue, 28 Aug 2018 09:02:11 +0200 Subject: [Python-ideas] A GUI for beginners and experts alike In-Reply-To: References: <5B809B20.70407@canterbury.ac.nz> Message-ID: Didn't see the Qt version of the adding together with GUI yet, so here I have a minimalist version: import sys from PyQt5.QtWidgets import QWidget, QSpinBox, QLabel, QApplication, QHBoxLayout app = QApplication(sys.argv) w = QWidget() w.setLayout(QHBoxLayout()) spinOne = QSpinBox(w) spinTwo = QSpinBox(w) output = QLabel(w) def add(): output.setText(str(spinOne.value() + spinTwo.value())) spinOne.valueChanged.connect(add) spinTwo.valueChanged.connect(add) w.layout().addWidget(spinOne) w.layout().addWidget(spinTwo) w.layout().addWidget(output) w.show() app.exec() And here a version how I'd actually like to see it if written seriously: import sys from PyQt5.QtCore import pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QWidget, QSpinBox, QLabel, QApplication, QHBoxLayout class AddWidget(QWidget): newValue = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) self.setLayout(QHBoxLayout(self)) self.firstInput = QSpinBox(self) self.layout().addWidget(self.firstInput) self.firstInput.valueChanged.connect(self.addTogether) self.secondInput = QSpinBox(self) self.layout().addWidget(self.secondInput) self.secondInput.valueChanged.connect(self.addTogether) self.output = QLabel(self) self.layout().addWidget(self.output) self.newValue.connect(self.output.setText) @pyqtSlot(int) def addTogether(self, arg): self.newValue.emit(str(self.firstInput.value() + self.secondInput.value())) if __name__ == "__main__": app = QApplication(sys.argv) w = AddWidget() w.show() app.exec() I'll fully admit it takes a few lines more code to actually do it right compared to the other mentioned GUI frameworks, but it shows nicely how it's really a toolbox full of stuff you can use to assemble what you need. -------------- next part -------------- An HTML attachment was scrubbed... URL: From j.van.dorp at deonet.nl Tue Aug 28 03:11:34 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Tue, 28 Aug 2018 09:11:34 +0200 Subject: [Python-ideas] Python-ideas Digest, Vol 141, Issue 145 In-Reply-To: References: Message-ID: Op ma 27 aug. 2018 om 23:18 schreef James Lu : > > As Matthew points out, you could use numpy.array. Or code your own > > class, by providing __add__ and __iadd__ methods. > > > > >>> import numpy > > >>> a = numpy.array([1, 2]) > > >>> b = numpy.array([3, 4]) > > >>> a + b > > array([4, 6]) > > >>> a += b > > >>> a > > array([4, 6]) > > I could, but I don't think that justifies not having this functionality in > python > standard. From the language experience perspective, numpy is often a > pain to install on most systems. If I'm designing card games and I > just want to run a quick monte carlo simulation, the experience should be > as smooth as possible. > > This is something I think most students will expect while learning python, > especially if they're implementing algorithms. > To be really honest, if you want to run it as "smooth as possible" you'll NEED numpy anyway. If you have an algoritmn of any significant mathematical complexity, numpy's Fortran implementation will beat out pure python easily. I don't have any experience with monte carlo simulations myself, but if you're doing this any significant amount of times you'll be better off creating a numpy array. And personally I just grab Anaconda. It knows how to install wherever, and includes numpy and a lot of other things you might need. If you want it smooth, for beginners, that'd be my first recommendation. (Actually, I started using it because I had trouble installing numpy stack on a new system back when I was a noob.) Most students learning python will probably be on windows, so just down loading an installer and clicking through it should be more than familiar for them. -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Tue Aug 28 04:00:21 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Tue, 28 Aug 2018 17:00:21 +0900 Subject: [Python-ideas] Unpacking iterables for augmented assignment In-Reply-To: References: <23426.38022.793408.739343@turnbull.sk.tsukuba.ac.jp> <23426.58528.582721.814810@turnbull.sk.tsukuba.ac.jp> Message-ID: <23429.277.62034.466316@turnbull.sk.tsukuba.ac.jp> Tim Peters writes: > [Stephen J. Turnbull[ > > No. It's equivalent to > > > > = > > = > > = > > > > and the order matters because the s may have side effects. > > This is tricky stuff. Thank you, and Guido, for the correction. From turnbull.stephen.fw at u.tsukuba.ac.jp Tue Aug 28 04:05:25 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Tue, 28 Aug 2018 17:05:25 +0900 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: Message-ID: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> Executive summary: Much of this is my opinion, and as a newer poster, your opinion is *more* valuable than mine (fresh eyes and all that). What I hope you'll take from this post is a more precise understanding of the customary criteria that are used in evaluating a proposed feature on python-ideas and python-dev. Apologies for breaking the thread, but per Subject it's not really part of the thread. James Lu writes: > I could, but I don't think that justifies not having this > functionality in python standard. What's "this"? Note: >> When replying, please edit your Subject line so it is more specific >> than "Re: Contents of Python-ideas digest..." I had to edit the Subject. I'm going to assume you mean >> 1. Re: Unpacking iterables for augmented assignment (Matthew Einhorn) So. The Python development community generally doesn't require justification for refusing to implement new functionality. Rather, because Python has become a big and very complete programming environment, and a fairly large language, implementing new syntax requires that a feature increase expressiveness substantially. In the case in point, the destructuring assignments a, b = b, a w, x, y, z = z, w, y, x can be interpreted as "swapping" or "permuting", and AIUI that's why they were included. They express the intent better than tmp = a a = b b = tmp del tmp and I don't want to even think about how to do the 4-variable version without 4 temporary variables. By comparison, x, y += a, b is neither more expressive, nor easier to read, nor significantly harder to type, than x += a y += b as far as I can see. Note that this is the "not harder to type" criterion normally used in discussing new Python features, not something I've invented. > This is something I think most students will expect while learning > python, especially if they're implementing algorithms. I suppose this claim is unlikely to be accepted without testimony of several teachers of Python. In my own experience, I explicitly teach my students that the destructuring assignment is *for* permuting, and I have *not even once* been asked if it works for augmented assignments. By contrast, students with knowledge of other languages (especially C-like languages) invariably "just use" augmented assignments and ask if there's some spelling for increment and decrement expressions. Obviously, my teaching approach biases the result, but if nobody ever overcomes that bias, I do not think it is an expected or needed feature. Steve From rosuav at gmail.com Tue Aug 28 04:15:42 2018 From: rosuav at gmail.com (Chris Angelico) Date: Tue, 28 Aug 2018 18:15:42 +1000 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> Message-ID: On Tue, Aug 28, 2018 at 6:05 PM, Stephen J. Turnbull wrote: > In the case in point, the destructuring assignments > > a, b = b, a > w, x, y, z = z, w, y, x > > can be interpreted as "swapping" or "permuting", and AIUI that's why > they were included. They express the intent better than > > tmp = a > a = b > b = tmp > del tmp > > and I don't want to even think about how to do the 4-variable version > without 4 temporary variables. By comparison, > > x, y += a, b > > is neither more expressive, nor easier to read, nor significantly > harder to type, than > > x += a > y += b > > as far as I can see. When you have completely different variables, sure. But what if - like in the swap example - they're the same variables? def frobnicate(): a, b, c = 1, 10, 100 while True: a, b, c += b, c, a yield a On the first iteration, this would be: a += 10 b += 100 c += 1 I don't have an actual use-case, but to be fair, I also have very few use-cases for swapping/permuting. -0 on adding it, but it's not an illogical feature. ChrisA From wes.turner at gmail.com Tue Aug 28 12:34:14 2018 From: wes.turner at gmail.com (Wes Turner) Date: Tue, 28 Aug 2018 12:34:14 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> Message-ID: I now fully understand your use case. IIUC, what would make this easier is a syntax for defining preconditions, post conditions, and invariants that supports: * inheritance, composition (mixins) This isn't possible with decorators because there's no reference to the post-decorated function/method. A conventional method naming scheme and composition like _pre_check_[004]_height() would be unreasonably verbose; though it would then be possible to 'relax' specific contracts by name. * A better flow? Decorators subvert the normal top-down source layout (and so require up-down eye movements and working memory to remember what's going on) * Test case generation Generate tests and fixtures to verify the preconditions, postconditions, and invariants. * An Interpretor/compilation flag to skip the contracts/tests/assertions PYTHONOPTIMIZE (-O, -OO), __debug__ Isn't there now an -X <...> interpretor flag in CPython? On Tuesday, August 28, 2018, Marko Ristin-Kaufmann wrote: > Hi, > To clarify the benefits of the contracts, let me give you an example from > our code base: > > @icontract.pre(lambda x: x >= 0) > @icontract.pre(lambda y: y >= 0) > @icontract.pre(lambda width: width >= 0) > @icontract.pre(lambda height: height >= 0) > @icontract.pre(lambda x, width, img: x + width <= pqry.opencv.width_of(img)) > @icontract.pre(lambda y, height, img: y + height <= pqry.opencv.height_of(img)) > @icontract.post(lambda self: (self.x, self.y) in self) > @icontract.post(lambda self: (self.x + self.width - 1, self.y + self.height - 1) in self) > @icontract.post(lambda self: (self.x + self.width, self.y + self.height) not in self) > def __init__(self, img: np.ndarray, x: int, y: int, width: int, height: int) -> None: > self.img = img[y:y + height, x:x + width].copy() > self.x = x > self.y = y > self.width = width > self.height = height > > def __contains__(self, xy: Tuple[int, int]) -> bool: > x, y = xy > return self.x <= x < self.x + self.width and \ > self.y <= y < self.y + self.height > > We use mypy and type annotations for typing, and we don't need contracts > for that. In this particular case, contracts are very handy to formulate > how we deal with pixels. If you carefully look at the contracts, you will > see: > * pixels are indexed starting from 0 (as oppose to starting from 1) > * region-of-interest needs to fit within an image. It can not be outside > of its boundaries > * pixels within the region-of-interest are in [x, x + width), [y, y + > height) (where "[" means inclusive and ")" exclusive) > > *Why not types?* These constraints are either impossible or very hard to > write as types. Moreover, I doubt that you could give such types meaningful > names, and I expect the readability to suffer immensely. I suppose any > constraints involving more than a couple of variables is hard to write as a > type. > > *Benefits.* You could write all of this in human-readable informal > docstring of a class, but then it would never be verified. This way we are > sure that contracts are always there. Whenever we test, we can be sure that > all the contracted properties hold. Mind that we do not test that they hold > for that single test case -- we automatically test that they hold for all > the test cases. > > This is, in my opinion, far superior to ambiguous human documentation or > print statements (which are deleted after the debugging). I suppose *any* > larger code base built by a team of more than one developer needs this kind > of rigor. The contracts are not meant to be used only in high-risk > applications -- they are meant to improve any code base. > > *Problem without standard support. *The current libraries (dpcontracts, > icontract) can deal with pre and postconditions and class invariants of a > concrete class. > > However, the current libraries break as soon as you have inheritance. > There is no way in python to inherit the function decorators and to modify > them. If we are to inherit from the above-mentioned class ROI, we need to > make sure that the invariants of the parent class hold (*e.g., *what is > contained in a ROI) as well as invariants of the child class. We might want > to weaken the requirements (*e.g., *a ROI that can deal with pixels > outside of an image) such that x and y can be an arbitrary numbers, not > restricted to 0 <= x < img.width and 0 <= y < img.height respectively. > > Additionally, without standard approach, we do not know how to deal with > contracts when we have a third-party tool that would like to use them (*e.g., > *for automatic generation of unit tests, static testing or visualization > in IDE or in documentation). > > @Wes Turner : If I understood you correctly, you > are looking for a library that gives you verbose messages when a contract > is breached. Please have a look at icontract library: > https://github.com/Parquery/icontract > > We added informative messages particularly because we wanted to have > verbose output when something goes wrong.This was helpful not only during > the development, but also in production since failure cases were hard to > reproduce and anticipate in the first place (otherwise, they wouldn't have > made it into the production). Here is an example with an error message: > > >>> class B:... def __init__(self) -> None:... self.x = 7...... def y(self) -> int:... return 2...... def __repr__(self) -> str:... return "instance of B"...>>> class A:... def __init__(self)->None:... self.b = B()...... def __repr__(self) -> str:... return "instance of A"...>>> SOME_GLOBAL_VAR = 13>>> @icontract.pre(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR)... def some_func(a: A) -> None:... pass...>>> an_a = A()>>> some_func(an_a) > Traceback (most recent call last): > ... > icontract.ViolationError: Precondition violated: (a.b.x + a.b.y()) > SOME_GLOBAL_VAR:SOME_GLOBAL_VAR was 13 > a was instance of A > a.b was instance of B > a.b.x was 7 > a.b.y() was 2 > > > On Tue, 28 Aug 2018 at 03:19, Wes Turner wrote: > >> Thanks for the explanation. >> >> This may be a bit OT, >> but is there a good way to do runtime assertions (in particular for data >> validation) that's as easy as assert? >> >> - self.assertEqual (unittest.TestCase.assertEqual) is hardly usable in >> other class instances, >> - pytest can be used at runtime but has somewhat nontrivial overhead >> - I always end up writing e.g. _assert() and _assertEqual() that throw >> AssertionErrors and helpful error messages just like unittest. >> >> >> How do contracts differ from checking interfaces with e.g. zope.interface? >> https://zopeinterface.readthedocs.io/en/latest/verify.html >> >> I'll read up a bit more on design by contract. I seem to have >> conceptualized dbc as a composition approach with typed interfaces and type >> and value assertions, but that's not it? >> >> If the parameter value assertions in pycontracts aren't really contracts, >> and the mypy compile-time parameter and return type checks are not really >> contracts, and zope.interface verifications aren't really contracts; what >> does that leave in terms of abstract data types, preconditions, >> postconditions, and invariants? >> >> https://en.wikipedia.org/wiki/Design_by_contract >> >> On Monday, August 27, 2018, Steven D'Aprano wrote: >> >>> On Mon, Aug 27, 2018 at 11:01:21AM -0400, Wes Turner wrote: >>> > Runtime checks: data validation & code validation >>> > Compile-time checks: code validation >>> > >>> > What sort of data validation is appropriate for assert statements or >>> > contacts that may be skipped due to trading performance for more risk >>> > ('optimized out')? >>> >>> That depends on what you mean by "data validation". >>> >>> Testing for bad input, or testing for predictable error states such as >>> I/O errors, missing files, permission errors, server down etc is >>> not appropriate for assertions (which includes contracts). >>> >>> The rule I use is that assertions are for: >>> >>> (1) testing your program state, which is under your control; and >>> >>> (2) communicating the intention of your program as executable >>> code rather than comments. >>> >>> The ultimate aim of contracts and assertions is to eventually disable >>> them when the program is bug-free. >>> >>> The Eiffel docs say: >>> >>> It should be clear from the preceding discussion that contracts >>> are not a mechanism to test for special conditions, for example >>> erroneous user input. For that purpose, the usual control >>> structures [...] are available [...] An assertion is instead a >>> correctness condition governing the relationship between two >>> software modules (not a software module and a human, or a >>> software module and an external device). ... Bluntly: >>> >>> Rule -- Assertion Violation: A run-time assertion violation is >>> the manifestation of a bug. >>> >>> https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_ >>> %28tm%29%2C_Assertions_and_Exceptions >>> >>> For detecting *external* error states (anything to do with data that >>> comes from outside your program, like user input) you can never let your >>> guard down and never disable the test, because servers can always go >>> down, users can always give you bad data, files can always be corrupt. >>> It is unsafe to disable these tests and so these should not be >>> assertions. >>> >>> For a library function intended to be called by third-parties, the >>> function arguments aren't under the control of the library author so >>> should not be tested with assertions. But for an application where the >>> author controls those function arguments, they are under the author's >>> control and may be assertions or contracts. >>> >>> Design By Contract is partly a methodology and partly a set of syntax. >>> Its a way of thinking about the design of your program. In practice, you >>> don't have to buy 100% into DBC to get some benefit for it. A study done >>> a few years back looked at 21 large projects in Eiffel, JML (Java) and >>> Code Contracts for C# and found that 33% of the classes used contracts. >>> >>> http://se.ethz.ch/~meyer/publications/methodology/contract_analysis.pdf >>> >>> Like unit testing, you don't need 100% coverage to get benefit. 10% is >>> better than nothing, and 20% is better than 10%. >>> >>> I wrote more about assertions here: >>> >>> https://import-that.dreamwidth.org/676.html >>> >>> >>> -- >>> Steve >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> _______________________________________________ >> Python-ideas mailing list >> Python-ideas at python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Tue Aug 28 12:37:09 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Wed, 29 Aug 2018 01:37:09 +0900 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> Message-ID: <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> Chris Angelico writes: > When you have completely different variables, sure. But what if - like > in the swap example - they're the same variables? > > a, b, c += b, c, a Good point. a, b, c = a + b, b + c, c + a is "good enough" for this particular case, I'd say, and has the advantage that it immediately generalizes to mixed operations: a, b, c = a + b, b - c, c * a I will say that the fact that neither of us has an immediate use case in mind is really the point of my previous post. Swaps frequently come up in sorting algorithms and heap structure modifications. Swapping alone might be enough to justify the destructuring assignment. Steve From guido at python.org Tue Aug 28 13:57:10 2018 From: guido at python.org (Guido van Rossum) Date: Tue, 28 Aug 2018 19:57:10 +0200 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> Message-ID: So we currently have iterable unpacking: a, b, c = x # x better be an iterable of exactly 3 values as well as tuple packing: x = a, b, c # sets x to a tuple of 3 values (a, b, c) and we can combine these, e.g.: a, b, c = x, y, z and this still creates an intermediate, anonymous tuple from the values on the right. (At least in the formal semantics -- it may be optimized away if that can be done safely.) This leads to the following idioms: a, b = b, a # swap variables a, b, c = b, c, a # rotate variables That's all well established (and I have to admit that the elegance of the swap idiom was one reason to add this to the earliest version of the language). The proposal on the table is to see if there's a logical extension for augmented assignment. If we look at this: a, b, c = x, y, z and notice that it's equivalent to this: a = x b = y c = z we might propose (as the OP did) that this: a, b, c += x, y, z could be made equivalent to this: a += x b += y c += z but the question is, what would this do? a, b, c += x Presumably it requires that x is an iterable of 3 values, so it would be translated to this first: x0, x1, x2 = x a, b, c += x0, x1, x2 However, a user who doesn't typically think about the actual semantics of iterable unpacking and tuple packing might think this would instead mean the following: a += x b += x c += x IOW they might think that this is a clever way to increment three variables at once: a, b, c += 1 This ambiguity (in naive users' minds) leads me to frown upon the proposal. If we were to ignore the naive view, we could definitely give semantics to `a, b, c += ...` -- basically it would unpack the RHS into the right number of elements (if needed) and call __iadd__ pairwise. But I am not so keen, because the ambiguity of `a, b, c += x`. Perhaps someone can do some research and unearth real code that contains series of += assignments that would become more readable by collapsing them into a single line using the proposed construct. -- --Guido van Rossum (python.org/~guido) -------------- next part -------------- An HTML attachment was scrubbed... URL: From prometheus235 at gmail.com Tue Aug 28 14:52:55 2018 From: prometheus235 at gmail.com (Nick Timkovich) Date: Tue, 28 Aug 2018 13:52:55 -0500 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> Message-ID: On Tue, Aug 28, 2018 at 12:57 PM Guido van Rossum wrote: > However, a user who doesn't typically think about the actual semantics of > iterable unpacking and tuple packing might think this would instead mean > the following: > > a += x > b += x > c += x > > IOW they might think that this is a clever way to increment three > variables at once: > > a, b, c += 1 > > This ambiguity (in naive users' minds) leads me to frown upon the proposal. > This sort of broadcasting is often quite convenient in Numpy, where many arithmetic operators will accept scalars or vectors and generally "do the right thing" in the context. It gets complicated in higher dimensions, but for 0/1-dimensions you don't need an axis-selector. abc = np.array([1, 2, 3]) abc += 1 print(abc) # [2 3 4] abc += [10, 100, 1000] print(abc) # [ 12 103 1004] The quirks I see are with + being a concatenation operator for lists/tuples. a, b = (10, 20) # a, b += (1, 2) # a, b == 11, 22? (a, b) + (1, 2) # (10, 20, 1, 2) Nick -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Tue Aug 28 15:20:10 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Tue, 28 Aug 2018 20:20:10 +0100 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> Message-ID: Guido wrote > Perhaps someone can do some research and unearth real code that contains > series of += assignments that would become more readable by collapsing them > into a single line using the proposed construct. Here's some notes towards finding (or constructing) such examples. First note that it's awkward to unpack a, b = b, a # swap values because this simple solution does not work (as we need a temporary) a = b b = a so perhaps our example should require unpacking, to avoid the use of temporarys. Now consider, for example, wibble(4).wobble.cheese += 8 This has semantics tmp1 = wibble(4).wobble tmp2 = tmp1.cheese tmp1.cheese = tmp2 + 8 which is different to and harder to write than wibble(4).wobble.cheese = wibble(4).wobble.cheese + 8 so perhaps our example should involve an assignable expression, such as wibble(4).wobble.cheese. So here's a concocted example. ns.aaa.a, ns.bbb.b, += 2 * ns.bbb.b, 3 * ns.aaa.a I describe this as a namespace-of-values, whose values change at least logically all at the same time. In other words, it's something like vector = apply(matrix, vector) This example can be expanded by first computing the values, and then doing the assignment. tmp1, tmp2 = ns.bbb.b, ns.aaa.a ns.aaa.a += 2 * tmp2 ns.bbb.b += 3 * tmp1 The following avoids the double lookup of ns.aaa.a (and of ns.bbb.b). tmp1, tmp2 = ns.bbb.b, ns.aaa.a ns.aaa.a = tmp1 + 2 * tmp2 ns.bbb.b = tmp2 + 3 * tmp1 So far, this is the best artificial example I've come up with. -- Jonathan From python at mrabarnett.plus.com Tue Aug 28 15:46:23 2018 From: python at mrabarnett.plus.com (MRAB) Date: Tue, 28 Aug 2018 20:46:23 +0100 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> Message-ID: <16f33347-63a3-9db5-db20-8fd315a0ee2a@mrabarnett.plus.com> On 2018-08-28 18:57, Guido van Rossum wrote: > So we currently have iterable unpacking: > > ? a, b, c = x? # x better be an iterable of exactly 3 values > > as well as tuple packing: > > ? x = a, b, c? # sets x to a tuple of 3 values (a, b, c) > > and we can combine these, e.g.: > > ? a, b, c = x, y, z > > and this still creates an intermediate, anonymous tuple from the values > on the right. (At least in the formal semantics -- it may be optimized > away if that can be done safely.) > > This leads to the following idioms: > > ? a, b = b, a? # swap variables > ? a, b, c = b, c, a? # rotate variables > > That's all well established (and I have to admit that the elegance of > the swap idiom was one reason to add this to the earliest version of the > language). > > The proposal on the table is to see if there's a logical extension for > augmented assignment. > > If we look at this: > > ? a, b, c = x, y, z > > and notice that it's equivalent to this: > > ? a = x > ? b = y > ? c = z > > we might propose (as the OP did) that this: > > ? a, b, c += x, y, z > > could be made equivalent to this: > > ? a += x > ? b += y > ? c += z > > but the question is, what would this do? > > ? a, b, c += x > > Presumably it requires that x is an iterable of 3 values, so it would be > translated to this first: > > ? x0, x1, x2 = x > ? a, b, c += x0, x1, x2 > > However, a user who doesn't typically think about the actual semantics > of iterable unpacking and tuple packing might think this would instead > mean the following: > > ? a += x > ? b += x > ? c += x > > IOW they might think that this is a clever way to increment three > variables at once: > > ? a, b, c += 1 > > This ambiguity (in naive users' minds) leads me to frown upon the proposal. > By the same logic, wouldn't such a naive user also expect: a, b, c = 0 to set three variables to 0? > If we were to ignore the naive view, we could definitely give semantics > to `a, b, c += ...` -- basically it would unpack the RHS into the right > number of elements (if needed) and call __iadd__ pairwise. But I am not > so keen, because the ambiguity of `a, b, c += x`. > > Perhaps someone can do some research and unearth real code that contains > series of += assignments that would become more readable by collapsing > them into a single line using the proposed construct. > From robertve92 at gmail.com Tue Aug 28 16:09:23 2018 From: robertve92 at gmail.com (Robert Vanden Eynde) Date: Tue, 28 Aug 2018 22:09:23 +0200 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: <16f33347-63a3-9db5-db20-8fd315a0ee2a@mrabarnett.plus.com> References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> <16f33347-63a3-9db5-db20-8fd315a0ee2a@mrabarnett.plus.com> Message-ID: > > > By the same logic, wouldn't such a naive user also expect: > > a, b, c = 0 > > to set three variables to 0? > > Let's notice that this syntax is valid: a = b = c = 0 But for += there is no such direct translation. -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Tue Aug 28 18:36:52 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Wed, 29 Aug 2018 10:36:52 +1200 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> <23429.31285.936745.529073@turnbull.sk.tsukuba.ac.jp> Message-ID: <5B85CE84.7080300@canterbury.ac.nz> Guido van Rossum wrote: > we might propose (as the OP did) that this: > > a, b, c += x, y, z > > could be made equivalent to this: > > a += x > b += y > c += z But not without violating the principle that lhs += rhs is equivalent to lhs = lhs.__iadd__(lhs) Granted, this rule inevitably leads to an "unpacking sequence of wrong length" error in the case we're considering, so we wouldn't be changing any useful existing semantics, but it's still making the rules more complicated. > but the question is, what would this do? > > a, b, c += x > > they might think that this is a clever way to increment three > variables at once: > > a, b, c += 1 Someone who thinks that might also think a, b, c = 1 is a way to assign 1 to a, b and c, but we don't seem to be worried about that possible misunderstanding. This does raise the question of what the corresponding generalisation of multiple assignment targets might be. Would you write a += b += c += 1 or a = b = c += 1 ? And if the former, do we allow different operations on each target, e.g. a += b -= c *= 2 ? -- Greg From mertz at gnosis.cx Tue Aug 28 19:32:43 2018 From: mertz at gnosis.cx (David Mertz) Date: Tue, 28 Aug 2018 19:32:43 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> Message-ID: I admit that I don't care that much about pre- and post-conditions. Like a lot of people I've written a you library to handle some cases, but was never motivates to make it better or use ones folks have refined. I definitely oppose dedicated syntax. Nonetheless, I'll say that it's really not hard to get a decorator to cooperate with inheritance if you want that. If you decorate a parent class you can simply attach the collection of invariants to the class as notations, along with whatever actual guards the decorator enforces. An inheriting child (also decorated) can just look up those notations and apply them to the child. I.e. the first thing a decorator can do is lookup the invariants attached to the parent (if any) and apply them to the child (if this behavior is enabled). Easy peasy. On Tue, Aug 28, 2018, 12:35 PM Wes Turner wrote: > I now fully understand your use case. > > IIUC, what would make this easier is a syntax for defining preconditions, > post conditions, and invariants that supports: > > * inheritance, composition (mixins) > > This isn't possible with decorators because there's no reference to the > post-decorated function/method. > > A conventional method naming scheme and composition like > _pre_check_[004]_height() would be unreasonably verbose; though it would > then be possible to 'relax' specific contracts by name. > > * A better flow? > > Decorators subvert the normal top-down source layout (and so require > up-down eye movements and working memory to remember what's going on) > > * Test case generation > > Generate tests and fixtures to verify the preconditions, postconditions, > and invariants. > > * An Interpretor/compilation flag to skip the contracts/tests/assertions > > PYTHONOPTIMIZE (-O, -OO), __debug__ > Isn't there now an -X <...> interpretor flag in CPython? > > On Tuesday, August 28, 2018, Marko Ristin-Kaufmann > wrote: > >> Hi, >> To clarify the benefits of the contracts, let me give you an example from >> our code base: >> >> @icontract.pre(lambda x: x >= 0) >> @icontract.pre(lambda y: y >= 0) >> @icontract.pre(lambda width: width >= 0) >> @icontract.pre(lambda height: height >= 0) >> @icontract.pre(lambda x, width, img: x + width <= pqry.opencv.width_of(img)) >> @icontract.pre(lambda y, height, img: y + height <= pqry.opencv.height_of(img)) >> @icontract.post(lambda self: (self.x, self.y) in self) >> @icontract.post(lambda self: (self.x + self.width - 1, self.y + self.height - 1) in self) >> @icontract.post(lambda self: (self.x + self.width, self.y + self.height) not in self) >> def __init__(self, img: np.ndarray, x: int, y: int, width: int, height: int) -> None: >> self.img = img[y:y + height, x:x + width].copy() >> self.x = x >> self.y = y >> self.width = width >> self.height = height >> >> def __contains__(self, xy: Tuple[int, int]) -> bool: >> x, y = xy >> return self.x <= x < self.x + self.width and \ >> self.y <= y < self.y + self.height >> >> We use mypy and type annotations for typing, and we don't need contracts >> for that. In this particular case, contracts are very handy to formulate >> how we deal with pixels. If you carefully look at the contracts, you will >> see: >> * pixels are indexed starting from 0 (as oppose to starting from 1) >> * region-of-interest needs to fit within an image. It can not be outside >> of its boundaries >> * pixels within the region-of-interest are in [x, x + width), [y, y + >> height) (where "[" means inclusive and ")" exclusive) >> >> *Why not types?* These constraints are either impossible or very hard to >> write as types. Moreover, I doubt that you could give such types meaningful >> names, and I expect the readability to suffer immensely. I suppose any >> constraints involving more than a couple of variables is hard to write as a >> type. >> >> *Benefits.* You could write all of this in human-readable informal >> docstring of a class, but then it would never be verified. This way we are >> sure that contracts are always there. Whenever we test, we can be sure that >> all the contracted properties hold. Mind that we do not test that they hold >> for that single test case -- we automatically test that they hold for all >> the test cases. >> >> This is, in my opinion, far superior to ambiguous human documentation or >> print statements (which are deleted after the debugging). I suppose *any* >> larger code base built by a team of more than one developer needs this kind >> of rigor. The contracts are not meant to be used only in high-risk >> applications -- they are meant to improve any code base. >> >> *Problem without standard support. *The current libraries (dpcontracts, >> icontract) can deal with pre and postconditions and class invariants of a >> concrete class. >> >> However, the current libraries break as soon as you have inheritance. >> There is no way in python to inherit the function decorators and to modify >> them. If we are to inherit from the above-mentioned class ROI, we need to >> make sure that the invariants of the parent class hold (*e.g., *what is >> contained in a ROI) as well as invariants of the child class. We might want >> to weaken the requirements (*e.g., *a ROI that can deal with pixels >> outside of an image) such that x and y can be an arbitrary numbers, not >> restricted to 0 <= x < img.width and 0 <= y < img.height respectively. >> >> Additionally, without standard approach, we do not know how to deal with >> contracts when we have a third-party tool that would like to use them (*e.g., >> *for automatic generation of unit tests, static testing or visualization >> in IDE or in documentation). >> >> @Wes Turner : If I understood you correctly, you >> are looking for a library that gives you verbose messages when a contract >> is breached. Please have a look at icontract library: >> https://github.com/Parquery/icontract >> >> We added informative messages particularly because we wanted to have >> verbose output when something goes wrong.This was helpful not only during >> the development, but also in production since failure cases were hard to >> reproduce and anticipate in the first place (otherwise, they wouldn't have >> made it into the production). Here is an example with an error message: >> >> >>> class B:... def __init__(self) -> None:... self.x = 7...... def y(self) -> int:... return 2...... def __repr__(self) -> str:... return "instance of B"...>>> class A:... def __init__(self)->None:... self.b = B()...... def __repr__(self) -> str:... return "instance of A"...>>> SOME_GLOBAL_VAR = 13>>> @icontract.pre(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR)... def some_func(a: A) -> None:... pass...>>> an_a = A()>>> some_func(an_a) >> Traceback (most recent call last): >> ... >> icontract.ViolationError: Precondition violated: (a.b.x + a.b.y()) > SOME_GLOBAL_VAR:SOME_GLOBAL_VAR was 13 >> a was instance of A >> a.b was instance of B >> a.b.x was 7 >> a.b.y() was 2 >> >> >> On Tue, 28 Aug 2018 at 03:19, Wes Turner wrote: >> >>> Thanks for the explanation. >>> >>> This may be a bit OT, >>> but is there a good way to do runtime assertions (in particular for data >>> validation) that's as easy as assert? >>> >>> - self.assertEqual (unittest.TestCase.assertEqual) is hardly usable in >>> other class instances, >>> - pytest can be used at runtime but has somewhat nontrivial overhead >>> - I always end up writing e.g. _assert() and _assertEqual() that throw >>> AssertionErrors and helpful error messages just like unittest. >>> >>> >>> How do contracts differ from checking interfaces with e.g. >>> zope.interface? >>> https://zopeinterface.readthedocs.io/en/latest/verify.html >>> >>> I'll read up a bit more on design by contract. I seem to have >>> conceptualized dbc as a composition approach with typed interfaces and type >>> and value assertions, but that's not it? >>> >>> If the parameter value assertions in pycontracts aren't really >>> contracts, and the mypy compile-time parameter and return type checks are >>> not really contracts, and zope.interface verifications aren't really >>> contracts; what does that leave in terms of abstract data types, >>> preconditions, postconditions, and invariants? >>> >>> https://en.wikipedia.org/wiki/Design_by_contract >>> >>> On Monday, August 27, 2018, Steven D'Aprano >>> wrote: >>> >>>> On Mon, Aug 27, 2018 at 11:01:21AM -0400, Wes Turner wrote: >>>> > Runtime checks: data validation & code validation >>>> > Compile-time checks: code validation >>>> > >>>> > What sort of data validation is appropriate for assert statements or >>>> > contacts that may be skipped due to trading performance for more risk >>>> > ('optimized out')? >>>> >>>> That depends on what you mean by "data validation". >>>> >>>> Testing for bad input, or testing for predictable error states such as >>>> I/O errors, missing files, permission errors, server down etc is >>>> not appropriate for assertions (which includes contracts). >>>> >>>> The rule I use is that assertions are for: >>>> >>>> (1) testing your program state, which is under your control; and >>>> >>>> (2) communicating the intention of your program as executable >>>> code rather than comments. >>>> >>>> The ultimate aim of contracts and assertions is to eventually disable >>>> them when the program is bug-free. >>>> >>>> The Eiffel docs say: >>>> >>>> It should be clear from the preceding discussion that contracts >>>> are not a mechanism to test for special conditions, for example >>>> erroneous user input. For that purpose, the usual control >>>> structures [...] are available [...] An assertion is instead a >>>> correctness condition governing the relationship between two >>>> software modules (not a software module and a human, or a >>>> software module and an external device). ... Bluntly: >>>> >>>> Rule -- Assertion Violation: A run-time assertion violation is >>>> the manifestation of a bug. >>>> >>>> >>>> https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions >>>> >>>> For detecting *external* error states (anything to do with data that >>>> comes from outside your program, like user input) you can never let >>>> your >>>> guard down and never disable the test, because servers can always go >>>> down, users can always give you bad data, files can always be corrupt. >>>> It is unsafe to disable these tests and so these should not be >>>> assertions. >>>> >>>> For a library function intended to be called by third-parties, the >>>> function arguments aren't under the control of the library author so >>>> should not be tested with assertions. But for an application where the >>>> author controls those function arguments, they are under the author's >>>> control and may be assertions or contracts. >>>> >>>> Design By Contract is partly a methodology and partly a set of syntax. >>>> Its a way of thinking about the design of your program. In practice, >>>> you >>>> don't have to buy 100% into DBC to get some benefit for it. A study >>>> done >>>> a few years back looked at 21 large projects in Eiffel, JML (Java) and >>>> Code Contracts for C# and found that 33% of the classes used contracts. >>>> >>>> http://se.ethz.ch/~meyer/publications/methodology/contract_analysis.pdf >>>> >>>> Like unit testing, you don't need 100% coverage to get benefit. 10% is >>>> better than nothing, and 20% is better than 10%. >>>> >>>> I wrote more about assertions here: >>>> >>>> https://import-that.dreamwidth.org/676.html >>>> >>>> >>>> -- >>>> Steve >>>> _______________________________________________ >>>> Python-ideas mailing list >>>> Python-ideas at python.org >>>> https://mail.python.org/mailman/listinfo/python-ideas >>>> Code of Conduct: http://python.org/psf/codeofconduct/ >>>> >>> _______________________________________________ >>> Python-ideas mailing list >>> Python-ideas at python.org >>> https://mail.python.org/mailman/listinfo/python-ideas >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Tue Aug 28 21:58:39 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 29 Aug 2018 11:58:39 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> Message-ID: <20180829015839.GL24160@ando.pearwood.info> On Tue, Aug 28, 2018 at 07:46:02AM +0200, Marko Ristin-Kaufmann wrote: > Hi, > To clarify the benefits of the contracts, let me give you an example from > our code base: > > @icontract.pre(lambda x: x >= 0) > @icontract.pre(lambda y: y >= 0) > @icontract.pre(lambda width: width >= 0) > @icontract.pre(lambda height: height >= 0) > @icontract.pre(lambda x, width, img: x + width <= pqry.opencv.width_of(img)) > @icontract.pre(lambda y, height, img: y + height <= pqry.opencv.height_of(img)) > @icontract.post(lambda self: (self.x, self.y) in self) > @icontract.post(lambda self: (self.x + self.width - 1, self.y + > self.height - 1) in self) > @icontract.post(lambda self: (self.x + self.width, self.y + > self.height) not in self) > def __init__(self, img: np.ndarray, x: int, y: int, width: int, > height: int) -> None: Thanks for your example Marko. I think that is quite close to the ugliest piece of Python code I've ever seen, and I don't mean that as a criticism of you for writing it or the icontract library's design. We write code that our language allows us to write, not the code we want to write. Python has not been designed for contracts, and it shows. I think this demonstrates a truth about programming languages: Aethestics matter. Syntax matters. Some features, no matter how useful and beneficial, have no hope at all of getting widespread use if the syntax is awkward or the result ugly. I think that contracts will be doomed to be a minor niche used only by really keen proponents of the style so long as the best way to write a contract is to use a sequence of decorator calls with lambdas. I'm going to re-write that in a pseudo-Eiffel like syntax: def __init__(self, img: np.ndarray, x: int, y: int, width: int, height: int) -> None: require: x >= 0 y >= 0 width >= 0 height >= 0 x + width <= pqry.opencv.width_of(img) y + height <= pqry.opencv.height_of(img) # possibly this should be an invariant, not a post-condition? ensure: (self.x, self.y) in self (self.x + self.width - 1, self.y + self.height - 1) in self (self.x + self.width, self.y + self.height) not in self # body of __init__ goes here... This makes a huge difference to readability: - block structure to give visual shape to the code; - related code stays together (all the pre-conditions naturally go into the require block, post-conditions in the ensure block, and no chance of interleaving them @pre(...) @post(...) @pre(...) - no extraneous lambdas (they are pure noise); - no long sequence of decorators (more than one of each is pure noise); - possibility to write assertions which take more than one statement. -- Steve From wes.turner at gmail.com Wed Aug 29 00:41:50 2018 From: wes.turner at gmail.com (Wes Turner) Date: Wed, 29 Aug 2018 00:41:50 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180829015839.GL24160@ando.pearwood.info> References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> Message-ID: How are conditions relaxed/overridden in Eiffel without a named reference? That looks much more readable. Expressions within such blocks are implicitly assertTrue(s). What sort of test generation from said nameless expressions would be most helpful? On Tuesday, August 28, 2018, Steven D'Aprano wrote: > On Tue, Aug 28, 2018 at 07:46:02AM +0200, Marko Ristin-Kaufmann wrote: > > Hi, > > To clarify the benefits of the contracts, let me give you an example from > > our code base: > > > > @icontract.pre(lambda x: x >= 0) > > @icontract.pre(lambda y: y >= 0) > > @icontract.pre(lambda width: width >= 0) > > @icontract.pre(lambda height: height >= 0) > > @icontract.pre(lambda x, width, img: x + width <= > pqry.opencv.width_of(img)) > > @icontract.pre(lambda y, height, img: y + height <= > pqry.opencv.height_of(img)) > > @icontract.post(lambda self: (self.x, self.y) in self) > > @icontract.post(lambda self: (self.x + self.width - 1, self.y + > > self.height - 1) in self) > > @icontract.post(lambda self: (self.x + self.width, self.y + > > self.height) not in self) > > def __init__(self, img: np.ndarray, x: int, y: int, width: int, > > height: int) -> None: > > > Thanks for your example Marko. I think that is quite close to the > ugliest piece of Python code I've ever seen, and I don't mean that as a > criticism of you for writing it or the icontract library's design. > > We write code that our language allows us to write, not the code we want > to write. Python has not been designed for contracts, and it shows. > > I think this demonstrates a truth about programming languages: > > Aethestics matter. Syntax matters. > > Some features, no matter how useful and beneficial, have no hope at all > of getting widespread use if the syntax is awkward or the result ugly. I > think that contracts will be doomed to be a minor niche used only by > really keen proponents of the style so long as the best way to write a > contract is to use a sequence of decorator calls with lambdas. > > I'm going to re-write that in a pseudo-Eiffel like syntax: > > def __init__(self, img: np.ndarray, x: int, y: int, width: int, height: > int) -> None: > require: > x >= 0 > y >= 0 > width >= 0 > height >= 0 > x + width <= pqry.opencv.width_of(img) > y + height <= pqry.opencv.height_of(img) > > # possibly this should be an invariant, not a post-condition? > ensure: > (self.x, self.y) in self > (self.x + self.width - 1, self.y + self.height - 1) in self > (self.x + self.width, self.y + self.height) not in self > > # body of __init__ goes here... > > > This makes a huge difference to readability: > > - block structure to give visual shape to the code; > > - related code stays together (all the pre-conditions naturally go > into the require block, post-conditions in the ensure block, and > no chance of interleaving them > > @pre(...) > @post(...) > @pre(...) > > - no extraneous lambdas (they are pure noise); > > - no long sequence of decorators (more than one of each is pure noise); > > - possibility to write assertions which take more than one statement. > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Wed Aug 29 01:52:46 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Wed, 29 Aug 2018 17:52:46 +1200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> Message-ID: <5B8634AE.1000008@canterbury.ac.nz> Wes Turner wrote: > I'm going to re-write that in a pseudo-Eiffel like syntax: Maybe some magic could be done to make this work: def __init__(self, img: np.ndarray, x: int, y: int, width: int, height: int) -> None: def __require__(): x >= 0 y >= 0 width >= 0 height >= 0 x + width <= pqry.opencv.width_of(img) y + height <= pqry.opencv.height_of(img) def __ensure__(): (self.x, self.y) in self (self.x + self.width - 1, self.y + self.height - 1) in self (self.x + self.width, self.y + self.height) not in self # body of __init__ goes here... -- Greg From stephanh42 at gmail.com Wed Aug 29 01:58:39 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Wed, 29 Aug 2018 07:58:39 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B8634AE.1000008@canterbury.ac.nz> References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> <5B8634AE.1000008@canterbury.ac.nz> Message-ID: I Op wo 29 aug. 2018 07:53 schreef Greg Ewing : > Wes Turner wrote: > > I'm going to re-write that in a pseudo-Eiffel like syntax: > > Maybe some magic could be done to make this work: > > def __init__(self, img: np.ndarray, x: int, y: int, width: int, > height: int) -> None: > > def __require__(): > x >= 0 > y >= 0 > width >= 0 > height >= 0 > x + width <= pqry.opencv.width_of(img) > y + height <= pqry.opencv.height_of(img) > > def __ensure__(): > (self.x, self.y) in self > (self.x + self.width - 1, self.y + self.height - 1) in self > (self.x + self.width, self.y + self.height) not in self > > # body of __init__ goes here... > I have often wished we could get at the AST of a function object. Then we could inspect the AST and extract these magic functions. Stephan -- > Greg > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From contact at brice.xyz Wed Aug 29 02:48:26 2018 From: contact at brice.xyz (Brice Parent) Date: Wed, 29 Aug 2018 08:48:26 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B8634AE.1000008@canterbury.ac.nz> References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> <5B8634AE.1000008@canterbury.ac.nz> Message-ID: <5537359b-75af-ece3-f253-207d77da7041@brice.xyz> I've never used contracts, so excuse me if I didn't get how they would work, and what they should do. The last example is about pre-post conditions in a class constructor. But I imagine this is not the only case where one would want to define contracts, like probably: within methods that return something and to functions (and in both cases, we'd want to contractually state some of the return's specificities). Is the following function something someone used to work with contracts would write? def calculate(first: int, second: int) -> float: ??? def __require__(): ??????? first > second ??????? second > 0 ??????? # or first > second > 0 ? ??? def __ensure__(ret):? # we automatically pass the return of the function to this one ??????? ret > 1 ??? return first / second If so, having a reference to the function's output would probably be needed, as in the example above. Also, wouldn't someone who use contracts want the type hints he provided to be ensured without having to add requirements like `type(first) is int` or something? - Brice Le 29/08/2018 ? 07:52, Greg Ewing a ?crit?: > Wes Turner wrote: >> ??? I'm going to re-write that in a pseudo-Eiffel like syntax: > > Maybe some magic could be done to make this work: > > ???? def __init__(self, img: np.ndarray, x: int, y: int, width: int, > ???????????? height: int) -> None: > > ???????? def __require__(): > ???????????? x >= 0 > ???????????? y >= 0 > ???????????? width >= 0 > ???????????? height >= 0 > ???????????? x + width <= pqry.opencv.width_of(img) > ???????????? y + height <= pqry.opencv.height_of(img) > > ???????? def __ensure__(): > ???????????? (self.x, self.y) in self > ???????????? (self.x + self.width - 1, self.y + self.height - 1) in self > ???????????? (self.x + self.width, self.y + self.height) not in self > > ???????? # body of __init__ goes here... > From j.van.dorp at deonet.nl Wed Aug 29 03:23:02 2018 From: j.van.dorp at deonet.nl (Jacco van Dorp) Date: Wed, 29 Aug 2018 09:23:02 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180829015839.GL24160@ando.pearwood.info> References: <20180827103506.GE24160@ando.pearwood.info> <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> Message-ID: Op wo 29 aug. 2018 om 03:59 schreef Steven D'Aprano : > On Tue, Aug 28, 2018 at 07:46:02AM +0200, Marko Ristin-Kaufmann wrote: > > Hi, > > To clarify the benefits of the contracts, let me give you an example from > > our code base: > > > > @icontract.pre(lambda x: x >= 0) > > @icontract.pre(lambda y: y >= 0) > > @icontract.pre(lambda width: width >= 0) > > @icontract.pre(lambda height: height >= 0) > > @icontract.pre(lambda x, width, img: x + width <= > pqry.opencv.width_of(img)) > > @icontract.pre(lambda y, height, img: y + height <= > pqry.opencv.height_of(img)) > > @icontract.post(lambda self: (self.x, self.y) in self) > > @icontract.post(lambda self: (self.x + self.width - 1, self.y + > > self.height - 1) in self) > > @icontract.post(lambda self: (self.x + self.width, self.y + > > self.height) not in self) > > def __init__(self, img: np.ndarray, x: int, y: int, width: int, > > height: int) -> None: > > > Thanks for your example Marko. I think that is quite close to the > ugliest piece of Python code I've ever seen, and I don't mean that as a > criticism of you for writing it or the icontract library's design. > > What, really ? Well, it clearly shows you teach python and don't look much at code written by people who taught themselves. I taught myself, and the first .py file I created was over a 1000 lines, and contained the GUI in a 4-deep nested global dictionary, since I'd never seen a style guide at that point. (I got better) -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Wed Aug 29 03:28:59 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 29 Aug 2018 17:28:59 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B8634AE.1000008@canterbury.ac.nz> References: <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> <5B8634AE.1000008@canterbury.ac.nz> Message-ID: <20180829072858.GA27312@ando.pearwood.info> On Wed, Aug 29, 2018 at 05:52:46PM +1200, Greg Ewing wrote: > Wes Turner wrote: > > I'm going to re-write that in a pseudo-Eiffel like syntax: > > Maybe some magic could be done to make this work: > > def __init__(self, img: np.ndarray, x: int, y: int, width: int, > height: int) -> None: > > def __require__(): The problem with this idea is that methods and functions are not declarations, but executable code. This __require__ function doesn't exist except while the __init__ method is running. So it can't be called before the __init__, it can't be called *automatically* (you need to call it yourself, from inside the __init__), and it can't be inherited. Of course with sufficient compiler magic of course the compiler could special case these methods and do whatever we want, but that seems like it would be just as much work but much uglier than using dedicated syntax. -- Steve From steve at pearwood.info Wed Aug 29 07:51:57 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 29 Aug 2018 21:51:57 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180827125012.GF24160@ando.pearwood.info> <20180827135350.GH24160@ando.pearwood.info> <20180828000340.GI24160@ando.pearwood.info> <20180829015839.GL24160@ando.pearwood.info> Message-ID: <20180829115156.GB27312@ando.pearwood.info> On Wed, Aug 29, 2018 at 09:23:02AM +0200, Jacco van Dorp wrote: > Op wo 29 aug. 2018 om 03:59 schreef Steven D'Aprano : > > > On Tue, Aug 28, 2018 at 07:46:02AM +0200, Marko Ristin-Kaufmann wrote: > > > Hi, > > > To clarify the benefits of the contracts, let me give you an example from > > > our code base: [snip long sequence of @decorator(lambda) calls] > > Thanks for your example Marko. I think that is quite close to the > > ugliest piece of Python code I've ever seen, and I don't mean that as a > > criticism of you for writing it or the icontract library's design. > > > > > What, really ? I said *close* :-) > Well, it clearly shows you teach python and don't look much > at code written by people who taught themselves. I didn't mean to compare it to code written by beginners. I meant professional quality. And I didn't mean it was *bad* code. Python is a remarkable elegant and pretty language, but there are some things that aren't a good fit to the existing syntax. Contracts are one. We can't easily write code in a declarative style like Prolog: sibling(X, Y) :- parent_child(Z, X), parent_child(Z, Y) (X is a sibling of Y when there exists some Z who is a parent of X and the same Z is the parent of Y); we have to re-write it in a procedural style. Some programming styles aren't a natural fit to a given syntax. > I taught myself, and the > first .py file I created was over a 1000 lines, and contained the GUI in a > 4-deep nested global dictionary, since I'd never seen a style guide at that > point. (I got better) So far, nothing you describe is *necessarily* ugly or bad code. The std lib contains at least one file well over 1000 lines, and while it is complex code, its not ugly code by any means. And I couldn't judge the elegance of the dict unless I saw it and the alternatives :-) -- Steve From oscar.j.benjamin at gmail.com Wed Aug 29 08:15:46 2018 From: oscar.j.benjamin at gmail.com (Oscar Benjamin) Date: Wed, 29 Aug 2018 13:15:46 +0100 Subject: [Python-ideas] Python-ideas Digest, Vol 141, Issue 145 In-Reply-To: References: Message-ID: On Tue, 28 Aug 2018 at 08:12, Jacco van Dorp wrote: > > Op ma 27 aug. 2018 om 23:18 schreef James Lu : >> >> > As Matthew points out, you could use numpy.array. Or code your own >> > class, by providing __add__ and __iadd__ methods. >> >> I could, but I don't think that justifies not having this functionality in python >> standard. From the language experience perspective, numpy is often a >> pain to install on most systems. Numpy is easy to install: $ pip install numpy Should work on OSX, Windows and Linux. In all cases this should download a precompiled binary wheel. It used to be more difficult but improvements in packaging (wheels, manylinux etc) and the good work of the numpy folks have made this painless now. Scipy (on Windows) is a different story. -- Oscar From steve at pearwood.info Wed Aug 29 08:16:09 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 29 Aug 2018 22:16:09 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> Message-ID: <20180829121609.GC27312@ando.pearwood.info> I didn't want to embarass Ivan any further by seemingly picking on his opinion about contracts being always statically checked, but when I asked off-list I got told to reword and post it here. So here it is. Sorry Ivan if this makes you feel I'm picking on you, that isn't my intention. On Mon, Aug 27, 2018 at 12:25:44PM +0100, Jonathan Fine wrote: [..] > Based on the Eiffel docs, I find Ivan's opinion reasonable. He said it > was "one of the main points". The goal is to detect errors > immediately. Run-time assertion monitoring and static typing are two > means towards that end. Ivan said that static checking was a main point. Those Eiffel docs which you (Jonathon) quoted approvingly describe them as "run-time assertions". You describe them as "run-time assertions". I described them as "run-time assertions". So I'm having difficulty in understand what part of Ivan's opinion that they are compile-time static checks is "reasonable". If there's something I'm missing about Ivan's comment that you can see, I'd like to be enlightened. I don't see the relevance of the "two means towards that end" -- we have many means towards detecting bugs as early as possible: - correctness proofs - test-driven development - type checking - design by contract (and possibly more). If it was just a throw-away comment and I'm reading more into it than you intended, that's okay too, but I'd like to understand what you meant. > Our shared problem and goal is to have similar immediate detection of > errors in Python (when the development process requires that degree of > rigour). Well, yes, but what's that got to do with the question of whether contracts are checked statically or at runtime? -- Steve From steve at pearwood.info Wed Aug 29 08:24:29 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Wed, 29 Aug 2018 22:24:29 +1000 Subject: [Python-ideas] Python-ideas Digest, Vol 141, Issue 145 In-Reply-To: References: Message-ID: <20180829122429.GD27312@ando.pearwood.info> On Wed, Aug 29, 2018 at 01:15:46PM +0100, Oscar Benjamin wrote: > On Tue, 28 Aug 2018 at 08:12, Jacco van Dorp wrote: > > > > Op ma 27 aug. 2018 om 23:18 schreef James Lu : > >> > >> > As Matthew points out, you could use numpy.array. Or code your own > >> > class, by providing __add__ and __iadd__ methods. > >> > >> I could, but I don't think that justifies not having this functionality in python > >> standard. From the language experience perspective, numpy is often a > >> pain to install on most systems. > > Numpy is easy to install: > > $ pip install numpy [steve at ando ~]$ pip install numpy Collecting numpy /usr/local/lib/python3.5/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:315: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#snimissingwarning. SNIMissingWarning Could not fetch URL https://pypi.python.org/simple/numpy/: There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:645) - skipping Could not find a version that satisfies the requirement numpy (from versions: ) No matching distribution found for numpy I'm sure pip is great, but honestly I've never been able to get it to work reliably, ever, on four different machines using four different Linux distros. In any case, the answer "just use Numpy" isn't really relevant to the question about adding new syntax. -- Steve From p.f.moore at gmail.com Wed Aug 29 08:26:38 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Wed, 29 Aug 2018 13:26:38 +0100 Subject: [Python-ideas] Python-ideas Digest, Vol 141, Issue 145 In-Reply-To: References: Message-ID: On Wed, 29 Aug 2018 at 13:17, Oscar Benjamin wrote: > Scipy (on Windows) is a different story. There are Windows (and other platform) wheels for scipy 1.1.0 on PyPI, so that's easy too :-) Paul From p.f.moore at gmail.com Wed Aug 29 08:33:02 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Wed, 29 Aug 2018 13:33:02 +0100 Subject: [Python-ideas] Python-ideas Digest, Vol 141, Issue 145 In-Reply-To: <20180829122429.GD27312@ando.pearwood.info> References: <20180829122429.GD27312@ando.pearwood.info> Message-ID: On Wed, 29 Aug 2018 at 13:26, Steven D'Aprano wrote: > > [steve at ando ~]$ pip install numpy > Collecting numpy > /usr/local/lib/python3.5/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:315: > SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject > Name Indication) extension to TLS is not available on this platform. > This may cause the server to present an incorrect TLS certificate, which > can cause validation failures. For more information, see > https://urllib3.readthedocs.org/en/latest/security.html#snimissingwarning. > SNIMissingWarning > Could not fetch URL https://pypi.python.org/simple/numpy/: There was a > problem confirming the ssl certificate: [SSL: > TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:645) > - skipping > Could not find a version that satisfies the requirement numpy (from > versions: ) > No matching distribution found for numpy > > > I'm sure pip is great, but honestly I've never been able to get it to > work reliably, ever, on four different machines using four different > Linux distros. >From the "For more information" link above, that seems to be related to your SSL support. The link says it happens with Python older than 2.7.9, but you seem to be getting a Python 3.5 site-packages. Did you build Python yourself? Maybe you have an old version of openssl somewhere. I've not seen this sort of error come up commonly, so I suspect there's something particular to how you have your environment(s) set up. However... > In any case, the answer "just use Numpy" isn't really relevant to the > question about adding new syntax. Indeed. And nor is discussion about pip issues, so I'll leave it there. If you want help getting pip to work, I'd suggest raising an issue on the pip tracker. Paul. From jfine2358 at gmail.com Wed Aug 29 09:26:54 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Wed, 29 Aug 2018 14:26:54 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <20180829121609.GC27312@ando.pearwood.info> References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> Message-ID: This is about a difference of opinion regarding design by contract and static checking, that Steve D'Aprano has re-raised. Steve wrote that Ivan Levkivskyi's opinion was that: > contracts [are] always statically checked This is what Ivan wrote: > TBH, I think one of the main points of design by contract is that contracts > are verified statically. There's no 'always' or 'all' here. I read it to mean 'sometimes' or 'some'. And also, that static verification is a good thing. My message of support for Ivan quoted the Eiffel docs. > https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions > During development and testing, assertion monitoring should > be turned on at the highest possible level. Combined with > static typing and the immediate feedback of compilation techniques > [...] this permits the development process [...] > where errors are exterminated at birth. I then wrote: > Based on the Eiffel docs, I find Ivan's opinion reasonable. Steve wrote: > Ivan said that static checking was a main point. Those Eiffel docs which > you (Jonathon) quoted approvingly describe them as "run-time > assertions". I'm sorry, but I'm just not seeing that. Either in what I quoted, or elsewhere in the page. True, my quote is from a section titled "Run-time assertion monitoring", but the context to me makes it clear that in Eiffel static typing IS NOT regarded as a run-time assertion. By the way, Steve wrote > when I asked off-list I got told to reword and post it here. I don't think that's quite right. What I said off-list to Steve was > If you post [...] to python-ideas, I'd be happy to respond there. It was my intention that it was up to Steve, whether or not to re-raise the issue. And now I'm doing my part of the bargain, by responding happily. I'm now happy to let this particular topic rest. -- Jonathan From steve at pearwood.info Wed Aug 29 12:30:32 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 30 Aug 2018 02:30:32 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> Message-ID: <20180829163032.GE27312@ando.pearwood.info> On Wed, Aug 29, 2018 at 02:26:54PM +0100, Jonathan Fine wrote: > This is about a difference of opinion regarding design by contract and > static checking, that Steve D'Aprano has re-raised. Steve wrote that > Ivan Levkivskyi's opinion was that: > > > contracts [are] always statically checked > > This is what Ivan wrote: > > > TBH, I think one of the main points of design by contract is that contracts > > are verified statically. > > There's no 'always' or 'all' here. I read it to mean 'sometimes' or > 'some'. And also, that static verification is a good thing. Fair enough, I should not have added "always" in my description. But you probably shouldn't have skipped the part I wrote earlier: "Contracts may be verified statically if the compiler is able to do so, but they are considered runtime checks. Static checks are an optimization." In context, you quoted me disagreeing with the "static" claim, but trimmed out my qualification that contracts may sometimes be statically verified when possible. [...] > > Ivan said that static checking was a main point. Those Eiffel docs which > > you (Jonathon) quoted approvingly describe them as "run-time > > assertions". > > I'm sorry, but I'm just not seeing that. Either in what I quoted, or > elsewhere in the page. True, my quote is from a section titled > "Run-time assertion monitoring", but the context to me makes it clear > that in Eiffel static typing IS NOT regarded as a run-time assertion. Of course it isn't. By definition, static typing is done *statically*, at compile-time, not run-time. That has not been questioned and nobody has asserted that static typing is done at run-time. We're discussing whether *contracts* are checked at run-time. Because contracts are (in general) run-time assertions, they are a good fit for Python's execution model -- or at least they would be if we can find a good way to apply contracts to methods and classes. If they were static, they would be a bad fit and would probably need to be handled by a separate static checker, like MyPy does for static type checks. -- Steve From greg.ewing at canterbury.ac.nz Wed Aug 29 16:41:02 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 30 Aug 2018 08:41:02 +1200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> Message-ID: <5B8704DE.20808@canterbury.ac.nz> Jonathan Fine wrote: > > My message of support for Ivan quoted the Eiffel docs. > >>https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions > >>During development and testing, assertion monitoring should >>be turned on at the highest possible level. Combined with >>static typing and the immediate feedback of compilation techniques >>[...] this permits the development process [...] >>where errors are exterminated at birth. I think you're misinterpreting the Eiffel docs here. It's saying that contracts *together* with static typing help to catch a lot of errors early in the development process. It's not saying that contracts are verified statically, or that all the errors thus caught are caught at compile time. > the context to me makes it clear > that in Eiffel static typing IS NOT regarded as a run-time assertion. That's true, but static typing and contracts are *different things* in Eiffel. Static types are checked at compile time, contracts are checked at run time. -- Greg From marko.ristin at gmail.com Wed Aug 29 18:07:04 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Thu, 30 Aug 2018 00:07:04 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B8704DE.20808@canterbury.ac.nz> References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> <5B8704DE.20808@canterbury.ac.nz> Message-ID: Hi, I think we got entangled in a discussion about whether design-by-contract is useful or not. IMO, the personal experience ("I never used/needed this feature") is quite an inappropriate rule whether something needs to be introduced into the language or not. There seems to be evidence that design-by-contract is useful. Let me cite Bertrand Meyer from his article "Why not program right?" that I already mentioned before: > We are back then to the core question. These techniques are simple, > demonstrably useful, practical, validated by years of use, explained in > professional books (e.g. [6]), introductory programming textbooks (e.g. > [7]), EdX MOOCs (e.g. [8]), YouTube videos, online tutorials at eiffel.org, > and hundreds of articles cited thousands of times. > 6. Bertrand Meyer, Object-Oriented Software Construction, 2nd edition, > Prentice Hall, 1997. > > 7. Bertrand Meyer, Touch of Class: Learning to Program Well Using > Objects and Contracts, Springer, 2009, see touch.ethz.ch and Amazon page > > . > > 8. MOOCs (online courses) on EdX : "Computer: Art, Magic, Science", Part > 1 > and Part 2 > . > (Go to "archived versions" to follow the courses.) > Is there any logical or empirical objection that the design-by-contract is not useful and hence does not merit to be introduced into the core language? There is little point in writing a PEP and fleshing out the details if the community will reject it on grounds that design-by-contract by itself is meaningless. So I'd suggest we clarify this first before we move on. @David Mertz: > Nonetheless, I'll say that it's really not hard to get a decorator to > cooperate with inheritance if you want that. If you decorate a parent class > you can simply attach the collection of invariants to the class as > notations, along with whatever actual guards the decorator enforces. An > inheriting child (also decorated) can just look up those notations and > apply them to the child. > > I.e. the first thing a decorator can do is lookup the invariants attached > to the parent (if any) and apply them to the child (if this behavior is > enabled). Easy peasy. > Could you please elaborate a bit? I don't see how the annotations would make the contracts invoked on inheritance. Consider this simple case: class A: @icontract.pre(lambda x: x > 0) def some_method(self, x: int)->None: pass class B(A): # Precondition should be inherited here. def some_method(self, x: int) -> None: pass You would still need to somehow decorate manually the overridden methods even though you would not specify any new contracts, right? Is there a mechanism in Python that I am not aware of that would allow us to accomplish that? On Wed, 29 Aug 2018 at 22:41, Greg Ewing wrote: > Jonathan Fine wrote: > > > > My message of support for Ivan quoted the Eiffel docs. > > > >> > https://www.eiffel.org/doc/eiffel/ET-_Design_by_Contract_%28tm%29%2C_Assertions_and_Exceptions > > > >>During development and testing, assertion monitoring should > >>be turned on at the highest possible level. Combined with > >>static typing and the immediate feedback of compilation techniques > >>[...] this permits the development process [...] > >>where errors are exterminated at birth. > > I think you're misinterpreting the Eiffel docs here. It's saying > that contracts *together* with static typing help to catch a lot > of errors early in the development process. It's not saying that > contracts are verified statically, or that all the errors thus > caught are caught at compile time. > > > the context to me makes it clear > > that in Eiffel static typing IS NOT regarded as a run-time assertion. > > That's true, but static typing and contracts are *different things* > in Eiffel. Static types are checked at compile time, contracts > are checked at run time. > > -- > Greg > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ericfahlgren at gmail.com Wed Aug 29 18:39:54 2018 From: ericfahlgren at gmail.com (Eric Fahlgren) Date: Wed, 29 Aug 2018 15:39:54 -0700 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> <5B8704DE.20808@canterbury.ac.nz> Message-ID: On Wed, Aug 29, 2018 at 3:07 PM Marko Ristin-Kaufmann < marko.ristin at gmail.com> wrote: > Could you please elaborate a bit? I don't see how the annotations would > make the contracts invoked on inheritance. Consider this simple case: > > class A: > @icontract.pre(lambda x: x > 0) > def some_method(self, x: int)->None: > pass > > class B(A): > # Precondition should be inherited here. > def some_method(self, x: int) -> None: > pass > > You would still need to somehow decorate manually the overridden methods > even though you would not specify any new contracts, right? Is there a > mechanism in Python that I am not aware of that would allow us to > accomplish that? > A metaclass does this pretty easily. I have a thing I wrote years ago called MIS (Multi-Inheritance Safety) that is used to ensure you don't do anything stupid in our physics-modeling database. The database is a collection of ~200 Python classes/mixins all deriving madly from each other to get various behaviors (Has mass? You'll need this. Has moments? You'll need this. Has physical extent, i.e., can be seen? You'll need these...). Anyhow, the basemost class has the metaclass, which traverses all the methods in the subclasses and makes sure you don't have methods with the same name in two distinct superclass trees and such things. It also forces you to be explicit when you overload a method from a base class (among other things, but this one is easy to illustrate). class MIS(type): def __init__(cls, name, bases, namespace): mro = cls.mro()[1:-1] # All the stuff between new class and 'object' for method_name, method in namespace.items(): if isinstance(method, executable_types): if not getattr(method, '_its_ok', False): # Make sure it's not in any baser class. # Could easily check for decorated pre/post properties and copy them... def override(func): # Mark the function as a valid override... func._its_ok = True return func class Base(metaclass=MIS): def something(self): pass class Derived(Base): @override # Signal that this is ok, otherwise we get an error. def something(self): ... -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Wed Aug 29 19:10:04 2018 From: mertz at gnosis.cx (David Mertz) Date: Wed, 29 Aug 2018 19:10:04 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> <5B8704DE.20808@canterbury.ac.nz> Message-ID: The technique Eric suggests is probably better than what I had in mind. But I was thinking you could have an "inherit" decorator for methods (or for a class as a whole). It's easy enough for a decorator to attach a `.__contracts__` attribute to either the class or the individual methods. Then the decorator(s) in the child can simply look through the `.__mro__` to find any such parent contracts. E.g.: class B(A): @inherit_invariants def some_method(self, x: int) -> None: pass @precondition(lambda x: x=42, inherit_parent=True) def other_method(self, x: int) -> float: return 42/5 I'm not writing a library to do this, so you can tweak the API to be different than my example. But this is already well possible. On the broader idea: Is there any logical or empirical objection that the design-by-contract is not useful and hence does not merit to be introduced into the core language? There is little point in writing a PEP and fleshing out the details if the community will reject it on grounds that design-by-contract by itself is meaningless. Lots of people have explained this relative to lots of ideas, probably mostly better than I will. Adding a new feature, even if it is *technically* backwards compatible, has HUGE costs. All the documentation?the books, articles, blog posts, videos, webinars, tutorials, etc.?about Python has to be updated. We get a divide between "code that will work in Python 3.9" versus what will run in 3.7. The cognitive burden of learning Python is increased for everyone in the world (millions of people) because even if they do not use a feature they will encounter code that does. There is another section of code in the implementation(s) of Python that can potentially have bugs and needs to be maintained by someone. Obviously, design-by-contract is not *meaningless*! It's a specific feature that is relatively well defined as a concept (and precisely defined in regard to Eiffel specifically; but we might not implement those *exact* semantics). It's also a feature that no languages in particularly widespread use have decided to implement at the language level. I've chatted with Meyer; he's definitely very smart and definitely strongly opinionated, but I also think he's wrong about the overall importance of this feature versus lots of others. In my mind, this feature doesn't come close to meeting the burden of those high costs listed above (and others I did not mention). But I don't have any say in what the core developers will do, beyond in that they might be influenced by my opinion here. Yours, David... On Wed, Aug 29, 2018 at 6:41 PM Eric Fahlgren wrote: > On Wed, Aug 29, 2018 at 3:07 PM Marko Ristin-Kaufmann < > marko.ristin at gmail.com> wrote: > >> Could you please elaborate a bit? I don't see how the annotations would >> make the contracts invoked on inheritance. Consider this simple case: >> >> class A: >> @icontract.pre(lambda x: x > 0) >> def some_method(self, x: int)->None: >> pass >> >> class B(A): >> # Precondition should be inherited here. >> def some_method(self, x: int) -> None: >> pass >> >> You would still need to somehow decorate manually the overridden methods >> even though you would not specify any new contracts, right? Is there a >> mechanism in Python that I am not aware of that would allow us to >> accomplish that? >> > > A metaclass does this pretty easily. I have a thing I wrote years ago > called MIS (Multi-Inheritance Safety) that is used to ensure you don't do > anything stupid in our physics-modeling database. The database is a > collection of ~200 Python classes/mixins all deriving madly from each other > to get various behaviors (Has mass? You'll need this. Has moments? You'll > need this. Has physical extent, i.e., can be seen? You'll need these...). > > Anyhow, the basemost class has the metaclass, which traverses all the > methods in the subclasses and makes sure you don't have methods with the > same name in two distinct superclass trees and such things. It also forces > you to be explicit when you overload a method from a base class (among > other things, but this one is easy to illustrate). > > class MIS(type): > def __init__(cls, name, bases, namespace): > mro = cls.mro()[1:-1] # All the stuff between new class and > 'object' > for method_name, method in namespace.items(): > if isinstance(method, executable_types): > if not getattr(method, '_its_ok', False): > # Make sure it's not in any baser class. > # Could easily check for decorated pre/post properties and > copy them... > > def override(func): > # Mark the function as a valid override... > func._its_ok = True > return func > > class Base(metaclass=MIS): > def something(self): > pass > > class Derived(Base): > @override # Signal that this is ok, otherwise we get an error. > def something(self): ... > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. -------------- next part -------------- An HTML attachment was scrubbed... URL: From levkivskyi at gmail.com Wed Aug 29 19:12:41 2018 From: levkivskyi at gmail.com (Ivan Levkivskyi) Date: Thu, 30 Aug 2018 00:12:41 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> Message-ID: replying to the list now... On Thu, 30 Aug 2018 at 00:11, Ivan Levkivskyi wrote: > On Wed, 29 Aug 2018 at 13:18, Steven D'Aprano wrote: > >> I didn't want to embarass Ivan any further by seemingly picking on his >> opinion about contracts being always statically checked, but when I >> asked off-list I got told to reword and post it here. So here it is. >> >> Sorry Ivan if this makes you feel I'm picking on you, that isn't my >> intention. >> > > NP, the discussion just shift more towards terminology etc. which is less > interesting TBH. > > -- > Ivan > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric at trueblade.com Wed Aug 29 19:40:32 2018 From: eric at trueblade.com (Eric V. Smith) Date: Wed, 29 Aug 2018 19:40:32 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> <5B8704DE.20808@canterbury.ac.nz> Message-ID: <274ce2cb-251e-2b79-6209-b8deb72b10dc@trueblade.com> On 8/29/2018 6:39 PM, Eric Fahlgren wrote: > On Wed, Aug 29, 2018 at 3:07 PM Marko Ristin-Kaufmann > > wrote: > > Could you please elaborate a bit? I don't see how the annotations > would make the contracts invoked on inheritance. Consider this > simple case: > > class A: > @icontract.pre(lambda x: x > 0) > def some_method(self, x: int)->None: > pass > > class B(A): > # Precondition should be inherited here. > def some_method(self, x: int) -> None: > pass > > You would still need to somehow decorate manually the overridden > methods even though you would not specify any new contracts, right? > Is there a mechanism in Python that I am not aware of that would > allow us to accomplish that? > > > A metaclass does this pretty easily.? I have a thing I wrote years ago > called MIS (Multi-Inheritance Safety) that is used to ensure you don't > do anything stupid in our physics-modeling database.? The database is a > collection of ~200 Python classes/mixins all deriving madly from each > other to get various behaviors (Has mass? You'll need this.? Has > moments?? You'll need this.? Has physical extent, i.e., can be seen? > You'll need these...). I think a metaclass is a non-starter. If one were used, it would preclude using contracts in any case where a metaclass were already used, or where one was needed in the future. I'm sure people will disagree with me on this. But, I think a more productive line of thinking is: what could be added to the language that would let contracts be implementable, and could also be used for other things, too? Sort of like how PEP 487 adds customizability that has wide applicability. Eric From hugo.fisher at gmail.com Wed Aug 29 19:53:02 2018 From: hugo.fisher at gmail.com (Hugh Fisher) Date: Thu, 30 Aug 2018 09:53:02 +1000 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: > Date: Thu, 30 Aug 2018 00:07:04 +0200 > From: Marko Ristin-Kaufmann ... > I think we got entangled in a discussion about whether design-by-contract > is useful or not. IMO, the personal experience ("I never used/needed this > feature") is quite an inappropriate rule whether something needs to be > introduced into the language or not. > > There seems to be evidence that design-by-contract is useful. Let me cite > Bertrand Meyer from his article "Why not program right?" that I already > mentioned before: I don't think that being useful by itself should be enough. I think new features should also be "Pythonic" and I don't see design by contract notation as a good fit. For example, C has the useful & operator which lets you pass &foo as a pointer/array argument despite foo being a scalar, so assignment to bar[0] in the called function actually sets the value of foo. It might be possible to create some kind of aliasing operator for Python so that two or more variables were bound to the same location, but would we want it? No, because Python is not intended for that style of programming. For another example, GPU shading languages have the special keywords uniform and varying for distinguishing definitions that won't change across parallel invocations and definitions that will. Demonstrably very useful in computer games and supercomputer number crunching, so why doesn't Python have those keywords? Because it's not designed to be used for such. For design by contract, as others have noted Python assert statements work fine for simple preconditions and postconditions. I don't see any significant difference in readability between existing def foo(x, y): assert(x > 0) # Do stuff assert(x == y) and new style def foo(x, y): require: x > 0 # Do stuff ensure: x == y Yes there's more to design by contract than simple assertions, but it's not just adding syntax. Meyer often uses the special "old" construct in his post condition examples, a trivial example being ensure count = old.count + 1 How do we do that in Python? And another part of design by contract (at least according to Meyer) is that it's not enough to just raise an exception, but there must be a guarantee that it is handled and the post conditions and/or invariants restored. So there's more syntax for "rescue" and "retry" If you want to do simple pre and post conditions, Python already has assert. If you want to go full design by contract, there's no law saying that Python is the only programming language allowed. Instead of trying to graft new and IMHO alien concepts onto Python, what's wrong with Eiffel? -- cheers, Hugh Fisher From oono0114 at gmail.com Wed Aug 29 21:27:33 2018 From: oono0114 at gmail.com (=?UTF-8?B?5aSn6YeO6ZqG5byY?=) Date: Thu, 30 Aug 2018 10:27:33 +0900 Subject: [Python-ideas] zipfile encryption function Message-ID: Dear all, I would like to use zipfile encryption as python standard library. https://github.com/python/cpython/blob/master/Lib/zipfile.py Below document says "currently" cannot. https://github.com/python/cpython/blob/master/Doc/library/zipfile.rst "but it currently cannot create an encrypted file." Current pythonians like me have to use 3rd party like below, but I believe it is worth to include. https://pypi.org/project/pyminizip/ https://github.com/wllm-rbnt/py-zipcrypt please forgive me if someone have already suggested before. Thanks and Regards, ------------------ Takahiro Ono -------------- next part -------------- An HTML attachment was scrubbed... URL: From ethan at stoneleaf.us Wed Aug 29 23:00:46 2018 From: ethan at stoneleaf.us (Ethan Furman) Date: Wed, 29 Aug 2018 20:00:46 -0700 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: Message-ID: <5B875DDE.2030308@stoneleaf.us> On 08/29/2018 04:53 PM, Hugh Fisher wrote: > From: Marko Ristin-Kaufmann: >> There seems to be evidence that design-by-contract is useful. Let me cite >> Bertrand Meyer from his article "Why not program right?" that I already >> mentioned before: > > I don't think that being useful by itself should be enough. I think new features > should also be "Pythonic" and I don't see design by contract notation as a > good fit. I don't see type annotation notation as a good fit, either, and yet we have it. Seems to me that DbC would be just as useful as type annotations (and I find D'Aprano's example syntax very readable). > For design by contract, as others have noted Python assert statements > work fine for simple preconditions and postconditions. And print statements work fine for simple debugging. New features are not added for the simple cases, but the complex, or non-obviously correct, or the very useful cases. > Yes there's more to design by contract than simple assertions, but it's not > just adding syntax. Meyer often uses the special "old" construct in his post > condition examples, a trivial example being > > ensure count = old.count + 1 I can see where that could get expensive quickly. > How do we do that in Python? And another part of design by contract (at > least according to Meyer) is that it's not enough to just raise an exception, > but there must be a guarantee that it is handled and the post conditions > and/or invariants restored. Well, we don't have to have exactly the same kind of DbC as Eiffel does. -- ~Ethan~ From mistersheik at gmail.com Thu Aug 30 00:39:05 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Wed, 29 Aug 2018 21:39:05 -0700 (PDT) Subject: [Python-ideas] Fix some special cases in Fractions? Message-ID: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Would there be any problem with changing: In [4]: Fraction(1, 1) ** Fraction(2, 3) Out[4]: 1.0 In [5]: Fraction(-1, 1) ** Fraction(2, 3) Out[5]: (-0.4999999999999998+0.8660254037844387j) In [6]: Fraction(0, 1) ** Fraction(2, 3) Out[6]: 0.0 I'd like these to be Fraction(1), Fraction(1), and Fraction(0). -------------- next part -------------- An HTML attachment was scrubbed... URL: From J.Demeyer at UGent.be Thu Aug 30 01:55:26 2018 From: J.Demeyer at UGent.be (Jeroen Demeyer) Date: Thu, 30 Aug 2018 07:55:26 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> Message-ID: <5B8786CE.4070604@UGent.be> On 2018-08-30 06:39, Neil Girdhar wrote: > I'd like these to be Fraction(1), Fraction(1), and Fraction(0). Why? I cannot think of any natural use case why you would want Fractions for a few special cases on an operation which returns non-Fractions generically. I consider it a feature to know in advance the type of the output of an operation, given the types of the input. Having an unexpected type suddenly show up because you happen to hit a special case is a recipe for bugs. Jeroen. From greg.ewing at canterbury.ac.nz Thu Aug 30 02:08:03 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 30 Aug 2018 18:08:03 +1200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B8786CE.4070604@UGent.be> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> Message-ID: <5B8789C3.6020803@canterbury.ac.nz> Jeroen Demeyer wrote: > On 2018-08-30 06:39, Neil Girdhar wrote: > >> I'd like these to be Fraction(1), Fraction(1), and Fraction(0). > > Why? I cannot think of any natural use case why you would want Fractions > for a few special cases on an operation which returns non-Fractions > generically. Also, Fraction(1) for the second case would be flat-out wrong. -- Greg From jcgoble3 at gmail.com Thu Aug 30 02:30:48 2018 From: jcgoble3 at gmail.com (Jonathan Goble) Date: Thu, 30 Aug 2018 02:30:48 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B8789C3.6020803@canterbury.ac.nz> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018, 2:08 AM Greg Ewing wrote: > Also, Fraction(1) for the second case would be flat-out wrong. > How? Raising something to the 2/3 power means squaring it and then taking the cube root of it. -1 squared is 1, and the cube root of 1 is 1. Or am I having a 2:30am brain fart? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Thu Aug 30 02:53:52 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 02:53:52 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B8789C3.6020803@canterbury.ac.nz> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 2:09 AM Greg Ewing wrote: > Jeroen Demeyer wrote: > > On 2018-08-30 06:39, Neil Girdhar wrote: > > > >> I'd like these to be Fraction(1), Fraction(1), and Fraction(0). > > > > Why? I cannot think of any natural use case why you would want Fractions > > for a few special cases on an operation which returns non-Fractions > > generically. > > Also, Fraction(1) for the second case would be flat-out wrong. > No, it's not "wrong". 1 is one of the cube roots of 1. It's consistent with 1 ** (2/3) == 1. -- > Greg > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/aZIHpPhe0mw/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Thu Aug 30 02:54:16 2018 From: rosuav at gmail.com (Chris Angelico) Date: Thu, 30 Aug 2018 16:54:16 +1000 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 4:30 PM, Jonathan Goble wrote: > On Thu, Aug 30, 2018, 2:08 AM Greg Ewing > wrote: >> >> Also, Fraction(1) for the second case would be flat-out wrong. > > > How? Raising something to the 2/3 power means squaring it and then taking > the cube root of it. -1 squared is 1, and the cube root of 1 is 1. Or am I > having a 2:30am brain fart? > For positive numbers, I believe you're correct. For negative numbers, no. >>> (-2)**(2/3) (-0.7937005259840993+1.3747296369986026j) >>> _**(3/2) (-1.9999999999999993+2.4492935982947054e-16j) >>> ((-2)**2)**(1/3) 1.5874010519681994 >>> _**(3/2) 1.9999999999999998 Rounding error aside, raising -2 to 2/3 power and then raising the result to 3/2 power gives back -2, as it should. Doing it in two steps loses the negation, and then (again, within rounding error) the end result is positive two. ChrisA From greg.ewing at canterbury.ac.nz Thu Aug 30 03:07:51 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 30 Aug 2018 19:07:51 +1200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> Message-ID: <5B8797C7.2080303@canterbury.ac.nz> Jonathan Goble wrote: > How? Raising something to the 2/3 power means squaring it and then > taking the cube root of it. On reflection, "wrong" is not quite accurate. A better word might be "surprising". (-1) ** (2/3) == 1 would imply that 1 ** (3/2) == -1. I suppose that could be considered true if you take the negative solution of the square root, but it seems a bit strange, and it's not what Python gives you for the result of 1 ** (3/2). If you want a solution that round-trips, you need complex numbers. That's what Python does when you use floats. Making Fractions do something different would make it inconsistent with floats. My calculator (which only does real floats) reports an error when trying to evaluate (-1) ** (2/3). -- Greg From mistersheik at gmail.com Thu Aug 30 03:37:10 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 03:37:10 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B8797C7.2080303@canterbury.ac.nz> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: There are a lot of misunderstandings in this thread. It's probably best to start by reading up on the roots of unity ( https://en.wikipedia.org/wiki/Root_of_unity). The key ideas are that a real number has two complex square roots, three complex cube roots, and so on. Normally, in Python, we return the principal square root ( http://mathworld.wolfram.com/PrincipalSquareRoot.html). We would do the same for the cube root I imagine if we had a cube root function Let's call that the principal cube root, which is always real for a real-valued input. --- > For positive numbers, I believe you're correct. For negative numbers, no. Actually, Jonathan is right. >>> (-2)**(2/3) (-0.7937005259840993+1.3747296369986026j) This is just giving you one of the other two cube roots. > Rounding error aside, raising -2 to 2/3 power and then raising the result to 3/2 power gives back -2, as it should. There is no way to guarantee that "it should do this". A fractional power is not a function, and so it has no inverse function. > Doing it in two steps loses the negation, and then (again, within rounding error) the end result is positive two. I think you would see your mistake if you applied this logic to -1 ** 2 ** (1/2). On Thu, Aug 30, 2018 at 3:08 AM Greg Ewing wrote: > Jonathan Goble wrote: > > How? Raising something to the 2/3 power means squaring it and then > > taking the cube root of it. > > On reflection, "wrong" is not quite accurate. A better > word might be "surprising". > > (-1) ** (2/3) == 1 would imply that 1 ** (3/2) == -1. I suppose that could be considered true if you take the > negative solution of the square root, but it seems a > bit strange, and it's not what Python gives you for > the result of 1 ** (3/2). > Python gives you the principle root when you do 1 ** (3/2), which is exactly what I'm proposing for Fraction. > If you want a solution that round-trips, you need > complex numbers. There is no solution that round trips since in general fractional powers are not functions. The case in which you can always round trip is when you are taking a power c ** (a/b) where a is odd, and either c is positive or b is odd. Then, the result to the power of (b/a) gives you c. That's what Python does when you use > floats. Making Fractions do something different would > make it inconsistent with floats. > Actually, my cases are all examples of the principal roots and are consistent with floats. > > My calculator (which only does real floats) reports an > error when trying to evaluate (-1) ** (2/3). > Yes, which is what Python does with reals. The difference is the the Fraction type has exact values, and it knows that the unique answer in the field of Fraction objects is 1. > > -- > Greg > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/aZIHpPhe0mw/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mal at egenix.com Thu Aug 30 03:42:17 2018 From: mal at egenix.com (M.-A. Lemburg) Date: Thu, 30 Aug 2018 09:42:17 +0200 Subject: [Python-ideas] zipfile encryption function In-Reply-To: References: Message-ID: On 30.08.2018 03:27, ???? wrote: > Dear all, > > I would like to use zipfile encryption as python standard library. > https://github.com/python/cpython/blob/master/Lib/zipfile.py > > Below document says "currently" cannot. > https://github.com/python/cpython/blob/master/Doc/library/zipfile.rst > "but it currently cannot create an encrypted file." > > Current pythonians like me have to use 3rd party like below, but I > believe it is worth to include. > https://pypi.org/project/pyminizip/ > https://github.com/wllm-rbnt/py-zipcrypt > > please forgive me if someone have already suggested before. I think adding zipfile support for the now common per file encryption logic using AES would be useful to have in the stdlib zipfile module. It's used a lot where people do not want to go for the full infrastructure which GPG entails. Could you provide a PR and upload that to bugs.python.org ? Some references: https://en.wikipedia.org/wiki/Zip_%28file_format%29#Encryption https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT Thanks, -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Aug 30 2018) >>> Python Projects, Coaching and Consulting ... http://www.egenix.com/ >>> Python Database Interfaces ... http://products.egenix.com/ >>> Plone/Zope Database Interfaces ... http://zope.egenix.com/ ________________________________________________________________________ ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ http://www.malemburg.com/ From marko.ristin at gmail.com Thu Aug 30 03:42:53 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Thu, 30 Aug 2018 09:42:53 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B875DDE.2030308@stoneleaf.us> References: <5B875DDE.2030308@stoneleaf.us> Message-ID: Hi, @David Mertz, Eric Fahlgren re inheritance: thank you very much for your suggestions. I will try to see how inheritance can be implemented with metaclasses and annotations and put it into icontract library. @David Mertz re costs: > Adding a new feature, even if it is *technically* backwards compatible, > has HUGE costs. > [...] > It's a specific feature that is relatively well defined as a concept (and > precisely defined in regard to Eiffel specifically; but we might not > implement those *exact* semantics). It's also a feature that no languages > in particularly widespread use have decided to implement at the language > level. I've chatted with Meyer; he's definitely very smart and definitely > strongly opinionated, but *I also think he's wrong about the overall > importance of this feature* *versus lots of others* [emphasis Marko]. > > In my mind, this feature doesn't come close to meeting the burden of those > high costs listed above (and others I did not mention). But I don't have > any say in what the core developers will do, beyond in that they might be > influenced by my opinion here. > I am also aware of the costs; when I wrote "useful", I actually meant "useful and meaningful to implement given the costs that you mention. Please apologize for my inexact wording (I write these emails in the evening after work). Related to the text I emphasized, would you mind to explain a bit more in-depth which features you have in mind? I see contracts formally written out and automatically verified as a completely indispensable tool in large projects with multiple people involved. As I already outlined, writing them in documentation leads to code rot. Not writing assumptions about the data structures at all causes, in my opinion, tons of problems and very, very slow development since each programmer working on the legacy code needs to figure these assumptions over and over again. While testing is not substitute for thinking, I possible don't see how you can add/refactor code in big projects and consider all the interactions between the components. Unit testing can get you only as far, since you always test only for a concrete case. Contracts get you much further, not to mention the automatically generated tests which I can't conceive practical without some sort of contracts in the code. I have also to admit that I was schooled with contracts so I might have a distorted view on the matter (Bertrand Meyer taught Introduction to Programming and all the software engineering university classes; I also worked as a teaching assistant with him for the Software Architecture class). I will try to see how far we can implement contracts as a library. Personally, I would prefer dedicated syntax and I do believe that dedicated syntax merits the costs since these constructs would lead to much better programming in the Python world. If we can't get new syntax, having contracts in the standard library would do it for me as a compromise -- it would standardize, even if in ugly way (as Steven D'Aprano pointed out), how we deal with contracts in Python and would allow for integration into IDEs and static analysis tools. On Thu, 30 Aug 2018 at 05:01, Ethan Furman wrote: > On 08/29/2018 04:53 PM, Hugh Fisher wrote: > > From: Marko Ristin-Kaufmann: > > >> There seems to be evidence that design-by-contract is useful. Let me > cite > >> Bertrand Meyer from his article "Why not program right?" that I already > >> mentioned before: > > > > I don't think that being useful by itself should be enough. I think new > features > > should also be "Pythonic" and I don't see design by contract notation as > a > > good fit. > > I don't see type annotation notation as a good fit, either, and yet we > have it. Seems to me that DbC would be just as > useful as type annotations (and I find D'Aprano's example syntax very > readable). > > > For design by contract, as others have noted Python assert statements > > work fine for simple preconditions and postconditions. > > And print statements work fine for simple debugging. New features are not > added for the simple cases, but the complex, > or non-obviously correct, or the very useful cases. > > > Yes there's more to design by contract than simple assertions, but it's > not > > just adding syntax. Meyer often uses the special "old" construct in his > post > > condition examples, a trivial example being > > > > ensure count = old.count + 1 > > I can see where that could get expensive quickly. > > > How do we do that in Python? And another part of design by contract (at > > least according to Meyer) is that it's not enough to just raise an > exception, > > but there must be a guarantee that it is handled and the post conditions > > and/or invariants restored. > > Well, we don't have to have exactly the same kind of DbC as Eiffel does. > > -- > ~Ethan~ > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Thu Aug 30 04:01:10 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 09:01:10 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: On Thu, 30 Aug 2018 at 08:38, Neil Girdhar wrote: > > There are a lot of misunderstandings in this thread. It's probably best to start by reading up on the roots of unity (https://en.wikipedia.org/wiki/Root_of_unity). The key ideas are that a real number has two complex square roots, three complex cube roots, and so on. The complexities of fractional powers aside, the type of a result should not depend on the values of the arguments. So I'm -1 on this change for that reason alone. Questions of which root it's appropriate to take are separate, and IMO the sensible option is to follow the behaviour of float, for which we have >>> (-1)**(2/3) (-0.4999999999999998+0.8660254037844387j) >>> (1)**(2/3) 1.0 >>> (0)**(2/3) 0.0 So current behaviour of Fraction is correct on that basis, IMO. Paul From p.f.moore at gmail.com Thu Aug 30 04:25:35 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 09:25:35 +0100 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <20180821102035.GB24160@ando.pearwood.info> <20180827103506.GE24160@ando.pearwood.info> <20180829121609.GC27312@ando.pearwood.info> <5B8704DE.20808@canterbury.ac.nz> Message-ID: On Wed, 29 Aug 2018 at 23:08, Marko Ristin-Kaufmann wrote: > > Hi, > I think we got entangled in a discussion about whether design-by-contract is useful or not. IMO, the personal experience ("I never used/needed this feature") is quite an inappropriate rule whether something needs to be introduced into the language or not. It's not a key factor, but it is indicative, in the sense that if no-one has ever needed the feature *in Python*, then it's possibly not a good fit for how the language is used in real life. That doesn't exclude the possibility of a new feature offering a new and not previously considered technique, but if that's the assertion, then it's up to the individual proposing the new feature to persuade the community that there's a real and significant benefit. > Is there any logical or empirical objection that the design-by-contract is not useful and hence does not merit to be introduced into the core language? There is little point in writing a PEP and fleshing out the details if the community will reject it on grounds that design-by-contract by itself is meaningless. So I'd suggest we clarify this first before we move on. "It could be useful" is nowhere near a strong enough reason for changing the language. Even "it is demonstrably useful in other languages" would have a hard time. What you need to demonstrate is that it would be useful *in Python code*. A good way of doing that is by reviewing a significant body of real-life Python code (the standard library is a common choice, but a big project like Django or SQLAlchemy would also be reasonable) and demonstrating how the code could be *improved* by using the proposed new feature. Here, the key is that the change has to be an improvement - readability is one (somewhat difficult to assess objectively) criterion, as is ease of identifying bugs, or efficiency (less need to repeat complex expressions, for example). Conversely, any proposed new feature needs to address how it impacts people who *don't* want to use it. That can be as simple as backward compatibility issues such as adding new keywords (people using that keyword as a variable name will have to change their code) but can also address any general runtime impact in the interpreter (bookkeeping and management of new data structures for example, or changes to class implementation details). and how people who don't use the new feature will be impacted if they encounter the feature in code written by others, or in code reviews. Also, there's the question of teachability. A proposed new feature must address how it will be explained to new and existing Python users. And given the confusion we're seeing in this thread ("aren't these just runtime assertions?") that's something that contracts will definitely have to address. I'm not saying that the proposal needs to offer a full tutorial on design by contract, but at a minimum, it'll have to cover why contracts aren't just runtime assertions, and how the differences can be made clear in the documentation and by trainers. I hope that helps explain what you'll need to do if you want to take this proposal forward, and why you're getting pushback in areas that maybe seem incidental to you. Personally, I'm interested in the feature, but I'm not sure I'm interested enough to want it in Python. My main questions are 1. How exactly do these differ from simple assertions? I don't understand the hints about "relaxing" and "strengthening" contracts in subclasses, in particular I've no idea how I'd express that in actual syntax. 2. Are we talking here about adding checks that would run in production code? Wouldn't that slow code down? How do I deal with the conflict between wanting tighter checks but not wanting to pay the cost at runtime of checking things that should never go wrong (contracts, as I understand it, are for protecting against code bugs, that's why there's no facility for trapping them and producing "user friendly" error messages)? I use assertions very sparingly in production code for precisely that reason - why would I be more willing to use contracts? Paul From p.f.moore at gmail.com Thu Aug 30 04:33:35 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 09:33:35 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: Sorry if this gets double posted. Can people using Google Groups *please* adjust the mail headers so that mailing list posters can reply without getting errors? Ideally stop using Google Groups, but if you have to, please consider those that don't. Specifically, please remove the Google Groups address from the reply-to header, so that replies go direct to the mailing list and not to the Google Groups address :-( (Google Groups messages also don't filter properly, so I end up also having to manually re-file messages that come via that route. While I doubt GG users can do much about that, it is another downside of using the GG interface, and one that GG users should be aware of). Sorry, feeling grumpy about GG today. On Thu, 30 Aug 2018 at 09:01, Paul Moore wrote: > > On Thu, 30 Aug 2018 at 08:38, Neil Girdhar wrote: > > > > There are a lot of misunderstandings in this thread. It's probably best to start by reading up on the roots of unity (https://en.wikipedia.org/wiki/Root_of_unity). The key ideas are that a real number has two complex square roots, three complex cube roots, and so on. > > The complexities of fractional powers aside, the type of a result > should not depend on the values of the arguments. So I'm -1 on this > change for that reason alone. > > Questions of which root it's appropriate to take are separate, and IMO > the sensible option is to follow the behaviour of float, for which we > have > > >>> (-1)**(2/3) > (-0.4999999999999998+0.8660254037844387j) > >>> (1)**(2/3) > 1.0 > >>> (0)**(2/3) > 0.0 > > So current behaviour of Fraction is correct on that basis, IMO. > > Paul From mistersheik at gmail.com Thu Aug 30 04:36:18 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 04:36:18 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 4:01 AM Paul Moore wrote: > On Thu, 30 Aug 2018 at 08:38, Neil Girdhar wrote: > > > > There are a lot of misunderstandings in this thread. It's probably best > to start by reading up on the roots of unity ( > https://en.wikipedia.org/wiki/Root_of_unity). The key ideas are that a > real number has two complex square roots, three complex cube roots, and so > on. > > The complexities of fractional powers aside, the type of a result > should not depend on the values of the arguments. So I'm -1 on this > change for that reason alone. > > Just so you know, it already does depend on the type of the arguments. In [4]: Fraction(2) ** Fraction(1, 2) Out[4]: 1.4142135623730951 In [5]: Fraction(2) ** Fraction(3, 1) Out[5]: Fraction(8, 1) Like a lot of types, Fraction tries to return a Fraction if it can. This is consistent with how math.sqrt of a float returns a float and never a complex, and same for numpy.cbrt. Questions of which root it's appropriate to take are separate, and IMO > the sensible option is to follow the behaviour of float, for which we > have > > >>> (-1)**(2/3) > (-0.4999999999999998+0.8660254037844387j) > But -1 ** Fraction(2, 3) is closer to cube_root(-1 ** 2) than it is to the floating behavior. The reason the floating behavior returns what it does is, if I understand correctly, to try to stay on the same complex branch as the power varies. In other words, we want branch continuity in the power. After all, floating point values have some inaccuracy, and we wouldn't want chaotic behavior, i.e., small changes to the power to have drastic changes to the result. This is not like Fraction where we know that x ** Fraction(1, 3) is a genuine cube root, and so why not return the principal cube, which we know to be real valued for real valued x? >>> (1)**(2/3) > 1.0 > >>> (0)**(2/3) > 0.0 > So current behaviour of Fraction is correct on that basis, IMO. > > Paul > -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Thu Aug 30 04:38:20 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Thu, 30 Aug 2018 17:38:20 +0900 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: <23431.44284.518718.308682@turnbull.sk.tsukuba.ac.jp> Neil Girdhar writes: > There are a lot of misunderstandings in this thread. It's probably > best to start by reading up on the roots of unity ( > https://en.wikipedia.org/wiki/Root_of_unity). That's not very polite, especially in context where somebody has already conceded that his "wrong" was over the top. Speaking of courtesy, please stop clean up your addressee list. If you don't, GoogleGroups spams people who reply with "you're not a member". > same for the cube root I imagine if we had a cube root function Let's call > that the principal cube root, which is always real for a > real-valued input. That doesn't seem to be how Wolfram sees it: http://mathworld.wolfram.com/PrincipalRootofUnity.html From oono0114 at gmail.com Thu Aug 30 04:44:25 2018 From: oono0114 at gmail.com (=?UTF-8?B?5aSn6YeO6ZqG5byY?=) Date: Thu, 30 Aug 2018 17:44:25 +0900 Subject: [Python-ideas] zipfile encryption function In-Reply-To: References: Message-ID: Thank you for responding. I'm afraid that Windows doesn't and won't support AES zip archive and AES implementation itself is not small task(at least for me), so I would say AES support can be next. https://blogs.msdn.microsoft.com/oldnewthing/20180515-00/?p=98755 https://pypi.org/project/pycrypto/ >Could you provide a PR and upload that to bugs.python.org ? Sure, I have created issue just now. https://bugs.python.org/issue34546 I will follow development instructions (please let me know if I miss something because I'm really newbie) https://devguide.python.org/pullrequest/ Thanks and Regards, ------------------ Takahiro Ono 2018?8?30?(?) 16:42 M.-A. Lemburg : > On 30.08.2018 03:27, ???? wrote: > > Dear all, > > > > I would like to use zipfile encryption as python standard library. > > https://github.com/python/cpython/blob/master/Lib/zipfile.py > > > > Below document says "currently" cannot. > > https://github.com/python/cpython/blob/master/Doc/library/zipfile.rst > > "but it currently cannot create an encrypted file." > > > > Current pythonians like me have to use 3rd party like below, but I > > believe it is worth to include. > > https://pypi.org/project/pyminizip/ > > https://github.com/wllm-rbnt/py-zipcrypt > > > > please forgive me if someone have already suggested before. > > I think adding zipfile support for the now common per file > encryption logic using AES would be useful to have in the stdlib > zipfile module. It's used a lot where people do not want to > go for the full infrastructure which GPG entails. > > Could you provide a PR and upload that to bugs.python.org ? > > Some references: > https://en.wikipedia.org/wiki/Zip_%28file_format%29#Encryption > https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT > > Thanks, > -- > Marc-Andre Lemburg > eGenix.com > > Professional Python Services directly from the Experts (#1, Aug 30 2018) > >>> Python Projects, Coaching and Consulting ... http://www.egenix.com/ > >>> Python Database Interfaces ... http://products.egenix.com/ > >>> Plone/Zope Database Interfaces ... http://zope.egenix.com/ > ________________________________________________________________________ > > ::: We implement business ideas - efficiently in both time and costs ::: > > eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 > D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg > Registered at Amtsgericht Duesseldorf: HRB 46611 > http://www.egenix.com/company/contact/ > http://www.malemburg.com/ > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Thu Aug 30 04:44:37 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 04:44:37 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <23431.44284.518718.308682@turnbull.sk.tsukuba.ac.jp> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <23431.44284.518718.308682@turnbull.sk.tsukuba.ac.jp> Message-ID: On Thu, Aug 30, 2018 at 4:38 AM Stephen J. Turnbull < turnbull.stephen.fw at u.tsukuba.ac.jp> wrote: > Neil Girdhar writes: > > > There are a lot of misunderstandings in this thread. It's probably > > best to start by reading up on the roots of unity ( > > https://en.wikipedia.org/wiki/Root_of_unity). > > That's not very polite, especially in context where somebody has > already conceded that his "wrong" was over the top. > > Speaking of courtesy, please stop clean up your addressee list. If > you don't, GoogleGroups spams people who reply with "you're not a > member". > > > same for the cube root I imagine if we had a cube root function Let's > call > > that the principal cube root, which is always real for a > > real-valued input. > > That doesn't seem to be how Wolfram sees it: > > http://mathworld.wolfram.com/PrincipalRootofUnity.html Right, I meant real root. It just happens the principal square root is the real root. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 30 05:05:55 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 30 Aug 2018 10:05:55 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Message-ID: Hi Neil You wrote: > Would there be any problem with changing: > In [4]: Fraction(1, 1) ** Fraction(2, 3) > Out[4]: 1.0 > In [5]: Fraction(-1, 1) ** Fraction(2, 3) > Out[5]: (-0.4999999999999998+0.8660254037844387j) > In [6]: Fraction(0, 1) ** Fraction(2, 3) > Out[6]: 0.0 > I'd like these to be Fraction(1), Fraction(1), and Fraction(0). I think this may be a hard problem, that looks easy. I'm used to using a number theory computer algebra system https://pari.math.u-bordeaux.fr/. Here's what it does with your examples. (First I show that it's default number type is whole numbers and fractions.) $ gp GP/PARI CALCULATOR Version 2.5.5 (released) ? 1/2 + 1/2 %1 = 1 ? 2^3 %2 = 8 ? 2^(6/2) %3 = 8 ? 4^(1/2) %4 = 2.0000000000000000000000000000000000000 ? 1^(2/3) %5 = 1.0000000000000000000000000000000000000 ? (-1)^(2/3) %6 = -0.50000000000000000000000000000000000000 + 0.86602540378443864676372317075293618347*I ? (0/1)^(2/3) %7 = 0 This gives the same results as Python's Fraction, except for your example [6]. There, it gives the Fraction(0) you ask for. If the smart mathematicians and computer scientists that wrote gp/pari get the same answers, it suggests to me that improvement would be hard. That said, a case can be made for the value given by [6] being a bug. Or a poorly documented feature. -- best regards Jonathan From jfine2358 at gmail.com Thu Aug 30 05:11:46 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 30 Aug 2018 10:11:46 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Message-ID: Hi Neil We wrote >> This gives the same results as Python's Fraction, except for your >> example [6]. There, it gives the Fraction(0) you ask for. >> >> If the smart mathematicians and computer scientists that wrote gp/pari >> get the same answers, it suggests to me that improvement would be >> hard. > That's because these are just floating point numbers. These are not being > processed symbolically. Wolfram Alpha gives all three roots, including the > real root. I've not used Wolfram Alpha, nor I think have many people on this list. Please copy and paste the input and output from Alpha, so we can see for ourselves (and so there's a record on this list). If anyone has time and ready access, it would help to know what https://www.sympy.org/en/index.html does with this. Perhaps your innocent request conceals a request for symbolic handling of simple algebraic numbers. -- best regards Jonathan From J.Demeyer at UGent.be Thu Aug 30 05:22:20 2018 From: J.Demeyer at UGent.be (Jeroen Demeyer) Date: Thu, 30 Aug 2018 11:22:20 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5fbfa9bef13d4f46bc901dfa9f72e574@xmail103.UGent.be> References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> <5fbfa9bef13d4f46bc901dfa9f72e574@xmail103.UGent.be> Message-ID: <5B87B74C.7080000@UGent.be> On 2018-08-30 11:05, Jonathan Fine wrote: > I'm used to using a number theory computer algebra system > https://pari.math.u-bordeaux.fr/. I don't think that a comparison with PARI is very relevant because PARI doesn't really have a type system the way that Python does. For example the fraction 3/1 doesn't really exist in PARI, only the integer 3 does. From mistersheik at gmail.com Thu Aug 30 05:25:04 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 05:25:04 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Message-ID: On Thu, Aug 30, 2018 at 5:11 AM Jonathan Fine wrote: > Hi Neil > > We wrote > > >> This gives the same results as Python's Fraction, except for your > >> example [6]. There, it gives the Fraction(0) you ask for. > >> > >> If the smart mathematicians and computer scientists that wrote gp/pari > >> get the same answers, it suggests to me that improvement would be > >> hard. > > > That's because these are just floating point numbers. These are not > being > > processed symbolically. Wolfram Alpha gives all three roots, including > the > > real root. > > I've not used Wolfram Alpha, nor I think have many people on this > list. Please copy and paste the input and output from Alpha, so we can > see for ourselves (and so there's a record on this list). > It's online for everyone to use: http://www.wolframalpha.com/input/?i=(-1)+%5E+(1%2F3) > > If anyone has time and ready access, it would help to know what > https://www.sympy.org/en/index.html does with this. > > Perhaps your innocent request conceals a request for symbolic handling > of simple algebraic numbers. > Well, rational numbers. Although an algebraic number type would be interesting. And, the way I see it, Fraction is the type corresponding to the field of rational numbers. > > -- > best regards > > Jonathan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg.ewing at canterbury.ac.nz Thu Aug 30 05:26:42 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Thu, 30 Aug 2018 21:26:42 +1200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: <5B87B852.1070705@canterbury.ac.nz> Neil Girdhar wrote: > we want branch continuity in the power. > After all, floating point values have some inaccuracy, and we wouldn't > want chaotic behavior, i.e., small changes to the power to have drastic > changes to the result. > > This is not like Fraction where we know that x ** Fraction(1, 3) is a > genuine cube root, and so why not return the principal cube, which we > know to be real valued for real valued x? Because that would be possible only for a few special combinations of Fractions ** Fractions that happen to have rational solutions. All the others would still have to return float or complex results, which could then be discontinuous with the rational ones. -- Greg From J.Demeyer at UGent.be Thu Aug 30 05:28:51 2018 From: J.Demeyer at UGent.be (Jeroen Demeyer) Date: Thu, 30 Aug 2018 11:28:51 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Message-ID: <5B87B8D3.6080304@UGent.be> On 2018-08-30 11:11, Jonathan Fine wrote: > If anyone has time and ready access, it would help to know what > https://www.sympy.org/en/index.html does with this. It handles such powers symbolically, not actually returning a numerical result: >>> from sympy import Rational >>> Rational(1,2) ** Rational(2,3) 2**(1/3)/2 >>> Rational(1,1) ** Rational(2,3) 1 >>> Rational(-1,1) ** Rational(2,3) (-1)**(2/3) >>> Rational(0,1) ** Rational(2,3) 0 From J.Demeyer at UGent.be Thu Aug 30 05:31:52 2018 From: J.Demeyer at UGent.be (Jeroen Demeyer) Date: Thu, 30 Aug 2018 11:31:52 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Message-ID: <5B87B988.3050802@UGent.be> With gmpy2 (note that mpq=fractions, mpfr=floating-point reals): >>> from gmpy2 import mpq >>> mpq("1/1") ** mpq("2/3") mpfr('1.0') >>> mpq("-1/1") ** mpq("2/3") mpfr('nan') >>> mpq("0/1") ** mpq("2/3") mpfr('0.0') From mistersheik at gmail.com Thu Aug 30 05:34:05 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 05:34:05 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B87B852.1070705@canterbury.ac.nz> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 5:27 AM Greg Ewing wrote: > Neil Girdhar wrote: > > we want branch continuity in the power. > > After all, floating point values have some inaccuracy, and we wouldn't > > want chaotic behavior, i.e., small changes to the power to have drastic > > changes to the result. > > > > This is not like Fraction where we know that x ** Fraction(1, 3) is a > > genuine cube root, and so why not return the principal cube, which we > > know to be real valued for real valued x? > > Because that would be possible only for a few special combinations > of Fractions ** Fractions that happen to have rational solutions. All > the others would still have to return float or complex results, > which could then be discontinuous with the rational ones. > > Right, but we already have some special cases: In [8]: Fraction(2, 3) ** Fraction(3, 1) Out[8]: Fraction(8, 27) Fraction.__pow__ already tries to return Fraction objects where possible. -- > Greg > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/aZIHpPhe0mw/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nicolas.rolin at tiime.fr Thu Aug 30 05:50:11 2018 From: nicolas.rolin at tiime.fr (Nicolas Rolin) Date: Thu, 30 Aug 2018 11:50:11 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: >> Right, but we already have some special cases: > > In [8]: Fraction(2, 3) ** Fraction(3, 1) > Out[8]: Fraction(8, 27) > > Fraction.__pow__ already tries to return Fraction objects where possible. > I think the main point to see here is what the scope of a built-in function should be. For a fraction module in the stdlib, I would expect that it handle "symbolically" any fraction multiplication or division of fractions, and integer power of fractions. Those are simple and useful cases, that can arise a bit anywhere. Power of non-integer is a way more complex issue (notably because power of a non-integer is not a function), and returning the same output as float is at least an honest way of dealing with those cases. I'm not really sure a stdlib should even try do deal with that. If I want to have a symbolic way of handling complex power of fractions, I should import a specific math library whose specific job is to get this right (the same way if you want to do matrix stuff you have to import numpy). -- *Nicolas Rolin* -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 30 05:51:05 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 30 Aug 2018 10:51:05 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B87B8D3.6080304@UGent.be> References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> <5B87B8D3.6080304@UGent.be> Message-ID: Jeroen Demeyer wrote >>>> from sympy import Rational >>>> Rational(1,2) ** Rational(2,3) > 2**(1/3)/2 >>>> Rational(1,1) ** Rational(2,3) > 1 >>>> Rational(-1,1) ** Rational(2,3) > (-1)**(2/3) >>>> Rational(0,1) ** Rational(2,3) > 0 Thank you very much for this, Jeroen. Most helpful. Perhaps revising https://docs.python.org/3/library/fractions.html, to mention sympy's symbolic Rational number class, would meet the original poster's request. Neil Girdhar - how does this sound to you? Short of migrating part of sympy into Python's standard library, I don't know what else we could reasonably do. -- Jonathan From mistersheik at gmail.com Thu Aug 30 06:27:21 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 06:27:21 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 5:51 AM Nicolas Rolin wrote: > > > >>> Right, but we already have some special cases: >> >> In [8]: Fraction(2, 3) ** Fraction(3, 1) >> Out[8]: Fraction(8, 27) >> >> Fraction.__pow__ already tries to return Fraction objects where possible. >> > > > I think the main point to see here is what the scope of a built-in > function should be. > For a fraction module in the stdlib, I would expect that it handle > "symbolically" any fraction multiplication or division of fractions, and > integer power of fractions. > Those are simple and useful cases, that can arise a bit anywhere. Power of > non-integer is a way more complex issue (notably because power of a > non-integer is not a function), and returning the same output as float is > at least an honest way of dealing with those cases. > But I'm only asking for fractional powers of -1, 0, and 1. Is that really a complex issue? You are right that the fractional power of -1 and 1 has multiple values, but the fractional power of zero has a unique value. > > I'm not really sure a stdlib should even try do deal with that. If I want > to have a symbolic way of handling complex power of fractions, I should > import a specific math library whose specific job is to get this right (the > same way if you want to do matrix stuff you have to import numpy). > That's how I use the fractions package. If you look at my example code, that seems like the kind of problem Fraction should make it easy to work with. And yet, there was a wrinkle where I had to calculate Fraction(-1) ** Fraction(a, b). > > -- > > *Nicolas Rolin* > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/aZIHpPhe0mw/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/aZIHpPhe0mw/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 30 07:03:26 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 30 Aug 2018 12:03:26 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: Hi Neil Summary: You say something should be done. But by who? Perhaps the should starts with you. Warning: This has been written quickly, and might have rough edges. If so, I apologise. You wrote > But I'm only asking for fractional powers of -1, 0, and 1. Is that really a > complex issue? > You are right that the fractional power of -1 and 1 has multiple values, but > the fractional power of zero has a unique value. >> I'm not really sure a stdlib should even try do deal with that. If I want >> to have a symbolic way of handling complex power of fractions, I should >> import a specific math library whose specific job is to get this right (the >> same way if you want to do matrix stuff you have to import numpy). > That's how I use the fractions package. If you look at my example code, > that seems like the kind of problem Fraction should make it easy to work > with. And yet, there was a wrinkle where I had to calculate Fraction(-1) ** > Fraction(a, b). Let's try to make the best of what we've got. First, the docs for the fraction module could be improved. Here's the page and it's history. https://docs.python.org/3/library/fractions.html https://github.com/python/cpython/commits/3.7/Doc/library/fractions.rst Already, doing this will help users. In particular, for a different approach, point them to https://www.sympy.org/en/index.html Second, assume you're right, when you say > [This sort of problem], Fraction should make it easy [...] The problem is, Python development resources are finite. They should be more, but they're not. It's hard to go from 'Fraction should' to ' should'. Perhaps the best one can come up with is the developers of fraction.py. Here's the page and history. https://github.com/python/cpython/blob/3.7/Lib/fractions.py https://github.com/python/cpython/commits/3.7/Lib/fractions.py Third, there is a way to go from 'Fraction should' to a group of persons. If you're correct, that 'Fraction should', then I'm happy to say that it follows that 'the Python community should'. Now, the Python community is vast. It's more than the core developers. I'm a member. You're a member. Everyone participating on this list is a member. It's got lots of resources. You want this problem solved. You've got clear ideas what should be done. You say it should be done. And you're a member of the Python community, who 'should fix this problem'. The module fractions.py is pure Python. You can fork it to develop your own solution, written as it should be. You can use this solution and share it with the community. And you can submit it as a pull request, for inclusion in the standard library. To summarise. You're part of the Python community, who you believe should solve this problem. Please, as a member of the community, accept some responsibility for do what you think should be done. And finally, thank you for drawing to our attention this blemish in the fractions module (or its documentation). -- Jonathan From p.f.moore at gmail.com Thu Aug 30 07:13:12 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 12:13:12 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: (You're still not fixing your mail headers. Please do, it's hard to be bothered responding if I keep having to fix your mails in order to do so). On Thu, 30 Aug 2018 at 11:28, Neil Girdhar wrote: > > But I'm only asking for fractional powers of -1, 0, and 1. Is that really a complex issue? Yes. (Even ignoring the oh-so-tempting complex number joke ;-)). As has been seen here there's no agreement on the "right" choice of which root of -1 to choose. Or possibly more accurately, no-one else is agreeing with your suggestion that we choose a different option for the case you're arguing over. And to be 100% precise, you asked for the results of three *very specific* calculations to change. I guess you actually want something more general - or are you really OK with (for example) Fraction(-1,1)**Fraction(2,3) changing as you request, but Fraction(-2,1)**Fraction(2,3) remaining as it currently is? You still haven't clarified (no-one has particularly asked yet - you may consider this a request to do so if you like) how you propose in general that the result of Fraction(-1,1) ** Fraction(a, b) and/or Fraction(1,1) ** Fraction(a, b) or maybe even more generally Fraction(c,d) ** Fraction(a,b) would change. What exactly are the special cases you want to define different results for? What is the process for choosing the result? > You are right that the fractional power of -1 and 1 has multiple values, but the fractional power of zero has a unique value. And that part of your proposal has not generated much controversy. Maybe if you proposed only that, you might get that change made? I haven't considered the ramifications of that because the discussions about -1 are obscuring it, but it might be relatively uncontroversial. Paul From mertz at gnosis.cx Thu Aug 30 07:22:43 2018 From: mertz at gnosis.cx (David Mertz) Date: Thu, 30 Aug 2018 07:22:43 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <5B875DDE.2030308@stoneleaf.us> Message-ID: On Thu, Aug 30, 2018 at 3:44 AM Marko Ristin-Kaufmann < marko.ristin at gmail.com> wrote: > Related to the text I emphasized, would you mind to explain a bit more > in-depth which features you have in mind? I see contracts formally written > out and automatically verified as a completely indispensable tool in large > projects with multiple people involved. > This much is rather self-evidently untrue. There are hundreds or thousands of large projects involving multiple people, written in Python, that have succeeded without using contracts. That suggests the feature is not "completely indispensable" since it was dispensed with in the vast majority of large projects. I think that most of these large projects succeed in large part because they have good *unit tests*. There are several popular frameworks for writing these (some in standard library), but notably none of them require specific syntax changes to make them work. Some of them *do* use DSLs of sorts as part of how they operate (or various metaprogramming and introspection magic). There is a whole lot of overlap between what unit tests do and what design-by-contract does, enough so that I believe the latter adds little to a large project (of course you can come up with some specific example that a unit test cannot verify as well as a pre/postcondition. In writing before about "features" (and Paul Moore) does a better job than me in writing about *costs*, I wasn't discussing design-by-contract specifically. Various new feature ideas come up here and elsewhere. A few are accepted, most are rejected. They all need to be compared to costs like those I mention before their possible advantages can win out. Yours, David... -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Thu Aug 30 07:31:10 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 07:31:10 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: Thanks for the feedback. On Thu, Aug 30, 2018 at 7:13 AM Paul Moore wrote: > (You're still not fixing your mail headers. Please do, it's hard to be > bothered responding if I keep having to fix your mails in order to do > so). > > On Thu, 30 Aug 2018 at 11:28, Neil Girdhar wrote: > > > > But I'm only asking for fractional powers of -1, 0, and 1. Is that > really a complex issue? > > Yes. (Even ignoring the oh-so-tempting complex number joke ;-)). As > has been seen here there's no agreement on the "right" choice of which > root of -1 to choose. Or possibly more accurately, no-one else is > agreeing with your suggestion that we choose a different option for > the case you're arguing over. > > And to be 100% precise, you asked for the results of three *very > specific* calculations to change. I guess you actually want something > more general - or are you really OK with (for example) > Fraction(-1,1)**Fraction(2,3) changing as you request, but > Fraction(-2,1)**Fraction(2,3) remaining as it currently is? Powers of other numbers have to keep the same behavior since in general those kinds of expressions don't create rational numbers. > You still > haven't clarified (no-one has particularly asked yet - you may > consider this a request to do so if you like) how you propose in > general that the result of > > Fraction(-1,1) ** Fraction(a, b) > and/or > Fraction(1,1) ** Fraction(a, b) > or maybe even more generally > Fraction(c,d) ** Fraction(a,b) > > would change. What exactly are the special cases you want to define > different results for? What is the process for choosing the result? > Here's my proposed method: class Fraction: def __pow__(a, b): """a ** b If b is not an integer, the result will be a float or complex since roots are generally irrational. If b is an integer, the result will be rational. """ if isinstance(b, numbers.Rational): if b.denominator == 1: power = b.numerator if power >= 0: return Fraction(a._numerator ** power, a._denominator ** power, _normalize=False) elif a._numerator >= 0: return Fraction(a._denominator ** -power, a._numerator ** -power, _normalize=False) else: return Fraction((-a._denominator) ** -power, (-a._numerator) ** -power, _normalize=False) elif a == -1 and b.denominator % 2 == 1: return Fraction(-1 if b.numerator % 2 == 1 else 1) elif a == 0: if b > 0: return Fraction(0) else: raise ZeroDivisionError( "0 cannot be raised to a negative power") elif a == 1: return Fraction(1) else: # A fractional power will generally produce an # irrational number. return float(a) ** float(b) else: return float(a) ** b Compare it with https://github.com/python/cpython/blob/3.7/Lib/fractions.py#L448 > > > You are right that the fractional power of -1 and 1 has multiple values, > but the fractional power of zero has a unique value. > > And that part of your proposal has not generated much controversy. > Maybe if you proposed only that, you might get that change made? I > haven't considered the ramifications of that because the discussions > about -1 are obscuring it, but it might be relatively uncontroversial. > Fair enough. > > Paul > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Thu Aug 30 07:46:19 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 07:46:19 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 7:03 AM Jonathan Fine wrote: > Hi Neil > > Summary: You say something should be done. But by who? Perhaps the > should starts with you. > What does this mean? Are you asking who is going to do the implementation? I posted here to get feedback about whether it would be a good idea. > > Warning: This has been written quickly, and might have rough edges. If > so, I apologise. > > You wrote > > > But I'm only asking for fractional powers of -1, 0, and 1. Is that > really a > > complex issue? > > > You are right that the fractional power of -1 and 1 has multiple values, > but > > the fractional power of zero has a unique value. > > >> I'm not really sure a stdlib should even try do deal with that. If I > want > >> to have a symbolic way of handling complex power of fractions, I should > >> import a specific math library whose specific job is to get this right > (the > >> same way if you want to do matrix stuff you have to import numpy). > > > That's how I use the fractions package. If you look at my example code, > > that seems like the kind of problem Fraction should make it easy to work > > with. And yet, there was a wrinkle where I had to calculate > Fraction(-1) ** > > Fraction(a, b). > > Let's try to make the best of what we've got. > > First, the docs for the fraction module could be improved. Here's the > page and it's history. > > https://docs.python.org/3/library/fractions.html > > https://github.com/python/cpython/commits/3.7/Doc/library/fractions.rst > > Already, doing this will help users. In particular, for a different > approach, point them to > > https://www.sympy.org/en/index.html > > Second, assume you're right, when you say > > > [This sort of problem], Fraction should make it easy [...] > > The problem is, Python development resources are finite. They should > be more, but they're not. It's hard to go from 'Fraction should' to > ' should'. Perhaps the best one can come up with > is the developers of fraction.py. Here's the page and history. > > https://github.com/python/cpython/blob/3.7/Lib/fractions.py > https://github.com/python/cpython/commits/3.7/Lib/fractions.py Thanks for linking the github. I'm only posting on ideas to get feedback. I think this is what the group is for. Also, I don't know why you keep bringing up the finite Python developer resources. Like I said above, this is a small change, (one that I coded below). Besides that bit of code, I could add a few tests, and modify the docs. Someone would have to review it, but it's not a big job. The only question is: should it be done? And that's why I posted it here. > > > Third, there is a way to go from 'Fraction should' to a group of > persons. If you're correct, that 'Fraction should', then I'm happy to > say that it follows that 'the Python community should'. > > Now, the Python community is vast. It's more than the core developers. > I'm a member. You're a member. Everyone participating on this list is > a member. It's got lots of resources. > > You want this problem solved. You've got clear ideas what should be > done. You say it should be done. And you're a member of the Python > community, who 'should fix this problem'. > > The module fractions.py is pure Python. You can fork it to develop > your own solution, written as it should be. You can use this solution > and share it with the community. And you can submit it as a pull > request, for inclusion in the standard library. > Before I do that, I want to get feedback here. The way I understand the usual order with feature requests is that they are discussed, they turn into PEPs, they are approved, they are implemented, they are reviewed, they are checked in. Someone will definitely correct me. No one wants to spend time writing documentation for code that will never be checked in. > To summarise. You're part of the Python community, who you believe > should solve this problem. Please, as a member of the community, > accept some responsibility for do what you think should be done. Maybe I'm interpreting this wrong, but what do you mean by "accept some responsibility"? The last time I felt strongly about a feature (PEP 448), and after it had been approved by Guido, I spent a few months implementing it along with Joshua Landau (https://bugs.python.org/issue2292). Compared to this tiny change, that was a huge change involving the parser, the compiler, and the grammar. I really don't understand what you're driving at with this "accept some responsibility" comment. > And finally, thank you for drawing to our attention this blemish in > the fractions module (or its documentation). > > -- > Jonathan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mistersheik at gmail.com Thu Aug 30 07:55:01 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 07:55:01 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: On Thu, Aug 30, 2018 at 7:13 AM Paul Moore wrote: > (You're still not fixing your mail headers. Please do, it's hard to be > bothered responding if I keep having to fix your mails in order to do > so). > Sorry about that, I don't understand where it's coming from. I'm never using google groups. I'm only replying to the emails that are sent to me. I guess gmail's reply-all is gathering the google groups mail from the thread. > On Thu, 30 Aug 2018 at 11:28, Neil Girdhar wrote: > > > > But I'm only asking for fractional powers of -1, 0, and 1. Is that > really a complex issue? > > Yes. (Even ignoring the oh-so-tempting complex number joke ;-)). As > has been seen here there's no agreement on the "right" choice of which > root of -1 to choose. Or possibly more accurately, no-one else is > agreeing with your suggestion that we choose a different option for > the case you're arguing over. > > And to be 100% precise, you asked for the results of three *very > specific* calculations to change. I guess you actually want something > more general - or are you really OK with (for example) > Fraction(-1,1)**Fraction(2,3) changing as you request, but > Fraction(-2,1)**Fraction(2,3) remaining as it currently is? You still > haven't clarified (no-one has particularly asked yet - you may > consider this a request to do so if you like) how you propose in > general that the result of > > Fraction(-1,1) ** Fraction(a, b) > and/or > Fraction(1,1) ** Fraction(a, b) > or maybe even more generally > Fraction(c,d) ** Fraction(a,b) > > would change. What exactly are the special cases you want to define > different results for? What is the process for choosing the result? > > > You are right that the fractional power of -1 and 1 has multiple values, > but the fractional power of zero has a unique value. > > And that part of your proposal has not generated much controversy. > Maybe if you proposed only that, you might get that change made? I > haven't considered the ramifications of that because the discussions > about -1 are obscuring it, but it might be relatively uncontroversial. > > Paul > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Thu Aug 30 08:15:01 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 13:15:01 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: Thu, 30 Aug 2018 at 12:55, Neil Girdhar wrote: > > On Thu, Aug 30, 2018 at 7:13 AM Paul Moore wrote: >> >> (You're still not fixing your mail headers. Please do, it's hard to be >> bothered responding if I keep having to fix your mails in order to do >> so). > > > Sorry about that, I don't understand where it's coming from. I'm never using google groups. I'm only replying to the emails that are sent to me. I guess gmail's reply-all is gathering the google groups mail from the thread. Your original mail was sent to Google Groups. Do you have the wrong address for the list in your mail client? Message ID<0067a655-4f82-479f-9970-5b72dc079364 at googlegroups.com> Created on:30 August 2018 at 05:39 (Delivered after 74 seconds) From:Neil Girdhar To:python-ideas Subject:[Python-ideas] Fix some special cases in Fractions? Paul From mistersheik at gmail.com Thu Aug 30 08:18:07 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 08:18:07 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: Yeah, you're right, my original mail was posted on google groups. Sorry for the trouble. On Thu, Aug 30, 2018 at 8:15 AM Paul Moore wrote: > Thu, 30 Aug 2018 at 12:55, Neil Girdhar wrote: > > > > On Thu, Aug 30, 2018 at 7:13 AM Paul Moore wrote: > >> > >> (You're still not fixing your mail headers. Please do, it's hard to be > >> bothered responding if I keep having to fix your mails in order to do > >> so). > > > > > > Sorry about that, I don't understand where it's coming from. I'm never > using google groups. I'm only replying to the emails that are sent to me. > I guess gmail's reply-all is gathering the google groups mail from the > thread. > > Your original mail was sent to Google Groups. Do you have the wrong > address for the list in your mail client? > > Message ID<0067a655-4f82-479f-9970-5b72dc079364 at googlegroups.com> > Created on:30 August 2018 at 05:39 (Delivered after 74 seconds) > From:Neil Girdhar > To:python-ideas > Subject:[Python-ideas] Fix some special cases in Fractions? > > Paul > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jfine2358 at gmail.com Thu Aug 30 08:18:22 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Thu, 30 Aug 2018 13:18:22 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: Hi Neil When I wrote my previous message, I didn't know who you were, or your previous contributions. Perhaps I should have. But I didn't. If I had known, my remarks would have been different. In particular, I would have acknowledged your previous contributions. I apologise for any offence I may have caused you. Better late than never. Thank you for your contributions to implementing PEP 448. with best regards Jonathan From mistersheik at gmail.com Thu Aug 30 08:21:48 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Thu, 30 Aug 2018 08:21:48 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: Hey, no worries. I do think though that people should feel free to suggest ideas even if they have never contributed anything. I read python-ideas for the discussion. Thank you for your feedback about my suggestion. On Thu, Aug 30, 2018 at 8:18 AM Jonathan Fine wrote: > Hi Neil > > When I wrote my previous message, I didn't know who you were, or your > previous contributions. Perhaps I should have. But I didn't. > > If I had known, my remarks would have been different. In particular, I > would have acknowledged your previous contributions. I apologise for > any offence I may have caused you. > > Better late than never. Thank you for your contributions to > implementing PEP 448. > > with best regards > > Jonathan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Thu Aug 30 08:56:57 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 13:56:57 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: On Thu, 30 Aug 2018 at 12:04, Jonathan Fine wrote: > First, the docs for the fraction module could be improved. Here's the > page and it's history. > > https://docs.python.org/3/library/fractions.html > https://github.com/python/cpython/commits/3.7/Doc/library/fractions.rst > > Already, doing this will help users. While the documentation is pretty terse and could be expanded, it's worth noting that the class also has docstrings. And whether we feel that docstrings are sufficiently accessible for users (certainly I often forget to check them) they *are* part of the module documentation. In particular: >>> help(fractions.Fraction.__pow__) Help on function __pow__ in module fractions: __pow__(a, b) a ** b If b is not an integer, the result will be a float or complex since roots are generally irrational. If b is an integer, the result will be rational. That's clear, concise, and explains the current behaviour precisely. Neil's proposal is definitely a functional change (not that he was denying this) in that it alters already documented behaviour. And I think that's something we should remember. This isn't undocumented (or even badly documented) behaviour - it's clearly defined behaviour noted in the official documentation (just in a part of that documentation that's easy to overlook). > In particular, for a different > approach, point them to > > https://www.sympy.org/en/index.html I don't honestly think that sympy is a comparable tool to the stdlib Fraction class. I suspect that most people who need the Fraction class are not even remotely in the target audience for sympy. The ones who are, likely already know about it. > And finally, thank you for drawing to our attention this blemish in > the fractions module (or its documentation). I wouldn't describe it as a blemish. Rather, it's somewhere we could maybe improve the discoverability of the existing documentation. Or an opportunity to review how we make it easier for users to get access to documentation that is held in docstrings, as opposed to the manuals. Maybe a pydoc instance available online, linked from the manual entries? Paul From steve at pearwood.info Thu Aug 30 09:01:52 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Thu, 30 Aug 2018 23:01:52 +1000 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> Message-ID: <20180830130150.GI27312@ando.pearwood.info> On Wed, Aug 29, 2018 at 09:39:05PM -0700, Neil Girdhar wrote: > Would there be any problem with changing: > > In [4]: Fraction(1, 1) ** Fraction(2, 3) > Out[4]: 1.0 > > In [5]: Fraction(-1, 1) ** Fraction(2, 3) > Out[5]: (-0.4999999999999998+0.8660254037844387j) > > In [6]: Fraction(0, 1) ** Fraction(2, 3) > Out[6]: 0.0 > > I'd like these to be Fraction(1), Fraction(1), and Fraction(0). If anyone else has mentioned the backward-compatibility issue by now, I haven't see it. I believe that would make it a fairly big problem. I expect that there is code out in the wild which (for good or ill) now expects 1**Fraction(2, 3) to return 1.0, rather than Fraction(1), and similarly for the other examples. Changing that could break people's code. Even if we had consensus that this was a good idea, or at least consensus from the maths-folk who care about this sort of thing (I'd like to know what Uncle Timmy and Mark think of this idea), it would still probably need a "__future__" import to activate it, or a deprecation period. Or some other annoyance. Possibly the simpler approach would be to add a subclass that does what you want. UnitRootFraction or something. Then the only argument will be whether such a subclass ought to go into the fractions module, or your own personal toolkit :-) I must admit though, I'm a bit curious as to what you are doing that having 1**Fraction(2,3) return 1.0 is an annoyance, but having 27**Fraction(2,3) return 8.999999999999998 instead of Fraction(9) isn't. -- Steve From nicolas.rolin at tiime.fr Thu Aug 30 09:05:23 2018 From: nicolas.rolin at tiime.fr (Nicolas Rolin) Date: Thu, 30 Aug 2018 15:05:23 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: I think you could take the implementation further and decide that any power of Fraction(1) is Fraction(1) and any positive power of Fraction(0) is Fraction(0). I woudn't be shocked that Fraction(1) ** 3.7 == Fraction(1) and Fraction(0) ** 3.7 == 0. However the implementation for Fraction(-1) seems a bit to "ad hoc", and break some expected behavior of the powers. For exemple in your code Fraction(-2) ** Fraction(2, 3) != Fraction(-1) ** Fraction(2, 3) * Fraction(2) ** Fraction(2, 3), whereas floats respect this. You could change the code so that the property (a *b) ** c == a**c *b**c, but idk how hard it is. 2018-08-30 13:31 GMT+02:00 Neil Girdhar : > Thanks for the feedback. > > On Thu, Aug 30, 2018 at 7:13 AM Paul Moore wrote: > >> (You're still not fixing your mail headers. Please do, it's hard to be >> bothered responding if I keep having to fix your mails in order to do >> so). >> >> On Thu, 30 Aug 2018 at 11:28, Neil Girdhar wrote: >> > >> > But I'm only asking for fractional powers of -1, 0, and 1. Is that >> really a complex issue? >> >> Yes. (Even ignoring the oh-so-tempting complex number joke ;-)). As >> has been seen here there's no agreement on the "right" choice of which >> root of -1 to choose. Or possibly more accurately, no-one else is >> agreeing with your suggestion that we choose a different option for >> the case you're arguing over. >> >> And to be 100% precise, you asked for the results of three *very >> specific* calculations to change. I guess you actually want something >> more general - or are you really OK with (for example) >> Fraction(-1,1)**Fraction(2,3) changing as you request, but >> Fraction(-2,1)**Fraction(2,3) remaining as it currently is? > > > Powers of other numbers have to keep the same behavior since in general > those kinds of expressions don't create rational numbers. > > >> You still >> haven't clarified (no-one has particularly asked yet - you may >> consider this a request to do so if you like) how you propose in >> general that the result of >> >> Fraction(-1,1) ** Fraction(a, b) >> and/or >> Fraction(1,1) ** Fraction(a, b) >> or maybe even more generally >> Fraction(c,d) ** Fraction(a,b) >> >> would change. What exactly are the special cases you want to define >> different results for? What is the process for choosing the result? >> > > Here's my proposed method: > > class Fraction: > def __pow__(a, b): > """a ** b > If b is not an integer, the result will be a float or complex > since roots are generally irrational. If b is an integer, the > result will be rational. > """ > if isinstance(b, numbers.Rational): > if b.denominator == 1: > power = b.numerator > if power >= 0: > return Fraction(a._numerator ** power, > a._denominator ** power, > _normalize=False) > elif a._numerator >= 0: > return Fraction(a._denominator ** -power, > a._numerator ** -power, > _normalize=False) > else: > return Fraction((-a._denominator) ** -power, > (-a._numerator) ** -power, > _normalize=False) > elif a == -1 and b.denominator % 2 == 1: > return Fraction(-1 if b.numerator % 2 == 1 else 1) > elif a == 0: > if b > 0: > return Fraction(0) > else: > raise ZeroDivisionError( > "0 cannot be raised to a negative power") > elif a == 1: > return Fraction(1) > else: > # A fractional power will generally produce an > # irrational number. > return float(a) ** float(b) > else: > return float(a) ** b > > Compare it with https://github.com/python/cpython/blob/3.7/Lib/ > fractions.py#L448 > > >> >> > You are right that the fractional power of -1 and 1 has multiple >> values, but the fractional power of zero has a unique value. >> >> And that part of your proposal has not generated much controversy. >> Maybe if you proposed only that, you might get that change made? I >> haven't considered the ramifications of that because the discussions >> about -1 are obscuring it, but it might be relatively uncontroversial. >> > > Fair enough. > >> >> Paul >> > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- -- *Nicolas Rolin* | Data Scientist + 33 631992617 - nicolas.rolin at tiime.fr *15 rue Auber, **75009 Paris* *www.tiime.fr * -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Thu Aug 30 09:36:30 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Thu, 30 Aug 2018 14:36:30 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: On Thu, 30 Aug 2018 at 14:06, Nicolas Rolin wrote: > I think you could take the implementation further and decide that any > power of Fraction(1) is Fraction(1) and any positive power of Fraction(0) > is Fraction(0). > I woudn't be shocked that Fraction(1) ** 3.7 == Fraction(1) and > Fraction(0) ** 3.7 == 0. > You could do lots of things. But are any of them useful enough to warrant changing documented behaviour, breaking backward compatibility, and introducing a much more complex rule on how the arguments to Fraction.__pow__ affect the type of the return value? At the moment, there are no known use cases for this change - beyond Neil's statement that he'd "like" the values to be as he quoted (with no justification given). > However the implementation for Fraction(-1) seems a bit to "ad hoc", and > break some expected behavior of the powers. > For exemple in your code Fraction(-2) ** Fraction(2, 3) != Fraction(-1) ** > Fraction(2, 3) * Fraction(2) ** Fraction(2, 3), whereas floats respect this. > You could change the code so that the property (a *b) ** c == a**c *b**c, > but idk how hard it is. > This (what behaviour is "expected" and/or natural) is the sort of detail that can't be answered without knowing use cases - both use cases for the proposed behaviour *and* use cases that rely on the existing behaviour. Paul -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephanh42 at gmail.com Thu Aug 30 12:35:55 2018 From: stephanh42 at gmail.com (Stephan Houben) Date: Thu, 30 Aug 2018 18:35:55 +0200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <20180830130150.GI27312@ando.pearwood.info> References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> <20180830130150.GI27312@ando.pearwood.info> Message-ID: I would also like to point out that the current behavior of Fraction is consistent with other parts of the numeric system, e.g. 1/1 produces 1.0 (rather than 1) math.sqrt(4) produces 2.0 (rather than 2) 1j-1j produces 0j (rather than 0.0 or 0) So in general the type of the output is determined by what the operation would in general return for that input type, as opposed to a more specific type which only applies to the specific input value. Stephan Op do 30 aug. 2018 om 15:03 schreef Steven D'Aprano : > On Wed, Aug 29, 2018 at 09:39:05PM -0700, Neil Girdhar wrote: > > > Would there be any problem with changing: > > > > In [4]: Fraction(1, 1) ** Fraction(2, 3) > > Out[4]: 1.0 > > > > In [5]: Fraction(-1, 1) ** Fraction(2, 3) > > Out[5]: (-0.4999999999999998+0.8660254037844387j) > > > > In [6]: Fraction(0, 1) ** Fraction(2, 3) > > Out[6]: 0.0 > > > > I'd like these to be Fraction(1), Fraction(1), and Fraction(0). > > If anyone else has mentioned the backward-compatibility issue by now, I > haven't see it. I believe that would make it a fairly big problem. > > I expect that there is code out in the wild which (for good or ill) now > expects 1**Fraction(2, 3) to return 1.0, rather than Fraction(1), and > similarly for the other examples. Changing that could break people's > code. > > Even if we had consensus that this was a good idea, or at least > consensus from the maths-folk who care about this sort of thing (I'd > like to know what Uncle Timmy and Mark think of this idea), it would > still probably need a "__future__" import to activate it, or a > deprecation period. Or some other annoyance. > > Possibly the simpler approach would be to add a subclass that does what > you want. UnitRootFraction or something. > > Then the only argument will be whether such a subclass ought to go into > the fractions module, or your own personal toolkit :-) > > I must admit though, I'm a bit curious as to what you are doing that > having 1**Fraction(2,3) return 1.0 is an annoyance, but having > 27**Fraction(2,3) return 8.999999999999998 instead of Fraction(9) isn't. > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brenbarn at brenbarn.net Thu Aug 30 03:38:04 2018 From: brenbarn at brenbarn.net (Brendan Barnwell) Date: Thu, 30 Aug 2018 00:38:04 -0700 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <5B8797C7.2080303@canterbury.ac.nz> References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> Message-ID: <5B879EDC.5010502@brenbarn.net> On 2018-08-30 00:07, Greg Ewing wrote:> Jonathan Goble wrote: >> How? Raising something to the 2/3 power means squaring it and then >> taking the cube root of it. > > On reflection, "wrong" is not quite accurate. A better > word might be "surprising". > > (-1) ** (2/3) == 1 would imply that 1 ** (3/2) == -1. > I suppose that could be considered true if you take the > negative solution of the square root, but it seems a > bit strange, and it's not what Python gives you for > the result of 1 ** (3/2). > > If you want a solution that round-trips, you need > complex numbers. That's what Python does when you use > floats. Making Fractions do something different would > make it inconsistent with floats. > > My calculator (which only does real floats) reports an > error when trying to evaluate (-1) ** (2/3). The problem is that in the minds of most people who know enough math to know about fractional exponents, but still don't enough to want to deal with complex numbers, the standard procedure when taking a fractional power of a real number is: 1) choose a positive real value if there is one 2) choose a negative real value otherwise 3) give up if the answer would be nonreal But if you're willing to go to complex numbers, then the logic shifts to "take the principal root", which is the root in the complex plane that you get to first when going in the mathematically positive direction (counterclockwise) from the positive real axis. In addition, I think having 2 in the numerator in the fractional power is a red herring as far as understanding the confusion. This is already going to be surprising to people: >>> (-1) ** (1/3) (0.5000000000000001+0.8660254037844386j) In high school math, people are taught that (-1)^(1/3) = -1, because that's the only real value. But if you open up to the complex numbers, then you'll start defining (-1)^(1/3) as (-1 + sqrt(3)i)/2 since that is the more mathematically defensible principal value. (Interestingly, Wolfram Alpha by default gives -1 for "cube root of -1", but gives the complex value for "(-1)^(1/3)". If only we had a way to type an nth-root symbol instead of having to indicate roots with exponents!) Personally I think I was happier with the way things worked in Python 2, where (-1)**(1/3) would raise an error, and you had to explicitly do (-1 + 0j)**(1/3) if you wanted a complex root. I'm willing to bet that the vast majority of users doing arithmetic with Python never want nor can make any use of a complex value for any operation, ever; it is more likely they want an error message to alert them that their data has gone awry. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown From kulakov.ilya at gmail.com Thu Aug 30 16:47:33 2018 From: kulakov.ilya at gmail.com (Ilya Kulakov) Date: Thu, 30 Aug 2018 13:47:33 -0700 (PDT) Subject: [Python-ideas] Extend the warnings module with Deprecation utility methods and classes Message-ID: <4f5db5c5-7092-4c0c-8e0f-49504f08a99e@googlegroups.com> Sooner or later authors and maintainers of libraries change public interfaces of their creations. Usually one of the two approaches is taken: 1. Outright breaking change 2. Soft deprecation later followed by [1] While [1] is perfectly suitable for libraries with limited audience, [2] is what popular libraries have to do (to remain popular). Python's stdlib contributed to the process via PEP 230 and, recently, PEP 565. The `warn` function and subclasses of Warning are omnipresent. However, when it comes to practical application it's still up to a developer to write utility methods and classes. I propose that Python should extend the warnings module with a set of utilities to cover basic needs as seen across the industry. The extension should include: 1. A decorator for functions 2. A decorator for classes 3. A context manager Function Decorator A function can be deprecated: - Via a rename when an author decides there is a better name - Via a change of its interface - By becoming obsolete Therefore the job of the decorator is to modify the behavior such as upon a call: - A warning is issued - Optionally an aliased (new) function is called - Optionally both positional and keyword arguments are mapped to satisfy new interface; might be followed by an extra warning for each remap Class Decorator A class can be deprecated: - Via a rename when an author decides there is a better name - By becoming obsolete Therefore a job of the decorator is to ensure that: - A warning is issued when class is either instantiated or used as a base class - If aliased, subclasses of a deprecated class (from the end user perspective) pass `issubclass` and `isinstance` checks against an aliased new class - If aliased, subclasses of a new class pass `issubclass` and `isinstance` checks against a deprecated class Context Manager Context manager is useful when behavior of a particular function changes without visible changes to its name or interface. E.g. when author realizes (too late) that arguments are mutually exclusive. Instead of introducing a breaking change outright, better solution is to wrap that particular case with a warning and consistent behavior. Each of these utilities should allow to specify a condition via a callable. E.g. when deprecation only makes sense for certain platforms or python interpreter versions. I think most if not all can be implemented using existing runtime and stdlib. But before diving into code, what do you think of this idea overall? -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Thu Aug 30 16:49:32 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Thu, 30 Aug 2018 22:49:32 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <5B875DDE.2030308@stoneleaf.us> Message-ID: Hi, @David Mertz, @Paul Moore: first of all, thank you very much for your thorough answers! @Paul Moore : Thanks in particular for suggesting a road map. I still think that we need somewhat broader agreement even on this list that contracts are useful at an abstract level before we dig in and find concrete examples in existing code bases, have a more detailed estimation about the costs and how much conflicts the new keyword would cause, analyze how hard it would be to teach the concepts *etc.* So far, my impression is that the majority rejects outright the idea that the design-by-contract is useful and actually sees it as a redundant approach to software correctness at best, and an useless concept at worst. Of course, it would be much more convincing if I already performed a much more thorough analysis as you suggested. Unfortunately, I don't have the eloquence nor the resources to accomplish that at this moment. I'd imagine such an analysis to be a collaborative project of multiple interested people. I'd find it a futile effort before we have at least a vague agreement here that design-by-contract would be useful. Please let me address here the concrete points you raised in your message. 1. How exactly do these differ from simple assertions? I don't > understand the hints about "relaxing" and "strengthening" contracts in > subclasses, in particular I've no idea how I'd express that in actual > syntax. > The contracts to not apply only to a concrete function, but also extend to inherited methods. Let me make an illustration on a stripped-down example of three classes A, B and C, where B and C inherit from A. class A: # A.some_func operates on sorted lists of integers and # it returns an integer larger than the length of # the input list. @icontract.pre(lambda lst: lst == sorted(lst)) @icontract.post(lambda result: result > len(lst)) def some_func(self, lst: List[int]) -> int: # ... class B(A): # B.some_func inherits contracts from A, but overrides the implementation -> # B.some_func also operates only on sorted lists of integers # and needs to return an integer larger than the length # of the input list. def some_func(self, lst: List[int]) -> int: # ... class C(A): # C.some_func also inherits the contracts from A. # It weakens the precondition: # it operates either on sorted lists OR # the lists that are shorter than 10 elements. # # It strenghthens the postcondition: # It needs to return an integer larger than # the length of the input list AND # the result needs to be divisible by 2. @icontract.post(lambda result: result % 2 == 0) def some_func(self, lst: List[int]) -> int: # ... Assume that the function A.some_func needs sorted integers as input (*e.g.* because it uses binary search). Now, class B inherits from A -- say B.some_func also uses binary search. The things get really interesting in the case of class C and its method some_func: to satisfy polymorphism, C.some_func needs to work in all cases where an instance of A could work as well. However, it can do more -- it can also operate in situations where the input list has few elements, but is not necessarily sorted. This is called "weakening" or "relaxing" of a contract. The "strengthening" or "tightening" of a contract is an analogous concept for the post-conditions. Due to polymorphism, C.some_func needs to return a result that satisfies all the postconditions of its ancestors so that we can safely use it in all the situations where we would also use an instance of the ancestor class. But we can strengthen it in C.some_func: it needs to return the result satisfying the ancestors' postcondition and than be constrained some more. I omitted the invariants for brevity. They behave the same as the post-conditions: C needs to satisfy all its own invariants as well as all the invariants of its ancestor classes (A in this case). 2. Are we talking here about adding checks that would run in > production code? Wouldn't that slow code down? How do I deal with the > conflict between wanting tighter checks but not wanting to pay the > cost at runtime of checking things that should never go wrong > (contracts, as I understand it, are for protecting against code bugs, > that's why there's no facility for trapping them and producing "user > friendly" error messages)? I use assertions very sparingly in > production code for precisely that reason - why would I be more > willing to use contracts? There is no way you can use contracts without slowing down the program (as they still needs to be verified at run-time). People who need the production code to run as fast as possible need to disable the contracts (and assertions) altogether. If contracts were fast to be verified (for example, by in-lining the checks into the function body instead of calling a separate function), the cost of many contracts might be still acceptable in the production code. Mind that there is also a gradation: there might be contracts which are simply always too slow to run in production (*e.g., *check that the input or output is sorted) while others are almost always acceptable (*e.g., *check that the input arguments are positive integers or one argument is smaller than the other). There is usually a switch mechanism that allows the developer to turn off certain contracts while still enforcing the others. Please mind that the benefits of the contracts are threefold and are not only reduced to "better assertions": * They allow us to formally write down the assumptions about the input and output of the functions and invariants of the data structures. * They verify these assumptions automatically in all possible cases at run-time (be it during the development or during the production). A smaller set of unit tests hence tests a larger portion of the code then if there were no contracts. * They can be used by downstream tools to automatically generate unit tests and perform static analysis. Imagine if you could just click on a class in Pycharm and generate unit tests for all of its methods automatically within couple of seconds. While these might not cover every use case, this feature would allow you to cover many cases with practically zero work. I don't see how such a tool could be developed without a standardized approach to contracts in python (be it a library or a language construct). @David Mertz: > Related to the text I emphasized, would you mind to explain a bit more >> in-depth which features you have in mind? I see contracts formally written >> out and automatically verified as a completely indispensable tool in large >> projects with multiple people involved. >> > > This much is rather self-evidently untrue. There are hundreds or > thousands of large projects involving multiple people, written in Python, > that have succeeded without using contracts. That suggests the feature is > not "completely indispensable" since it was dispensed with in the vast > majority of large projects. > Sorry, David, my bad; English is not my first language. What I meant to say is that I, as in "personally", could not see how I would tackle a large project with a bigger team with a variety of skill levels in efficient manner without a tool to formally write down the assumptions and have them automatically verified. I do understand that achieving large projects is evidently possible without contracts (and many other tools such as static type checks, assertions, and even unit testing). In my case, I would have a much higher overhead working in a team where the assumptions are written in the documentation and never verified since many bugs and obsolete documentation would just go unnoticed. Doing refactoring or adding new features would be hence much more costly for my team and me. Maybe this is also due to the fact that you refer to frameworks when you refer to "large projects" with many experienced and highly skilled contributors. The developers are most probably keen to update the documentation and thoroughly test the framework and also test the assumptions in combinatorial manner. In contrast, I work on a (larger) project where the comments actually become obsolete almost at the moment we wrote them and the testing budget is limited due to time constraints and non-critical application domain. At present, we are not developing a framework used by many other developers, but a solution based on computer vision. We can live with incorrect code, but it's good that it is as correct as it gets. Personally, I view contracts as a way to improve substantially the correctness of the code with very little overhead. In addition, contracts seem to lead to better and more maintainable code since people actually need to reflect more on the assumptions and write them down formally. This is, of course, a completely subjective impression based on my anecdotal experience. Let me see if I can make the inheritance work with meta-programming and extra magical members (__preconditions__, __postconditions__, __invariants__). Let's consider the icontract library a test case, and then see how much more work would it be to bring it into the standard library. @Steve D'Aprano: could you maybe point us to a couple of studies showing that design-by-contract is beneficial in practice? Cheers, Marko On Thu, 30 Aug 2018 at 13:22, David Mertz wrote: > On Thu, Aug 30, 2018 at 3:44 AM Marko Ristin-Kaufmann < > marko.ristin at gmail.com> wrote: > >> Related to the text I emphasized, would you mind to explain a bit more >> in-depth which features you have in mind? I see contracts formally written >> out and automatically verified as a completely indispensable tool in large >> projects with multiple people involved. >> > > This much is rather self-evidently untrue. There are hundreds or > thousands of large projects involving multiple people, written in Python, > that have succeeded without using contracts. That suggests the feature is > not "completely indispensable" since it was dispensed with in the vast > majority of large projects. > > I think that most of these large projects succeed in large part because > they have good *unit tests*. There are several popular frameworks for > writing these (some in standard library), but notably none of them require > specific syntax changes to make them work. Some of them *do* use DSLs of > sorts as part of how they operate (or various metaprogramming and > introspection magic). There is a whole lot of overlap between what unit > tests do and what design-by-contract does, enough so that I believe the > latter adds little to a large project (of course you can come up with some > specific example that a unit test cannot verify as well as a > pre/postcondition. > > In writing before about "features" (and Paul Moore) does a better job than > me in writing about *costs*, I wasn't discussing design-by-contract > specifically. Various new feature ideas come up here and elsewhere. A few > are accepted, most are rejected. They all need to be compared to costs > like those I mention before their possible advantages can win out. > > Yours, David... > > -- > Keeping medicines from the bloodstreams of the sick; food > from the bellies of the hungry; books from the hands of the > uneducated; technology from the underdeveloped; and putting > advocates of freedom in prisons. Intellectual property is > to the 21st century what the slave trade was to the 16th. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ethan at stoneleaf.us Thu Aug 30 17:01:18 2018 From: ethan at stoneleaf.us (Ethan Furman) Date: Thu, 30 Aug 2018 14:01:18 -0700 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: References: <5B875DDE.2030308@stoneleaf.us> Message-ID: <5B885B1E.30806@stoneleaf.us> On 08/30/2018 01:49 PM, Marko Ristin-Kaufmann wrote: > classC(A): > # C.some_func also inherits the contracts from A. > # It weakens the precondition: > # it operates either on sorted lists OR > # the lists that are shorter than 10 elements. > # > # It strenghthens the postcondition: > # It needs to return an integer larger than > # the length of the input list AND > # the result needs to be divisible by 2. > @icontract.post(lambdaresult: result %2==0) > defsome_func(self, lst: List[int]) ->int: > # ... I think you forgot an @icontract.pre() here. -- ~Ethan~ From greg.ewing at canterbury.ac.nz Thu Aug 30 18:24:32 2018 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Fri, 31 Aug 2018 10:24:32 +1200 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <00acb756cab343ee80274f5de606572d@xmail103.UGent.be> <5B8786CE.4070604@UGent.be> <5B8789C3.6020803@canterbury.ac.nz> <5B8797C7.2080303@canterbury.ac.nz> <5B87B852.1070705@canterbury.ac.nz> Message-ID: <5B886EA0.3050102@canterbury.ac.nz> Neil Girdhar wrote: > Powers of other numbers have to keep the same behavior since in general > those kinds of expressions don't create rational numbers. There are infinitely many other rational numbers that *could* be given the same treatment, though, e.g. (-8) ** (2/3). If you don't want to include those you'll have to explain your rationale. -- Greg From wes.turner at gmail.com Thu Aug 30 18:28:37 2018 From: wes.turner at gmail.com (Wes Turner) Date: Thu, 30 Aug 2018 18:28:37 -0400 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B885B1E.30806@stoneleaf.us> References: <5B875DDE.2030308@stoneleaf.us> <5B885B1E.30806@stoneleaf.us> Message-ID: def example_func(x, y): def __assert_before__(example_func): #implicit, AST-able assertion expressions # ... code def __assert_after__(example_func): # def __assert_after__invariants_02(example_func): # " But these need to be composed / mixed in in MRO order and overridable; more like a class with a __call__() and metaclassery for source-order composition that has to do substring matches for e.g. __assert__*. Blocks of expressions identified with keywords wouldn't be overrideable ('relaxed',); and would need to do fancy AST that replicates existing MRO? On Thursday, August 30, 2018, Ethan Furman wrote: > On 08/30/2018 01:49 PM, Marko Ristin-Kaufmann wrote: > > classC(A): >> # C.some_func also inherits the contracts from A. >> # It weakens the precondition: >> # it operates either on sorted lists OR >> # the lists that are shorter than 10 elements. >> # >> # It strenghthens the postcondition: >> # It needs to return an integer larger than >> # the length of the input list AND >> # the result needs to be divisible by 2. >> @icontract.post(lambdaresult: result %2==0) >> defsome_func(self, lst: List[int]) ->int: >> # ... >> > > I think you forgot an @icontract.pre() here. > > -- > ~Ethan~ > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jamtlu at gmail.com Thu Aug 30 20:14:40 2018 From: jamtlu at gmail.com (James Lu) Date: Thu, 30 Aug 2018 20:14:40 -0400 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> Message-ID: > Rather, > because Python has become a big and very complete programming > environment, and a fairly large language, implementing new syntax > requires that a feature increase expressiveness substantially. That makes sense. > By comparison, > x, y += a, b > is neither more expressive, nor easier to read, nor significantly > harder to type, than > > x += a > y += b I agree. I contend that x, y += func(...) is more readable than the three- statement alternative with a namespace pollution. On Tue, Aug 28, 2018 at 4:05 AM Stephen J. Turnbull < turnbull.stephen.fw at u.tsukuba.ac.jp> wrote: > Executive summary: Much of this is my opinion, and as a newer poster, > your opinion is *more* valuable than mine (fresh eyes and all that). > What I hope you'll take from this post is a more precise understanding > of the customary criteria that are used in evaluating a proposed > feature on python-ideas and python-dev. > > Apologies for breaking the thread, but per Subject it's not really part > of the thread. > > James Lu writes: > > > I could, but I don't think that justifies not having this > > functionality in python standard. > > What's "this"? Note: > > >> When replying, please edit your Subject line so it is more specific > >> than "Re: Contents of Python-ideas digest..." > > I had to edit the Subject. I'm going to assume you mean > > >> 1. Re: Unpacking iterables for augmented assignment (Matthew Einhorn) > > So. The Python development community generally doesn't require > justification for refusing to implement new functionality. Rather, > because Python has become a big and very complete programming > environment, and a fairly large language, implementing new syntax > requires that a feature increase expressiveness substantially. > > In the case in point, the destructuring assignments > > a, b = b, a > w, x, y, z = z, w, y, x > > can be interpreted as "swapping" or "permuting", and AIUI that's why > they were included. They express the intent better than > > tmp = a > a = b > b = tmp > del tmp > > and I don't want to even think about how to do the 4-variable version > without 4 temporary variables. By comparison, > > x, y += a, b > > is neither more expressive, nor easier to read, nor significantly > harder to type, than > > x += a > y += b > > as far as I can see. Note that this is the "not harder to type" > criterion normally used in discussing new Python features, not > something I've invented. > > > This is something I think most students will expect while learning > > python, especially if they're implementing algorithms. > > I suppose this claim is unlikely to be accepted without testimony of > several teachers of Python. In my own experience, I explicitly teach > my students that the destructuring assignment is *for* permuting, and > I have *not even once* been asked if it works for augmented > assignments. By contrast, students with knowledge of other languages > (especially C-like languages) invariably "just use" augmented > assignments and ask if there's some spelling for increment and > decrement expressions. Obviously, my teaching approach biases the > result, but if nobody ever overcomes that bias, I do not think it is > an expected or needed feature. > > Steve > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Thu Aug 30 20:27:50 2018 From: mertz at gnosis.cx (David Mertz) Date: Thu, 30 Aug 2018 20:27:50 -0400 Subject: [Python-ideas] On evaluating features [was: Unpacking iterables for augmented assignment] In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> Message-ID: In 20 years of programming Python, I have never wanted to augment two distinct variables by two distinct return values from a function. I'm sure it's possible to construct some situation where that would be convenient, and presumably the OP actually encountered that. But the need is exceedingly rare, and absolutely not worth enabling syntax that is confusing in other ways and introduces inconsistencies in overall semantics. On Thu, Aug 30, 2018, 8:16 PM James Lu wrote: > > Rather, > > > because Python has become a big and very complete programming > > > environment, and a fairly large language, implementing new syntax > > > requires that a feature increase expressiveness substantially. > That makes sense. > > > By comparison, > > x, y += a, b > > > is neither more expressive, nor easier to read, nor significantly > > > harder to type, than > > > > > > x += a > > > y += b > I agree. I contend that x, y += func(...) is more readable than the three- > statement alternative with a namespace pollution. > > > On Tue, Aug 28, 2018 at 4:05 AM Stephen J. Turnbull < > turnbull.stephen.fw at u.tsukuba.ac.jp> wrote: > >> Executive summary: Much of this is my opinion, and as a newer poster, >> your opinion is *more* valuable than mine (fresh eyes and all that). >> What I hope you'll take from this post is a more precise understanding >> of the customary criteria that are used in evaluating a proposed >> feature on python-ideas and python-dev. >> >> Apologies for breaking the thread, but per Subject it's not really part >> of the thread. >> >> James Lu writes: >> >> > I could, but I don't think that justifies not having this >> > functionality in python standard. >> >> What's "this"? Note: >> >> >> When replying, please edit your Subject line so it is more specific >> >> than "Re: Contents of Python-ideas digest..." >> >> I had to edit the Subject. I'm going to assume you mean >> >> >> 1. Re: Unpacking iterables for augmented assignment (Matthew Einhorn) >> >> So. The Python development community generally doesn't require >> justification for refusing to implement new functionality. Rather, >> because Python has become a big and very complete programming >> environment, and a fairly large language, implementing new syntax >> requires that a feature increase expressiveness substantially. >> >> In the case in point, the destructuring assignments >> >> a, b = b, a >> w, x, y, z = z, w, y, x >> >> can be interpreted as "swapping" or "permuting", and AIUI that's why >> they were included. They express the intent better than >> >> tmp = a >> a = b >> b = tmp >> del tmp >> >> and I don't want to even think about how to do the 4-variable version >> without 4 temporary variables. By comparison, >> >> x, y += a, b >> >> is neither more expressive, nor easier to read, nor significantly >> harder to type, than >> >> x += a >> y += b >> >> as far as I can see. Note that this is the "not harder to type" >> criterion normally used in discussing new Python features, not >> something I've invented. >> >> > This is something I think most students will expect while learning >> > python, especially if they're implementing algorithms. >> >> I suppose this claim is unlikely to be accepted without testimony of >> several teachers of Python. In my own experience, I explicitly teach >> my students that the destructuring assignment is *for* permuting, and >> I have *not even once* been asked if it works for augmented >> assignments. By contrast, students with knowledge of other languages >> (especially C-like languages) invariably "just use" augmented >> assignments and ask if there's some spelling for increment and >> decrement expressions. Obviously, my teaching approach biases the >> result, but if nobody ever overcomes that bias, I do not think it is >> an expected or needed feature. >> >> Steve >> >> _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jamtlu at gmail.com Thu Aug 30 20:30:23 2018 From: jamtlu at gmail.com (James Lu) Date: Thu, 30 Aug 2018 20:30:23 -0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? Message-ID: Why shouldn't Python be better at implementing Domain Specific Languages? >From Johnathan Fine: > I really do wish we could have language that had all of Ruby's > strengths, and also all of Python's. That would be really nice. Quite > something indeed. > Languages do influence each other. Ruby is good at internal Domain > Specific Languages (DSLs). And there's Perrotta's influential book on > Ruby Metaprogramming. That's something I think Python could learn > from. > But I don't see any need (or even benefit) in adding new language > features to Python, so it can do better at DSLs. It would be nice if there was a DSL for describing neural networks (Keras). The current syntax looks like this: model.add(Dense(units=64, activation='relu', input_dim=100)) model.add(Dense(units=10, activation='softmax')) -------------- next part -------------- An HTML attachment was scrubbed... URL: From mike at selik.org Thu Aug 30 21:19:56 2018 From: mike at selik.org (Michael Selik) Date: Thu, 30 Aug 2018 18:19:56 -0700 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Thu, Aug 30, 2018 at 5:31 PM James Lu wrote: > It would be nice if there was a DSL for describing neural networks (Keras). > > model.add(Dense(units=64, activation='relu', input_dim=100)) > model.add(Dense(units=10, activation='softmax')) > > Why not JSON or XML for cross-language compatibility? -------------- next part -------------- An HTML attachment was scrubbed... URL: From guido at python.org Thu Aug 30 21:40:22 2018 From: guido at python.org (Guido van Rossum) Date: Fri, 31 Aug 2018 03:40:22 +0200 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Fri, Aug 31, 2018 at 3:19 AM, Michael Selik wrote: > On Thu, Aug 30, 2018 at 5:31 PM James Lu wrote: > >> It would be nice if there was a DSL for describing neural networks >> (Keras). >> >> model.add(Dense(units=64, activation='relu', input_dim=100)) >> model.add(Dense(units=10, activation='softmax')) >> >> > Why not JSON or XML for cross-language compatibility? > Presumably because those are even harder to read and write for humans. I believe that the key issue with using Python as a DSL has to do with its insistence on punctuation -- the above example uses nested parentheses, commas, equal signs, and quotation marks. Those are in general needed to avoid ambiguities, but DSLs are often highly stylized, and a language that doesn't need them has a certain advantage. For example if a shell-like language was adopted, the above could probably be written with spaces instead of commas, parentheses and equal signs, and dropping the quotes (though perhaps it would be more readable if the equal signs were kept). I'm not sure how we would go about this though. IIRC there was a proposal once to allow top-level function calls to be written without parentheses, but it was too hard to make it unambiguous (e.g. would "foo +1" mean "foo(+1)" or "foo + 1"?) -- --Guido van Rossum (python.org/~guido) -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Thu Aug 30 22:04:13 2018 From: mertz at gnosis.cx (David Mertz) Date: Thu, 30 Aug 2018 22:04:13 -0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Thu, Aug 30, 2018 at 9:41 PM Guido van Rossum wrote: > On Fri, Aug 31, 2018 at 3:19 AM, Michael Selik wrote: > >> On Thu, Aug 30, 2018 at 5:31 PM James Lu wrote: >> >>> It would be nice if there was a DSL for describing neural networks >>> (Keras). >>> >>> model.add(Dense(units=64, activation='relu', input_dim=100)) >>> model.add(Dense(units=10, activation='softmax')) >>> >>> >> Why not JSON or XML for cross-language compatibility? >> > > Presumably because those are even harder to read and write for humans. > Guido is absolutely right (as usual) that JSON or XML would be *vastly* harder to read than that very clean Python code. That said, if you wanted a "DSL", the perfect choice would be YAML. The description above could look like this: >>> model = ''' ... model: ... - layer: Dense ... units: 64 ... activation: relu ... input_dim: 100 ... - layer: Dense ... units: 10 ... activation: softmax ... ''' >>> yaml.load(model) {'model': [{'layer': 'Dense', 'units': 64, 'activation': 'relu', 'input_dim': 100}, {'layer': 'Dense', 'units': 10, 'activation': 'softmax'}]} This format could easily be either a string within a Python program or an external file with the definition. YAML is already well supported in Python, all you'd need to do is write a little wrapper to translate the description above into the actual Keras API calls, which would be pretty easy. -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. -------------- next part -------------- An HTML attachment was scrubbed... URL: From marko.ristin at gmail.com Fri Aug 31 00:05:28 2018 From: marko.ristin at gmail.com (Marko Ristin-Kaufmann) Date: Fri, 31 Aug 2018 06:05:28 +0200 Subject: [Python-ideas] Pre-conditions and post-conditions In-Reply-To: <5B885B1E.30806@stoneleaf.us> References: <5B875DDE.2030308@stoneleaf.us> <5B885B1E.30806@stoneleaf.us> Message-ID: Hi Ethan, You are right, I deleted it without noticing. It should say: pre(len(lst) < 10). Le jeu. 30 ao?t 2018 ? 23:02, Ethan Furman a ?crit : > On 08/30/2018 01:49 PM, Marko Ristin-Kaufmann wrote: > > > classC(A): > > # C.some_func also inherits the contracts from A. > > # It weakens the precondition: > > # it operates either on sorted lists OR > > # the lists that are shorter than 10 elements. > > # > > # It strenghthens the postcondition: > > # It needs to return an integer larger than > > # the length of the input list AND > > # the result needs to be divisible by 2. > > @icontract.post(lambdaresult: result %2==0) > > defsome_func(self, lst: List[int]) ->int: > > # ... > > I think you forgot an @icontract.pre() here. > > -- > ~Ethan~ > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From guido at python.org Fri Aug 31 00:07:50 2018 From: guido at python.org (Guido van Rossum) Date: Fri, 31 Aug 2018 06:07:50 +0200 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Fri, Aug 31, 2018 at 4:04 AM, David Mertz wrote: > On Thu, Aug 30, 2018 at 9:41 PM Guido van Rossum wrote: > >> On Fri, Aug 31, 2018 at 3:19 AM, Michael Selik wrote: >> >>> On Thu, Aug 30, 2018 at 5:31 PM James Lu wrote: >>> >>>> It would be nice if there was a DSL for describing neural networks >>>> (Keras). >>>> >>>> model.add(Dense(units=64, activation='relu', input_dim=100)) >>>> model.add(Dense(units=10, activation='softmax')) >>>> >>>> >>> Why not JSON or XML for cross-language compatibility? >>> >> >> Presumably because those are even harder to read and write for humans. >> > > Guido is absolutely right (as usual) that JSON or XML would be *vastly* > harder to read than that very clean Python code. > > That said, if you wanted a "DSL", the perfect choice would be YAML. > Hm. YAML is indeed a great, readable alternative to JSON or XML. But the term DSL implies (to me) more than just nested key-value pairs. (Though who knows maybe that's all Keras needs, and then it's a poor argument for having a DSL.) Then again maybe I'm confusing DSL (which appears to be a Rubyism) with "little language": http://wiki.c2.com/?LittleLanguage -- --Guido van Rossum (python.org/~guido) -------------- next part -------------- An HTML attachment was scrubbed... URL: From mertz at gnosis.cx Fri Aug 31 00:23:11 2018 From: mertz at gnosis.cx (David Mertz) Date: Fri, 31 Aug 2018 00:23:11 -0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Fri, Aug 31, 2018, 12:08 AM Guido van Rossum wrote: > Hm. YAML is indeed a great, readable alternative to JSON or XML. But the > term DSL implies (to me) more than just nested key-value pairs. (Though who > knows maybe that's all Keras needs, and then it's a poor argument for > having a DSL.) > Keras is deliberately very declarative in defining models. So indeed sequences and mappings and scalars is everything it needs. Maybe I'll actually implement the idea I sketch out in a small independent library. Then again maybe I'm confusing DSL (which appears to be a Rubyism) with > "little language": http://wiki.c2.com/?LittleLanguage > I'm pretty sure I heard "DSL" before Ruby existed. Definitely before Ruby entered my consciousness as another neat language. I don't really care whether a DSL needs to be Turing complete, but I think many such are used primary declaratively. Mostly though I was pointing out that Keras doesn't need flow and branching for it's model definitions. -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Fri Aug 31 01:34:41 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Fri, 31 Aug 2018 15:34:41 +1000 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: <20180831053440.GK27312@ando.pearwood.info> On Fri, Aug 31, 2018 at 03:40:22AM +0200, Guido van Rossum wrote: > On Fri, Aug 31, 2018 at 3:19 AM, Michael Selik wrote: > > > On Thu, Aug 30, 2018 at 5:31 PM James Lu wrote: > > [James] > >> It would be nice if there was a DSL for describing neural networks > >> (Keras). > >> > >> model.add(Dense(units=64, activation='relu', input_dim=100)) > >> model.add(Dense(units=10, activation='softmax')) Is there something wrong with that style? I'm not sure what syntax you would consider an improvement. [Michael] > > Why not JSON or XML for cross-language compatibility? James dodn't mention cross-language compatibility, he presumably wants a better way to write machine learning code. Being able to exchange data from one application to another is great. Having to write your code as XML is not. [Guido] > Presumably because those are even harder to read and write for humans. Indeed. One criticism of XML is that it is the hammer which leads people to treat every problem as a nail. "Just use XML". Now you have two problems *wink* > I believe that the key issue with using Python as a DSL has to do with its > insistence on punctuation -- the above example uses nested parentheses, > commas, equal signs, and quotation marks. Those are in general needed to > avoid ambiguities, but DSLs are often highly stylized, and a language that > doesn't need them has a certain advantage. Right -- especially for imperative-style code. I'm reminded of an example from Leo Brodie's classic "Learning Forth", the top level application in an embedded washing machine controller: WASH SPIN RINSE SPIN That sort of punctuation-free imperative code elegantly matches the way we might right it down as a list of commands. > For example if a shell-like > language was adopted, the above could probably be written with spaces > instead of commas, parentheses and equal signs, and dropping the quotes > (though perhaps it would be more readable if the equal signs were kept). > > I'm not sure how we would go about this though. IIRC there was a proposal > once to allow top-level function calls to be written without parentheses, > but it was too hard to make it unambiguous (e.g. would "foo +1" mean > "foo(+1)" or "foo + 1"?) Please no, Ruby has that, and the meaning of expressions depends on whether you put whitespace around operators or not. Given: def a(x=4) x+2 end b = 1 the result of "a+b" depends on the spaces around the plus sign: irb(main):005:0> a + b => 7 irb(main):006:0> a +b => 3 -- Steve From harlowja at fastmail.com Fri Aug 31 01:43:31 2018 From: harlowja at fastmail.com (Joshua Harlow) Date: Thu, 30 Aug 2018 22:43:31 -0700 Subject: [Python-ideas] Extend the warnings module with Deprecation utility methods and classes In-Reply-To: <4f5db5c5-7092-4c0c-8e0f-49504f08a99e@googlegroups.com> References: <4f5db5c5-7092-4c0c-8e0f-49504f08a99e@googlegroups.com> Message-ID: <5B88D583.1090802@fastmail.com> If you want, feel free to take some of the code from: https://docs.openstack.org/debtcollector/latest/reference/index.html It was made for a similar purpose (and uses warnings module at its lowest level) and may offer some things that could be in this new warnings module. Code is at: https://git.openstack.org/cgit/openstack/debtcollector And mirrored at https://github.com/openstack/debtcollector -Josh From mike at selik.org Fri Aug 31 02:24:21 2018 From: mike at selik.org (Michael Selik) Date: Thu, 30 Aug 2018 23:24:21 -0700 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Thu, Aug 30, 2018, 9:23 PM David Mertz wrote: > On Fri, Aug 31, 2018, 12:08 AM Guido van Rossum wrote: > >> Hm. YAML is indeed a great, readable alternative to JSON or XML. But the >> term DSL implies (to me) more than just nested key-value pairs. (Though who >> knows maybe that's all Keras needs, and then it's a poor argument for >> having a DSL.) >> > > Keras is deliberately very declarative in defining models. So indeed > sequences and mappings and scalars is everything it needs. Maybe I'll > actually implement the idea I sketch out in a small independent library. > Defining Keras models reminds me of the ugly ASP code I'd sometimes write to create HTML in an object-oriented fashion. Writing plain HTML was usually more pleasant and readable. I suggested XML with that memory in mind. It's cumbersome for many tasks, but Keras models in particular might be a good fit. Or YAML. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Fri Aug 31 03:14:35 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Fri, 31 Aug 2018 11:14:35 +0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: i believe a DSL is simple enough for an enthusiastic py programmer to write if you really wanted one just write the tasks you need to accomplish, the data needed, the constrcuts needed (if needed), the feel/look of it on your editor plan first, come up with a good mock, then implement it. implementation is easy, ideas are hard. good ideas offload the efforts on the implementation side, they can also save you future troubles let me take an example : a DSL to calculate the cost of houses aim : calculate cost of houses input : num of houses price of house output : price of houses technical tasks : show to screen it might go on like that --- file --- house num 1,000 house price 250,000 calculate sum --- output --- $ 250 000 000 in the above example, assumptions were made and functions crammed but you have a dsl. real-life dsls are not far from the specs of this one but differ in the tools used Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From turnbull.stephen.fw at u.tsukuba.ac.jp Fri Aug 31 03:25:07 2018 From: turnbull.stephen.fw at u.tsukuba.ac.jp (Stephen J. Turnbull) Date: Fri, 31 Aug 2018 16:25:07 +0900 Subject: [Python-ideas] On evaluating features In-Reply-To: References: <23429.581.322785.398472@turnbull.sk.tsukuba.ac.jp> Message-ID: <23432.60755.35287.191477@turnbull.sk.tsukuba.ac.jp> Executive summary: Although I'm obviously not particularly in favor of this feature, my opinion is no more valuable than anyone else's. The point of this post is to show how features have been advocated successfully in the past. James Lu writes: > > By comparison, > > > > x, y += a, b > > > > is neither more expressive, nor easier to read, nor significantly > > harder to type, than > > > > x += a > > y += b > > I agree. I contend that x, y += func(...) is more readable than the three- > statement alternative with a namespace pollution. I'm sure it is. But what's the context? That is, just saying you think it's more readable isn't enough. What has succeeded in the past (in approximate order of effectiveness) has been 1. A reasonably comprehensive survey of the Python stdlib to find use cases for the "ugly" construct, and then providing a few "side by side" comparisons "before and after" the new syntax, as well as statistics for the frequency of the "ugly" construct, and how often translation to the new feature improved the code. 2. A similar exercise for some other large, reasonably well-known code base by a respected project. 3. A few examples from some code base. Here's an example of the kind of analysis I mean. I went looking for examples of swaps in the Python sources by grepping for "sort". I found several in Tools/demo/sortvisu.py, but strangely enough, although it uses sequence assignment for the swap, it does this: def swap(self, i, j): if i == j: return self.countswap() item = self.items[i] other = self.items[j] self.items[i], self.items[j] = other, item item.swapwith(other) The reason is that this is not a sorting application as such, but rather a demo of tkinter. So the sort is instrumented in several ways, and in particular the items being swapped know "where they are" in the visualization (the item.swapwith(other) call). Thus the temporary variables item and other are not spurious. I'm not sure if I think def swap(self, i, j): if i == j: return self.countswap() item, other = self.items[i], self.items[j] self.items[i], self.items[j] = other, item item.swapwith(other) is less readable, but I don't think it's more readable. And with the instrumentation removed, I'm not sure whether I prefer def swap(self, i, j): if i == j: return self.items[i], self.items[j] = self.items[j], self.items[i] or def swap(self, i, j): if i == j: return item, other = self.items[i], self.items[j] self.items[i], self.items[j] = other, item It's pretty marginal. Finally, I think if i != j: self.items[i], self.items[j] = self.items[j], self.items[i] inlined instead of self.swap(i, j) perceptibly harms readability, although it would be somewhat faster due to eliminating the function call, and if speed were at a premium I would prefer the inline swap to the introduction of any temporary variables.[1] My guess is that a lot of realistic cases where you apparently *could* use augmented assignment of sequences to avoid introducing one or more temporary variables are going to have some of the same features that the variables are actually useful beyond the augmented assignment, or the expressions on one side of the assignment or both are sufficiently complex that introducing the temporary variable with a descriptive name improves readability. But the proof of that will be in doing the work. Steve Footnotes: [1] And if you're reading this, Victor, of course I'd benchmark before using the less readable version in production. :-) From mistersheik at gmail.com Fri Aug 31 03:25:57 2018 From: mistersheik at gmail.com (Neil Girdhar) Date: Fri, 31 Aug 2018 03:25:57 -0400 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: <20180830130150.GI27312@ando.pearwood.info> References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> <20180830130150.GI27312@ando.pearwood.info> Message-ID: On Thu, Aug 30, 2018 at 9:03 AM Steven D'Aprano wrote: > On Wed, Aug 29, 2018 at 09:39:05PM -0700, Neil Girdhar wrote: > > > Would there be any problem with changing: > > > > In [4]: Fraction(1, 1) ** Fraction(2, 3) > > Out[4]: 1.0 > > > > In [5]: Fraction(-1, 1) ** Fraction(2, 3) > > Out[5]: (-0.4999999999999998+0.8660254037844387j) > > > > In [6]: Fraction(0, 1) ** Fraction(2, 3) > > Out[6]: 0.0 > > > > I'd like these to be Fraction(1), Fraction(1), and Fraction(0). > > If anyone else has mentioned the backward-compatibility issue by now, I > haven't see it. I believe that would make it a fairly big problem. > > I don't think it's that big a problem since Fraction < numbers.Real > I expect that there is code out in the wild which (for good or ill) now > expects 1**Fraction(2, 3) to return 1.0, rather than Fraction(1), and > similarly for the other examples. Changing that could break people's > code. > > Even if we had consensus that this was a good idea, or at least > consensus from the maths-folk who care about this sort of thing (I'd > like to know what Uncle Timmy and Mark think of this idea), it would > still probably need a "__future__" import to activate it, or a > deprecation period. Or some other annoyance. > > Possibly the simpler approach would be to add a subclass that does what > you want. UnitRootFraction or something. > > Then the only argument will be whether such a subclass ought to go into > the fractions module, or your own personal toolkit :-) > > I must admit though, I'm a bit curious as to what you are doing that > having 1**Fraction(2,3) return 1.0 is an annoyance, but having > 27**Fraction(2,3) return 8.999999999999998 instead of Fraction(9) isn't. > > You're right, it would have been better in my example (linked above) to support all of those things. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > > -- > > --- > You received this message because you are subscribed to a topic in the > Google Groups "python-ideas" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/python-ideas/aZIHpPhe0mw/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > python-ideas+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.f.moore at gmail.com Fri Aug 31 05:12:31 2018 From: p.f.moore at gmail.com (Paul Moore) Date: Fri, 31 Aug 2018 10:12:31 +0100 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: <20180831053440.GK27312@ando.pearwood.info> References: <20180831053440.GK27312@ando.pearwood.info> Message-ID: On Fri, 31 Aug 2018 at 06:36, Steven D'Aprano wrote: > Please no, Ruby has that, and the meaning of expressions depends on > whether you put whitespace around operators or not. > > Given: > > def a(x=4) > x+2 > end > b = 1 > > the result of "a+b" depends on the spaces around the plus sign: > > irb(main):005:0> a + b > => 7 > irb(main):006:0> a +b > => 3 Ewww. And people complain about *python's* use of significant whitespace???!?!! Paul From jfine2358 at gmail.com Fri Aug 31 06:13:00 2018 From: jfine2358 at gmail.com (Jonathan Fine) Date: Fri, 31 Aug 2018 11:13:00 +0100 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: <20180831053440.GK27312@ando.pearwood.info> Message-ID: James Lu started this thread by quoting me. Thank you, James, for the compliment. And I feel somewhat obliged to contribute here, are at removed I started the thread. In the message James quoted, I also said But most strengths, in another situation, can be a weakness. Language design is often a compromise between conciseness and readability, ease of use and performance, good for beginners and good for experts, and many other factors. Such as innovation and stability. Guido's decisions, as BDFL, have shaped Python and its community into what it is now. It is one set of compromises. Other languages, such as Ruby, have made different compromises. Now that the BDFL is on vacation, the challenge is to maintain the essence of Python while continuing to innovate. It's important, of course, for the developers of a DSL to understand the domain. I'm starting to learn http://elm-lang.org/. It describes itself as > A delightful language for reliable webapps. > Generate JavaScript with great performance and no runtime exceptions. The Elm developers have learnt a great deal from Python, and I think that we in turn can learn from them. Particularly about catching coding errors early, with good feedback. But that's a different thread. So I'd say to focus on improving the API to an existing library is a good way to develop our understanding of DSLs more generally. James provided a Keras example model.add(Dense(units=64, activation='relu', input_dim=100)) model.add(Dense(units=10, activation='softmax')) What might be better here, if allowed, is model.extend([ Dense(units=64, activation='relu', input_dim=100), Dense(units=10, activation='softmax'), ]) Another approach would be to provide a fluent interface. https://martinfowler.com/bliki/FluentInterface.html https://en.wikipedia.org/wiki/Fluent_interface Done this want, we might get something like jQuery ( model .dense(units=64, activation='relu', input_dim=100) .dense(units=10, activation='softmax') ) JSON and XML and YAML have already been mentioned. Here's another, XML-ish approach. A combined list-dictionary is quite common. It's used widely in XML (and SGML before it). So how to create such. A few years ago I experimented with an API such as A(a=1, b=2)[ X(1, 2, 3), Y[ ....], ] As I recall, someone told me that https://kivy.org does something similar. Kivi and Elm, are systems I'd like to learn. Ease of use is important in language and library design. We can learn from the success of others, as well as from our own successes and failures (smile). -- Jonathan From ja.py at farowl.co.uk Fri Aug 31 04:00:17 2018 From: ja.py at farowl.co.uk (Jeff Allen) Date: Fri, 31 Aug 2018 09:00:17 +0100 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: <64623712-6137-e773-9fa4-1d9d1265ee21@farowl.co.uk> The word "domain" appears in this sense on the first page of Aho and Ullman and ANTLR (which I know you've used) describes itself as a tool for building domain-specific languages. Both pre-date Ruby I'm fairly sure. James Lu, quoting Jonathan Fine, used the term "internal DSL" and although that's new to me, people seem to be interpreting it in the sense that Gradle is a Groovy DSL (note caps), a build tool a lot of software developers will be familiar with. In that case, what you write really is Groovy, but the execution environment has been pre-conditioned with objects and libraries that (almost) make a new language. When you understand what's going on (not sure I always do), it becomes possible to mix Gradle statements and Groovy freely. The most immediate benefit is that all the apparatus of expressions and types/methods is already present. So "internal" is the key word. The point about punctuation is spot-on, I think: Groovy is relatively free of (makes optional) some punctuation, including the parentheses that make calls easily identifiable in Python. So quite possibly starting from Python is limiting if what you want is an*internal* DSL with a grammar you choose: the object system is fantastic-plastic, but the grammar is not. DSLs embedded in Python are common, of course (f-strings, regexes, SQL), and DSLs can generate Python from fragments with almost no constraints on their own grammar. iPython strikes me as possibly a Python internal DSL, or Django, but what they've done does not take us far from pure Python. Jeff Allen On 31/08/2018 05:07, Guido van Rossum wrote: > > Hm. YAML is indeed a great, readable alternative to JSON or XML. But > the term DSL implies (to me) more than just nested key-value pairs. > (Though who knows maybe that's all Keras needs, and then it's a poor > argument for having a DSL.) > > Then again maybe I'm confusing DSL (which appears to be a Rubyism) > with "little language": http://wiki.c2.com/?LittleLanguage > > -- > --Guido van Rossum (python.org/~guido ) > -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Fri Aug 31 09:04:00 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Fri, 31 Aug 2018 17:04:00 +0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: <20180831053440.GK27312@ando.pearwood.info> Message-ID: as for elm, you have to look twice not to see the python of it Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From oscar.j.benjamin at gmail.com Fri Aug 31 10:00:13 2018 From: oscar.j.benjamin at gmail.com (Oscar Benjamin) Date: Fri, 31 Aug 2018 15:00:13 +0100 Subject: [Python-ideas] Fix some special cases in Fractions? In-Reply-To: References: <0067a655-4f82-479f-9970-5b72dc079364@googlegroups.com> <20180830130150.GI27312@ando.pearwood.info> Message-ID: On Thu, 30 Aug 2018 at 17:36, Stephan Houben wrote: > > I would also like to point out that the current behavior of Fraction > is consistent with other parts of the numeric system, e.g. > 1/1 produces 1.0 (rather than 1) > math.sqrt(4) produces 2.0 (rather than 2) > 1j-1j produces 0j (rather than 0.0 or 0) > > So in general the type of the output is determined by what > the operation would in general return for that input type, > as opposed to a more specific type which only applies > to the specific input value. An exception is integer exponentiation: >>> 1 ** 1 1 >>> 1 ** -1 1.0 Given two rationals q1 and q2 usually q1 ** q2 will not be a rational number. Integer exponentiation results in an integer for half of all possible integer pairs. To do the same with Fraction(a, b) ** Fraction(c, d) would require verifying that both a and b have exact integer dth roots which is more complicated than simply checking the sign of an integer exponent. The extra complexity would slow things down a bit but then again the fractions module is there for precisely those people who are happy to have substantial slow-down for the sake of exactness. >From a backwards compatibility perspective the old behaviour would still be available in a way that works already: float(q1) ** float(q2). Also it would also be straight-forward to implement this given the integer maths (iroot etc) functions that were discussed in a recent thread on this list: https://mail.python.org/pipermail/python-ideas/2018-July/051917.html However: Why would you do this operation if you wanted an exact result? I have at some point wanted (for ints or Fractions) a function root(q, n) that gives an exact root or an error. This proposal would mean that q1 ** q2 would be exact occasionally and would return a float the rest of the time though. If you care about exactness/accuracy in the code you write then it is not okay to be unsure whether your variable is float or Fraction. You need to know because it makes a big difference to how you calculate things (it isn't generally possible to write optimal polymorphic code over exact/inexact arithmetic). The proposed behaviour would look nicer in an interactive session but might not be any more useful in situations where you *really* care about exactness. -- Oscar From jamtlu at gmail.com Fri Aug 31 11:39:16 2018 From: jamtlu at gmail.com (James Lu) Date: Fri, 31 Aug 2018 11:39:16 -0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: <4303FD1F-05F6-4A36-BB41-CAF419DC5922@gmail.com> We should all take a look at Ruby Blocks and think about how Python could benefit from something similar. > On Aug 31, 2018, at 3:14 AM, Abdur-Rahmaan Janhangeer wrote: > > i believe a DSL is simple enough for an enthusiastic py programmer to write if you really wanted one > > just write the tasks you need to accomplish, the data needed, the constrcuts needed (if needed), the feel/look of it on your editor > > plan first, come up with a good mock, then implement it. implementation is easy, ideas are hard. good ideas offload the efforts on the implementation side, they can also save you future troubles > > let me take an example : > > a DSL to calculate the cost of houses > > aim : calculate cost of houses > > input : > num of houses > price of house > > output : > price of houses > > technical tasks : > show to screen > > it might go on like that > > --- file --- > > house num 1,000 > house price 250,000 > calculate sum > > --- output --- > > $ 250 000 000 > > in the above example, assumptions were made and functions crammed but you have a dsl. real-life dsls are not far from the specs of this one but differ in the tools used > > Abdur-Rahmaan Janhangeer > https://github.com/Abdur-rahmaanJ > Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From steve at pearwood.info Fri Aug 31 11:54:33 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 1 Sep 2018 01:54:33 +1000 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: <20180831155433.GL27312@ando.pearwood.info> On Fri, Aug 31, 2018 at 11:14:35AM +0400, Abdur-Rahmaan Janhangeer wrote: > let me take an example : > > a DSL to calculate the cost of houses [...] > --- file --- > house num 1,000 > house price 250,000 > calculate sum > > --- output --- > $ 250 000 000 I don't think the problem is people coming up with DSLs for their problems, but implementing those DSLs. Writing an informal specification is easy; writing the implementation is trickier. For the above, you need an interpreter for the DSL, otherwise it is just a static data file that generates no output at all. -- Steve From steve at pearwood.info Fri Aug 31 12:03:08 2018 From: steve at pearwood.info (Steven D'Aprano) Date: Sat, 1 Sep 2018 02:03:08 +1000 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: <4303FD1F-05F6-4A36-BB41-CAF419DC5922@gmail.com> References: <4303FD1F-05F6-4A36-BB41-CAF419DC5922@gmail.com> Message-ID: <20180831160307.GM27312@ando.pearwood.info> On Fri, Aug 31, 2018 at 11:39:16AM -0400, James Lu wrote: > We should all take a look at Ruby Blocks and think about how Python > could benefit from something similar. You are not the first person to suggest Ruby-like anonymous blocks or multi-statement lambdas. https://duckduckgo.com/?q=python-ideas+ruby+blocks Its not enough to just think about the benefits. We also need to think about the costs, the disadvantages, the possible syntax, and how well it fits into the existing language. If anyone has some new and interesting ideas, that would be fantastic. But if we're just going to rehash the same rejected ideas again, please don't. Python is 20+ years old and the idea of multi-statement anonymous functions has been discussed since before Ruby even existed. -- Steve From kulakov.ilya at gmail.com Fri Aug 31 13:33:30 2018 From: kulakov.ilya at gmail.com (Ilya Kulakov) Date: Fri, 31 Aug 2018 10:33:30 -0700 Subject: [Python-ideas] Extend the warnings module with Deprecation utility methods and classes In-Reply-To: <5B88D583.1090802@fastmail.com> References: <4f5db5c5-7092-4c0c-8e0f-49504f08a99e@googlegroups.com> <5B88D583.1090802@fastmail.com> Message-ID: <87A68A13-F987-4930-B18E-23521CC82211@gmail.com> Very nice, thank you. It would be a good start to collect usage patterns like this as seen in the wild for design consideration and test cases. > On Aug 30, 2018, at 10:43 PM, Joshua Harlow wrote: > > And mirrored at https://github.com/openstack/debtcollector -------------- next part -------------- An HTML attachment was scrubbed... URL: From arj.python at gmail.com Fri Aug 31 14:02:58 2018 From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer) Date: Fri, 31 Aug 2018 22:02:58 +0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: <20180831155433.GL27312@ando.pearwood.info> References: <20180831155433.GL27312@ando.pearwood.info> Message-ID: the implementation is very easy just a program and some ifs if you need more complex, just some reading on tokens etc but the first choice is enough if in py competitions people are solving regex like questions and word extractions without knowing they are solving compiler theory problems, implementing DSL is very easy Abdur-Rahmaan Janhangeer https://github.com/Abdur-rahmaanJ Mauritius -------------- next part -------------- An HTML attachment was scrubbed... URL: From moiein2000 at gmail.com Fri Aug 31 14:57:18 2018 From: moiein2000 at gmail.com (Matthew Einhorn) Date: Fri, 31 Aug 2018 14:57:18 -0400 Subject: [Python-ideas] Why shouldn't Python be better at implementing Domain Specific Languages? In-Reply-To: References: Message-ID: On Thu, Aug 30, 2018 at 8:31 PM James Lu wrote: > Why shouldn't Python be better at implementing Domain Specific Languages? > > [snip] > > It would be nice if there was a DSL for describing neural networks (Keras). > The current syntax looks like this: > > model.add(Dense(units=64, activation='relu', input_dim=100)) > model.add(Dense(units=10, activation='softmax')) > > How about something like this? with model: with Dense() as dense: dense.units = 64 dense.activation = 'relu' dense.input_dim = 100 with Dense() as dense: dense.units = 10 dense.activation = 'softmax' The `with` creates a context to which subsequent layers are added when created within the context. But it does suffer from the fact that the `with` object's (or the underlying stack that would implement this in the model/layers) scope is not local to the function, so if within the `with` context you call a function that creates a layer, the layer will be added to the caller's context, which would be surprising. I was working on a similar approach for a python GUI, and `with` seemed like a very nice candidate, but ran into this issue, which didn't seem to have a clean fix. I also thought about using an decorator that pre-processes the AST for a GUI description, which for your example would look like something like: with model: with Dense(): units = 64 activation = 'relu' input_dim = 100 with Dense(): units = 10 activation = 'softmax' But here the issues are (a) the similarity with local variables may be confusing (b) you'd need to either make all `with` statements special, or annotate the `with` statements that are going to be processed by the compiler (e.g. by prefixing the object with a dash). It seemed messy enough that I'm still pondering this. Matt -------------- next part -------------- An HTML attachment was scrubbed... URL: