Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Christopher Barker
On Wed, Feb 20, 2019 at 10:57 PM Abe Dillon  wrote:

> I wish you would have watched the video I linked
> 
>

that is an hour and 7 minute video! And I did watch some of it, and do
agree with much of it.

By the way, everyone should watch one of Jack Diederich's "naming things
once videos as well:

https://www.youtube.com/watch?v=hZ7hgYKKnF0



>  but in the context of code running off the edge of a window,
>

I never said anything about running off the edge of the window -- if you
put all your parameters on their own line, and don't use insanely long
names, that will not be an issue. Keeping it to 72 chars is virtually never
a problem.


> having the argument list hidden out there
>

nothing hidden about it --it's exactly where a single argument would be --
does anyone advocate putting a single parameter or argument on the next
line?

But my core point really was these are all matter of opiniion, and it's a
godo thing that PEP 8 allows some variation.

> This puts the parameter definitions over on the right, after the function
>> name, where they belong
>
>
> According to whom?
>

According to me, of course. But it is wehre a single parameter would be,
yes?


> [Christopher Baker]
>
>> if you HAVE to put it off to the left for I don't know why, at least put
>> some extra space in there:
>> def a_function_with_lots_of_params(
>> param1,
>> param2,
>> kwarg1=something,
>> kwarg2=something_else):
>> now_a_line_of_code = this_thing()
>> The parameters are still in an odd place, but at least it's clear where
>> the body of the function begins.
>
>
> If you'd seen my other replies in this very thread, you'd see that's
> exactly the style I use.
>

I've lost track of who advocates what style, but I was responding to
someone that specifically advocated one level of indentation -- which is
really the worst option.

[Christopher Baker]
>
>> well, that is an issue that I do face, but I blame it on my crappy tools
>> :-)
>
>
> I consider it a good thing that your tools don't facilitate bad coding
> style ;)
>

mostly they don't facilitate any of these styles in this context (I've been
meaning to write a plugin for sublime that does, but haven't gotten around
to it ). But the point is that handling indenting is really something the
tools should do for you -- choosing a style for "ease of refactoring"
should be pointless.


> This is just more Stockholm syndrome.
>

honestly, I haven't chooses this style due to having been forced (or even
encouraged) to use it -- I spend more time re-aligning code to make it the
way I want it -- so no, I"ve come on this 'cuse it fits my brain better.


> Nowhere else will you see people consider cramming valuable information
> off into the right margin with arbitrary indentation "good design".
>

It's not the margin, and it's not arbitrary.


> You won't see it in prose. You won't see it in mathematical notation. You
> won't see it anywhere else.
>

Actually, I"ve seen in it math, where you have an "array" of equations, and
> tabular information with columns on the right being important is not the
> least bit rare.
> > But if you are going to do it, for the love of god, use more than four
> > spaces! four spaces is one indentation, one indentation is how a code
> > block is delineated in Python -- this is NOT a code block. It should not
> > look like one.
> I feel the complete opposite.  "One indentation" is the only unit
> in
> multiples of which anything should ever be indented.  Using arbitrary
> "indentation" to visually line things up is horrible.  Everything gets
> indented by an integer number of indentation levels.


OK, then use two indentation levels for the parameter stack -- just don't
use one -- that really is the worst option -- one indentation has real
meaning in code.

-CHB

-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-20 Thread Ben Rudiak-Gould
On Wed, Feb 20, 2019 at 2:43 AM Chris Angelico  wrote:
> That's because a generator function conceptually has three ways to
> provide data (yield, return, and raise), but mechanically, one of them
> is implemented over the other ("return" is "raise StopIteration with a
> value"). For other raised exceptions, this isn't a problem.

Other functions also conceptually have three ways of returning:
ordinary return with a value, a documented special return like
KeyError, and pass-through exceptions. If the pass-through exception
is KeyError, it gets conflated with the documented exceptional return,
but correct code should handle them differently. It doesn't matter
whether the syntax for the documented special return is "return x" or
"raise KeyError(x)". I've never been screwed by this as badly with
other exceptions as I was by StopIteration, but it's a general problem
with the design of exceptions.

I don't think exception specifications would solve that problem since
you probably couldn't describe the KeyError's origin in the spec
either. But that doesn't mean it isn't a problem.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Lele Gaifax
Abe Dillon  writes:

> A better way to list arguments is only one indentation level above the
> current:
>
> variable = some_class.method(
> argument=value,
> argument2=value)
>
> Trying to match the indentation of the opening line is less readable and
> less robust to refactoring:
>
> variable = some_class.method(argument=value,
>  argument2=value)
>
> var = cls.method(argument=value,
>  argument2=value)

Yes, that's unfortunate, but I still prefer the latter, and usually I accept
the hassle and realign the remaining lines.

In hindsight, I wish someone with a powerful time machine could introduce the
concept of "one-indent-level-and-half" for continuation lines: the statement
that most annoys me is the "if" when the condition is very long, because my
eyes suffer when I see the following:

  if condition1 and \
  condition2 and \
  condition3:
  do_something()

or even

  if (condition1 and
  condition2 and
  condition3):
  do_something()

at the point that I usually use a double paren just to have one single space
of difference between the continued condition elements and the succeeding
suite:

  if ((condition1
   and condition2
   and condition3)):
  do_something()

ciao, lele.
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
l...@metapensiero.it  | -- Fortunato Depero, 1929.

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Brendan Barnwell

On 2019-02-20 18:41, Christopher Barker wrote:

God no! I HATE that style -- for me, it makes it MUCH harder to read --
even more so if the variable names are a bit longer.

But if you are going to do it, for the love of god, use more than four
spaces! four spaces is one indentation, one indentation is how a code
block is delineated in Python -- this is NOT a code block. It should not
look like one.


	I feel the complete opposite.  "One indentation" is the only unit in 
multiples of which anything should ever be indented.  Using arbitrary 
"indentation" to visually line things up is horrible.  Everything gets 
indented by an integer number of indentation levels.


	It was mentioned earlier on this thread, but I think the real problem 
is editors.  Specifically, people have become used to certain editor 
behaviors and conventions which are not actually that great, and as a 
result editors have not emphasized features which would be better.  Even 
more specifically, people have not insisted that editors be designed to 
support a reader-oriented, rather than writer-oriented, approach to code 
display.  In other words, visual details how the code is displayed 
should be up to person reading the code, not the person who wrote it.


	Instead, people have apparently for a long time insisted on the 
reverse, namely editors which format things as the code is written, by 
inserting actual characters in the file to make things like up visually. 
 Characters shouldn't be in the file to make things like up visually; 
they should be there for their semantic importance.  If that is done, 
then the editor can render those semantics in different ways according 
to the viewer's preference.


	The problem is that editors don't do this, because people have somehow 
gotten the idea that this would be a bad thing.  So instead we have to 
argue over things like this, because whatever purely cosmetic choices 
one person makes in indenting his or her code become baked into the 
actual bytes of the file, and cannot be rendered differently later 
according to the preferences of a different viewer.


	I've rather forlornly given up on dealing with any of this.  I use an 
editor that VISUALLY wraps long lines and maintains the indentation on 
the wrapped portion, without changing the bytes in the file.  I make my 
lines as long as I want, inserting linebreaks only where they have a 
semantic reason to be (such as between multiple long conditions in an 
"if").  Everything is fine, until someone else looks at the code, and 
they have an editor that is only designed to display code that has the 
formatting baked into the whitespace.


	As a result, I consider this issue pretty much moot.  There is no 
reason for the line length limit to be set to 100 or 120 or anything 
else.  There are already too many problems with PEP 8 that stem from a 
desire to use whitespace for visual alignment rather than semantics 
(such as using spaces instead of tabs).  So I just basically ignore PEP 
8 and follow my own style, which happens to overlap in some respects 
with PEP 8 and diverge from it in others.


--
Brendan Barnwell
"Do not follow where the path may lead.  Go, instead, where there is no 
path, and leave a trail."

   --author unknown
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
[Christopher Barker]

> God no! I HATE that style -- for me, it makes it MUCH harder to read --
> even more so if the variable names are a bit longer.
> But if you are going to do it, for the love of god, use more than four
> spaces! four spaces is one indentation, one indentation is how a code block
> is delineated in Python -- this is NOT a code block. It should not look
> like one.


Holly hell! I'm sorry I insulted your mother or whatever serious crime I
committed. Yes, I agree that two levels of indentation is an improvement
and is in-fact how I write function definitions.

[Christopher Baker]

> this is more readable to me :-)


I wish you would have watched the video I linked
 so I wouldn't have to
make all the same arguments, but in the context of code running off the
edge of a window, having the argument list hidden out there with arbitrary
indentation is definitely a readability issue.

[Christopher Baker]

> This puts the parameter definitions over on the right, after the function
> name, where they belong


According to whom?

[Christopher Baker]

> if you HAVE to put it off to the left for I don't know why, at least put
> some extra space in there:
> def a_function_with_lots_of_params(
> param1,
> param2,
> kwarg1=something,
> kwarg2=something_else):
> now_a_line_of_code = this_thing()
> The parameters are still in an odd place, but at least it's clear where
> the body of the function begins.


If you'd seen my other replies in this very thread, you'd see that's
exactly the style I use.

[Christopher Baker]

> well, that is an issue that I do face, but I blame it on my crappy tools
> :-)


I consider it a good thing that your tools don't facilitate bad coding
style ;)

This is just more Stockholm syndrome. Nowhere else will you see people
consider cramming valuable information off into the right margin with
arbitrary indentation "good design". You won't see it in prose. You won't
see it in mathematical notation. You won't see it anywhere else.

On Wed, Feb 20, 2019 at 8:42 PM Christopher Barker 
wrote:

> Most of this thread is all just so much opinion, so I have avoided chiming
> in -- but as for opinion:
>
> 
>
> A better way to list arguments is only one indentation level above the
>> current:
>>
>> variable = some_class.method(
>> argument=value,
>> argument2=value)
>>
>
> God no! I HATE that style -- for me, it makes it MUCH harder to read --
> even more so if the variable names are a bit longer.
>
> But if you are going to do it, for the love of god, use more than four
> spaces! four spaces is one indentation, one indentation is how a code block
> is delineated in Python -- this is NOT a code block. It should not look
> like one.
>
> 
>
> By the way, this is much worse for, say, function definitions:
>
> def a_function_with_lots_of_params(
> param1,
> param2,
> kwarg1=something,
> kwarg2=something_else):
> now_a_line_of_code = this_thing()
>
> How can anyone think that's more readable than (view with fixed-width font
> if this email doesn't already do that for you):
>
> def a_function_with_lots_of_params(param1,
>param2,
>kwarg1=something,
>kwarg2=something_else):
> now_a_line_of_code = this_thing()
>
> This puts the parameter definitions over on the right, after the function
> name, where they belong, and makes it very clear where the definition ends
> and the function code begins. But if you HAVE to put it off to the left for
> I don't know why, at least put some extra space in there:
>
> def a_function_with_lots_of_params(
> param1,
> param2,
> kwarg1=something,
> kwarg2=something_else):
> now_a_line_of_code = this_thing()
>
> The parameters are still in an odd place, but at least it's clear where
> the body of the function begins.
>
> If you need more convincing, consider functions with fewer params, and how
> they look compared to ones with many:
>
> def a_function_with_few_params(param1, param2):
> now_a_line_of_code = this_thing()
>
> then:
>
> def a_function_with_lots_of_params(
> param1,
> param2,
> kwarg1=something,
> kwarg2=something_else)
> now_a_line_of_code = this_thing()
>
> why am I looking in a different place for the parameters when there are
> more of them??
>
> Trying to match the indentation of the opening line is less readable
>>
>> variable = some_class.method(argument=value,
>>  argument2=value)
>>
>
> this is more readable to me :-)
>
> > and less robust to refactoring:
>
>
>> var = cls.method(argument=value,
>>  argument2=value)
>>
>
> well, that is an issue that I do face, but I blame it on my crappy tools
> :-)
>
> But YAPF does it the way I like :-)
>
> Except in the case of the "facebook" style -- yeach!)
>
> 

Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Dan Sommers

On 2/20/19 7:46 PM, Christopher Barker wrote:

> mutating operations vs copying operations
>
> functions vs methods.
>
> This has a lot of impact on the design, and it's very important that
> any final syntax makes these distinctions clear.

Absolutely.

> On Wed, Feb 20, 2019 at 8:33 AM Dan Sommers
> <2qdxy4rzwzuui...@potatochowder.com> wrote:

> > It's a different way of doing things.  Please don't conflate them.
>
> however, that's kind of what this thread is all about :-)

And I'm objecting to it.  :-)

> So is the goal here to get "fluent" syntax for stringing mutating
> operations together that mutate the object?

Not my goal, no.

> ... we should extend the mutable sequence
> ABC with methods that return new objects:
>
> list.sorted()
> list.appended()
> list.extended()

Call me +0, or maybe +0.5 if adding such additional methods prevent
adding new syntax.

Dan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Steven D'Aprano
On Thu, Feb 21, 2019 at 12:55:00PM +1100, Steven D'Aprano wrote:
> On Wed, Feb 20, 2019 at 10:24:25AM -0800, Bruce Leban wrote:
> 
> > Here's a syntax that solves this using the new operators _:= and ,_
> 
> Be careful about making such dogmatic statements.

Ah, I have just spotted your later explanation that you aren't referring 
to *new operators* spelled as _:= and ,_ (as I understood from your 
words) but as *existing syntax* that works today (at least in the most 
up-to-date version of 3.8).

That pretty much makes all my previous objections to these "new 
operators" redundant, as they aren't operators at all.

I'll point out that there's nothing special about the use of an 
underscore here. Instead of your snippet:

_:= a ,_ .append(4) ,_ .sort()

we could write:

   tmp := a, tmp.append(4), tmp.sort()

So this is hardly method chaining or a fluent interface. (Hence my 
confusion -- I thought you were suggesting a way to implement a fluent 
interface.)

If this were an Obfuscated Python competition, I'd congratulate you for 
the nasty trick of putting whitespace in non-standard positions to 
conceal what is going on. But in real code, that's only going to cause 
confusion.

(But I think you acknowledge that this trick is not easy to read.)

But it's also sub-optimal code. Why introduce a temporary variable 
instead of just writing this?

a.append(4), a.sort()

The only advantage of _ is that it is a one-character name. But there 
are other one character names which are less mystifying:

a := some_long_identifier, a.append(4), a.sort()

But why create a tuple filled mostly with None? Python is slow enough as 
it is without encouraging such anti-patterns.

a := some_long_identifier; a.append(4); a.sort()

Now no tuple is created, and doesn't need to be garbage collected.

But this is still not a fluent interface. Its just cramming multiple 
statements into a single line. Which means you can't do this:

function(arg1, mylist.append(1).sort(), arg3)




-- 
Steven
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Christopher Barker
Most of this thread is all just so much opinion, so I have avoided chiming
in -- but as for opinion:



A better way to list arguments is only one indentation level above the
> current:
>
> variable = some_class.method(
> argument=value,
> argument2=value)
>

God no! I HATE that style -- for me, it makes it MUCH harder to read --
even more so if the variable names are a bit longer.

But if you are going to do it, for the love of god, use more than four
spaces! four spaces is one indentation, one indentation is how a code block
is delineated in Python -- this is NOT a code block. It should not look
like one.



By the way, this is much worse for, say, function definitions:

def a_function_with_lots_of_params(
param1,
param2,
kwarg1=something,
kwarg2=something_else):
now_a_line_of_code = this_thing()

How can anyone think that's more readable than (view with fixed-width font
if this email doesn't already do that for you):

def a_function_with_lots_of_params(param1,
   param2,
   kwarg1=something,
   kwarg2=something_else):
now_a_line_of_code = this_thing()

This puts the parameter definitions over on the right, after the function
name, where they belong, and makes it very clear where the definition ends
and the function code begins. But if you HAVE to put it off to the left for
I don't know why, at least put some extra space in there:

def a_function_with_lots_of_params(
param1,
param2,
kwarg1=something,
kwarg2=something_else):
now_a_line_of_code = this_thing()

The parameters are still in an odd place, but at least it's clear where the
body of the function begins.

If you need more convincing, consider functions with fewer params, and how
they look compared to ones with many:

def a_function_with_few_params(param1, param2):
now_a_line_of_code = this_thing()

then:

def a_function_with_lots_of_params(
param1,
param2,
kwarg1=something,
kwarg2=something_else)
now_a_line_of_code = this_thing()

why am I looking in a different place for the parameters when there are
more of them??

Trying to match the indentation of the opening line is less readable
>
> variable = some_class.method(argument=value,
>  argument2=value)
>

this is more readable to me :-)

> and less robust to refactoring:


> var = cls.method(argument=value,
>  argument2=value)
>

well, that is an issue that I do face, but I blame it on my crappy tools :-)

But YAPF does it the way I like :-)

Except in the case of the "facebook" style -- yeach!)

https://yapf.now.sh/

Facebook style:

def a_function_with_lots_of_params(
param1, param2, kwarg1=something, kwarg2=something_else
):
now_a_line_of_code = this_thing()

Anyway, PEP8 is officially for the standard library, but it HAS become a
python-wide standard. As such, it simply needs to be flexible on some of
these opinionated issues -- so both of the above styles are OK, as is
adjusting your max line length up some.

So at most, I'd say rewording this:

"""
Some teams strongly prefer a longer line length. For code maintained
exclusively or primarily by a team that can reach agreement on this issue,
it is okay to increase the nominal line length from 80 to 100 characters
(effectively increasing the maximum length to 99 characters), provided that
comments and docstrings are still wrapped at 72 characters.
"""

To be a bit less harsh would be a fine idea -- that is, change the clause:

"For code maintained exclusively or primarily by a team that can reach
agreement on this issue, it is okay ..."

To maybe just

"For code maintained  by a team that can reach agreement on this issue, it
is okay ..."

Then we can all go back to bike-shedding something else.

-CHB

PS -- I personally use 95 char per line :-)



-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
[Chris Angelico]

> Not about HOW it works. That's irrelevant. You DO need to know about
> what it does, which is what I said.


So it is. I'm sorry I misread your comment.

[Chris Angelico]

> In the case of random.choice, that's very clearly defined by its
> documentation: it chooses a random
> element from the thing you give it. If you don't know that, you have to
> look it up to determine whether

that's the problem.


I think you're missing the point. The name random.choice alone, doesn't
fully describe its interface,
yet the first time I came across it in code, I didn't feel the need to go
look into documentation. I'm betting you
could make a pretty good educated guess of the interface of all the
functions in the code I wrote above.

Humans aren't computers. We can and do deal with ambiguity all the time. We
can usually make a pretty
good guess whether we need to drill down into a function to find a bug even
if we don't know EVERYTHING
about what the function does. Sometimes that educated guess is wrong and we
have to back up and look
at things we initially thought were irrelevant, but we're not as brittle to
ambiguity as you seem to think.

On Wed, Feb 20, 2019 at 7:35 PM Chris Angelico  wrote:

> On Thu, Feb 21, 2019 at 12:26 PM Abe Dillon  wrote:
> > You don't need to know EVERYTHING about how block_fork works to debug
> that failure. You
> > probably don't need to know EVERYTHING about how random.choice works
> either. You don't
> > need to know about how most of the functions in the code work. The code
> is not blocking an
> > opponent's win. The fault must be in "win" or "opposite".
>
> Not about HOW it works. That's irrelevant. You DO need to know about
> what it does, which is what I said. In the case of random.choice,
> that's very clearly defined by its documentation: it chooses a random
> element from the thing you give it. If you don't know that, you have
> to look it up to determine whether that's the problem.
>
> ChrisA
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Steven D'Aprano
On Wed, Feb 20, 2019 at 10:24:25AM -0800, Bruce Leban wrote:

> Here's a syntax that solves this using the new operators _:= and ,_

Be careful about making such dogmatic statements.

Language design is not a matter of picking random syntax and claiming 
that it solves the problem -- especially when it doesn't solve the 
problem.

Putting aside the aethestics of your suggestions (I think they are as 
ugly as sin), both of them are currently legal code, since a single 
underscore _ is a legal identifier. Starting in 3.8, _:= is the left 
hand side of an assignment expression assigning to the variable "_", so 
your suggestion:

_:=a

already has meaning in Python. That's a new feature, and you can be 
forgiven for perhaps not knowing about it. But the second suggestion is 
a very old feature, going back to Python 1 days. ,_ is part of a tuple 
or argument list including a variable called "_".

You probably could have discovered this for yourself by trying something 
like this in the interactive interpreter:


py> x = []
py> x,_.append(1)
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'tuple' object has no attribute 'append'

The actual result you would get (an exception, or a tuple) will depend 
on the history of your current session, but whatever result you get it 
will show that it is already legal syntax. That means that there's going 
to be an ambiguity between your hoped-for semantics and the existing 
semantics:

_:= a ,_.b

would mean a tuple with two items:

_:= a

_.b

rather than a chained method call as you hoped.


> a = [1,2,3]
> (_:=a,_.append(4),_.sort())
> 
> 
> Personally, I find this a bit harder to read on one line and would break it
> up like this:
> 
> (_:=a
> ,_  .append(4)
> ,_ ..sort()
> )


That's currently legal code which assigns a to _ then builds a tuple (or 
at least attempts to build a tuple) consisting of:

a
None
None

after calling a.append and a.sort.


But there's a deeper problem with this entire concept, regardless of 
syntax, one which to my knowledge nobody has mentioned yet: it simply 
isn't compatible with the way operators work in Python at the moment. 
More on this in another post (coming soon).


-- 
Steven
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Christopher Barker
TL;DR:

When talking about all this, there are two distictions that should be
considered:

mutating operations vs copying operations

functions vs methods.

This has a lot of impact on the design, and it's very important that any
final syntax makes these distinctions clear.

On Wed, Feb 20, 2019 at 8:33 AM Dan Sommers <
2qdxy4rzwzuui...@potatochowder.com> wrote:

> Python lists and dicts are classic objects.  I don't interact with the
> underlying data,




> Python strings, however, don't work that way.  If I create one at the
> top of my application, I can pass it around, but my original remains as
> is.
>

It's a different way of doing things.  Please don't conflate them.
>

however, that's kind of what this thread is all about :-)

Python has two "kinds" of objects -- mutable and immutable.

Immutable objects necessarily return new objects when you call methods on
them (or do something else entirely)

This also makes them naturally easy to chain operations, as per the string
processing example(s).

However, mutating operations are not so easy to chain -- you can't write:

a_list.append(item).sort()[:10]

To, say, add a value to a list and get th first ten items in sorted order

I think the solution to THAT is to do as someone suggested, and to identify
the missing non-mutating operations. after all, we can, with lists, do:

sorted(a_list + [item])[:10]

but there are multiple issues with that:
1) a mixture of function calling and operators
2) that fact that "append an item and make a new list" isn't supported by
either a method or an operator, so we have to do a kludge to use +.

And I think a big one that inspires these ideas:

3) When nesting function calling, you write (and read) the code in the
reverse order that the operations take place:
First you add the item to the list, then you sort it, then you slice it.
4) the "functional" form -- e.g. sorted() doesn't preserve type -- whether
you sort a list or a tuple, you get a list back.

So is the goal here to get  "fluent" syntax for stringing mutating
operations together that mutate the object?

If so, then that should be clearly different than string together
immutables. That is if I see:

that = this.a_method().another_method()

It should be really obvious whether or not "this" has been altered!
Right now, if the object in question follows python conventions, then it
has not been altered.

Personally, I think Python has enough ways to apply an operation, but maybe
in the spirit of functional programming's
idea that we shouldn't be mutating collections at all, we should extend the
mutable sequence ABC with methods that
return new objects:

list.sorted()
list.appended()
list.extended()
...

(slicing already copies). Then you could work with mutable and immutable
sequences similarly to how we do with strings:

first_ten = a_list.appended(item).sorted()[:10]

-CHB


-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Chris Angelico
On Thu, Feb 21, 2019 at 12:26 PM Abe Dillon  wrote:
> You don't need to know EVERYTHING about how block_fork works to debug that 
> failure. You
> probably don't need to know EVERYTHING about how random.choice works either. 
> You don't
> need to know about how most of the functions in the code work. The code is 
> not blocking an
> opponent's win. The fault must be in "win" or "opposite".

Not about HOW it works. That's irrelevant. You DO need to know about
what it does, which is what I said. In the case of random.choice,
that's very clearly defined by its documentation: it chooses a random
element from the thing you give it. If you don't know that, you have
to look it up to determine whether that's the problem.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
[Chris Angelico]
>
> And this is always cited as the "obvious" solution.


Yes. I think simon even referred to this "obvious" solution in his post
when he said, "...which is a very common ocurence, *and doesn't warrant
refactoring*"
So, my comment may have been unwarranted.

[Chris Angelico]

> The trouble is, unless "handle_it" has a name that tells you EVERYTHING
> about what it
> does, you probably will end up having to go look at its definition -
> which means a lot more flicking around.


I think you're over emphasizing "EVERYTHING" and "probably". If your
de-bugging or refactoring,
You typically have enough context to make an educated guess if you need to
look deeper.

The Wikipedia for the game Tic-Tac-Toe (AKA Nots and Crosses) describes a
strategy 

play(board, my_mark):
# Win
moves = win(board, my_mark)
if moves: return random.choice(moves)

# Block
moves = win(board, opposite(my_mark))
if moves: return random.choice(moves)

# Fork
moves = fork(board, my_mark)
if moves: return random.choice(moves)

# Block Fork
moves = fork(board, opposite(my_mark))
if moves: return block_fork(moves, board, my_piece)

# Center
if board[1][1] is None: return (1, 1)

# Corners
moves = empty_corners(board)
if moves: return random.choice(moves)

# Sides
moves = empty_sides(board)
if moves: return random.choice(moves)

# Failing test
board = [['O' , None, None]
 ['X' , 'X' , None]
 [None, None, None]]
mark = 'O'
result = play(board, mark)
expected = (1, 2)
assert move == expected, f"Block! Expected: {expected}, Got: {result}"

You don't need to know EVERYTHING about how block_fork works to debug that
failure. You
probably don't need to know EVERYTHING about how random.choice works
either. You don't
need to know about how most of the functions in the code work. The code is
not blocking an
opponent's win. The fault must be in "win" or "opposite".

 [Chris Angelico]

> The cost of a long line has to be balanced against the cost of *avoiding*
> having a long line. Splitting a line into consecutive lines has less cost
> than
> breaking it out into a function, *unless* the function truly has its own
> meaning.


That's a good point. Pragmatism should always win the day, of course; and
excessive functional decomposition can cause it's own readability issues.
I only offer it as a strategy, not a flawless solution. Sometimes going
beyond
80 columns is the most pragmatic choice, but such cases should be rare.

On Wed, Feb 20, 2019 at 6:23 PM Chris Angelico  wrote:

> On Thu, Feb 21, 2019 at 11:09 AM Abe Dillon  wrote:
> >
> > [simon.bordeyne]
> >>
> >> I find that 100 to 120 characters is ideal as far as line length goes.
> >
> > Your finding goes against a long history of people attempting to present
> text in the most readable way possible.
> > AFIK, the human fovea hasn't grown much larger in recent years.
>
> You can't see the entire line in focus simultaneously anyway, so the
> line length is about how far you can flit your eye left to right, not
> the actual fovea itself.
>
> > [simon.bordeyne]
> >>
> >>  On top of that, it's not uncommon to reach 6, even 7 indentation
> levels.
> >
> > It should be pretty uncommon. You might want to re-think your coding
> style if you're regularly writing code that's so deeply indented.
> > A good trick is to use helper functions:
> >
> > #instead of this
> > if condition:
> > ...code
> >
> > #do this
> > if condition:
> > handle_it()
>
> And this is always cited as the "obvious" solution. The trouble is,
> unless "handle_it" has a name that tells you EVERYTHING about what it
> does, you probably will end up having to go look at its definition -
> which means a lot more flicking around. The cost of a long line has to
> be balanced against the cost of *avoiding* having a long line.
> Splitting a line into consecutive lines has less cost than breaking it
> out into a function, *unless* the function truly has its own meaning.
>
> ChrisA
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Steven D'Aprano
On Wed, Feb 20, 2019 at 07:53:21PM +, Jonathan Fine wrote:
> Steven D'Aprano wrote:
> 
> > > I wasn't making a point. I was providing evidence.
> >
> > Evidence of what?
> >
> > What was the point of this evidence?
> >
> > If it was to demonstrate that it is possible to reformat function
> > parameter lists to split over multiple lines, we already knew that.
> >
> > If it was to demonstrate something else, I have no idea what.
> 
> One idea arising from the evidence I provided 

Evidence for what?


> was that like a
> word-processor, one could use black.py to 'line-wrap' the Python code
> to what is the current width of the editor window. Which may vary from
> person to person.

So when I receive a bug report with a traceback, the line number and 
line of code showing in the traceback may have little or no relationship 
to those on disk or in my editor?



-- 
Steven
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
First of all, thank you so much for taking the time to do some actual
analysis!
I only have one thing to add:

[Paul Ferrell]

> 3 - function calls
> Function calls, even with the arguments put one per line, often exceed 80
> (and sometimes 100) character limit. The issue tends to be a combination of
> tabbing, kwarg names, and the context in which all of this is used. It's
> often unavoidable.
> variable = some_class.method(argument=value,
>argument2=value)


This reminds me of a bit that shows up often in Kevlin Henney's talks
.

A better way to list arguments is only one indentation level above the
current:

variable = some_class.method(
argument=value,
argument2=value)

Trying to match the indentation of the opening line is less readable and
less robust to refactoring:

variable = some_class.method(argument=value,
 argument2=value)

var = cls.method(argument=value,
 argument2=value)

On Wed, Feb 20, 2019 at 4:52 PM Paul Ferrell  wrote:

> Opinion first - I don't see a need to change PEP 8. I recommend 100 char
> width for Python, which is acceptable under PEP 8 anyway. I think the real
> limit should be around 70 characters per line, not including leading
> white-space, but I realize that's impractical.
>
> I work mostly at 100 character line width, and the question of line width
> came up for me recently.  Otherwise, I follow PEP 8. I want to see where,
> and why I exceed 79 chars, so I dove into a decently sized module file of
> mine and tallied the results. This is what I found.
>
> 563 total lines
> 448 non-blank lines
>
> For the non-blank lines:
> 49.6 characters per line on average
> 36.7 non-leading-whitespace characters per line
> 13.1 leading spaces per line on average
> 15.5% of lines exceeded 79 chars.
>
> The 69 lines that exceeded 79 characters fell into the following
> categories, listed according to how annoying they would be to fix.
>
> 1 - with statements
> I have a with statement that contains two context managers "with
> open(blah) as b, open(foo) as f:". There isn't a really good way to wrap
> this without adding another with statement or a backslash.
>
> 3 - function calls
> Function calls, even with the arguments put one per line, often exceed 80
> (and sometimes 100) character limit. The issue tends to be a combination of
> tabbing, kwarg names, and the context in which all of this is used. It's
> often unavoidable.
> variable = some_class.method(argument=value,
>argument2=value)
>
> 5 - Overly deep logic
> There were a couple of blocks of code that should have been pushed into
> separate methods/functions. I do occasionally run into issues where there
> simply isn't room (in 79 chars) for the logic required, and that logic
> can't reasonably be separated out.
>
> 8 - Format calls
> While I love the new format syntax, I almost always end up moving the
> format call to a new line with 4 spaces of extra indentation. These were
> instances of when I didn't.
>
> 21 - Comments
> There's plenty of space for readable comments in most cases. Under several
> nested scopes, however, the space gets pretty tight. Those extra 20 chars
> go a long way.
>
> 12 - Strings
> Like comments, having a few extra chars for strings (mostly exception
> messages in this case) goes a long way when even moderately nested.
>
> 2 - Chained conditionals
> if A and B and C
> Should have been:
> if (A and
> B and
> C):
>
> 16 - Doc strings
> These are easily fixable with no change in readability, and rarely have
> issues with padding.
>
> On Wed, Feb 20, 2019 at 12:57 PM Chris Angelico  wrote:
>
>> On Thu, Feb 21, 2019 at 6:48 AM Jonathan Fine 
>> wrote:
>> > Here's a suggestion, at least for people projects that use black.py
>> > (such as Samuel's). It is to use black.py with a line-length of say 80
>> > characters for code that is saved in version control. And when editing
>> > code, use whatever line-length that happens to suit the tools you are
>> > using.
>> >
>> > Indeed, like a word-processor, one could use black.py to 'line-wrap'
>> > the Python code to what is the current width of the editor window.
>>
>> From my experience (granted, I work heavily with students, so maybe
>> it's different if everyone involved in the project has 5+ or 10+ years
>> coding), autoformatters are a blight. They take a simple, easy-to-find
>> missed parenthesis, and completely obscure it by reindenting the code
>> until it finds something unrelated that seems to close it. The
>> indentation in the code of even a novice programmer is valuable
>> information about *programmer intent*, and throwing that away
>> automatically as part of checking in code (or, worse, every time you
>> save the file) is a bad idea. Easy bugs become hard.
>>
>> Of course, if you assume that everything in your code is 

Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Chris Angelico
On Thu, Feb 21, 2019 at 11:09 AM Abe Dillon  wrote:
>
> [simon.bordeyne]
>>
>> I find that 100 to 120 characters is ideal as far as line length goes.
>
> Your finding goes against a long history of people attempting to present text 
> in the most readable way possible.
> AFIK, the human fovea hasn't grown much larger in recent years.

You can't see the entire line in focus simultaneously anyway, so the
line length is about how far you can flit your eye left to right, not
the actual fovea itself.

> [simon.bordeyne]
>>
>>  On top of that, it's not uncommon to reach 6, even 7 indentation levels.
>
> It should be pretty uncommon. You might want to re-think your coding style if 
> you're regularly writing code that's so deeply indented.
> A good trick is to use helper functions:
>
> #instead of this
> if condition:
> ...code
>
> #do this
> if condition:
> handle_it()

And this is always cited as the "obvious" solution. The trouble is,
unless "handle_it" has a name that tells you EVERYTHING about what it
does, you probably will end up having to go look at its definition -
which means a lot more flicking around. The cost of a long line has to
be balanced against the cost of *avoiding* having a long line.
Splitting a line into consecutive lines has less cost than breaking it
out into a function, *unless* the function truly has its own meaning.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
[simon.bordeyne]

> I find that 100 to 120 characters is ideal as far as line length goes.

Your finding goes against a long history of people attempting to present
text in the most readable way possible.
AFIK, the human fovea hasn't grown much larger in recent years.

[simon.bordeyne]

>  On top of that, it's not uncommon to reach 6, even 7 indentation levels.

It should be pretty uncommon. You might want to re-think your coding style
if you're regularly writing code that's so deeply indented.
A good trick is to use helper functions:

#instead of this
if condition:
...code

#do this
if condition:
handle_it()

[simon.bordeyne]

> All it takes is a loop in a loop (looping through an array for instance),
> a condition and all of that inside a class' method. Just in that example,
> which is a very common occurence, an doesn't warrant refactoring, there is
> 5 indentation level, eg a quarter of the recommended line length.

You should check out the itertools library and possibly the toolz package.
I find it's often pretty simple to collapse nested loops in python:

for n, element in enumerate(chain(*array)):
r, c = divmod(n, len(array[0]))  # if you need the indexes
if condition(element): do_something(element) # this follows the
one-line one-thought rule over PEP8


On Tue, Feb 19, 2019 at 8:08 AM simon.bordeyne 
wrote:

> I find that 100 to 120 characters is ideal as far as line length goes. In
> my opinion, splitting lines is much worse in terms of cognitive burden than
> just a longer line. On top of that, it's not uncommon to reach 6, even 7
> indentation levels. All it takes is a loop in a loop (looping through an
> array for instance), a condition and all of that inside a class' method.
> Just in that example, which is a very common occurence, an doesn't warrant
> refactoring, there is 5 indentation level, eg a quarter of the recommended
> line length.
>
> Defining decorators also goes up there in terms of number of indents by
> the way.
>
> As far as monitor size goes, I agree that on a laptop is not ideal for
> 100+ characters per line if you want two pieces of code side by side. And,
> fyi, I work on a 23" monitor at home and on a 15.6" monitor on the go. Both
> are perfectly fine with 100 characters a line.
>
> A good middle ground would be to enforce customization of that rule in the
> most used python linters. A simple setting to set the number of characters
> before a linting warning occurs would be acceptable.
>
>
>
> Envoyé depuis mon smartphone Samsung Galaxy.
>
>  Message d'origine 
> De : David Mertz 
> Date : 19/02/2019 07:28 (GMT+01:00)
> À : Anders Hovmöller 
> Cc : Simon , python-ideas <
> python-ideas@python.org>
> Objet : Re: [Python-ideas] PEP 8 update on line length
>
> 60, or 68, or 80 characters, is not per se a cognitive limit. Yes, sure
> whitespace counts much less towards that burden than do regular characters.
> And to a significant degrees, punctuation vs. letters vs. numbers matter.
> And sure familiar words such as keywords scan a bit easier than unfamiliar
> names of variables. And so on.
>
> But 80 characters in general is already too wide most of the time. 65 is a
> better goal as a rule of thumb, with 80 already being for exceptionally
> long lines. Python keywords are already short, there's not much improvement
> to be had there. Saving two characters for acryptic WHL isn't better than
> the word 'while', for example.
>
> Pretty much the only time my code how's more than 80 characters is when it
> includes string literally that occupy a large chunk of the width. But if
> that 50 character string is the last argument of a function call, the
> reader can mostly stop scanning at it's beginning, so it's not terrible.
> When I have many keyword arguments, I break them into multiple physical
> lines using parents too continue the logical line. Or if I have complex
> compound conditions, I give the subclauses short but descriptive names
> before the if/elif.
>
> On Tue, Feb 19, 2019, 1:11 AM Anders Hovmöller 
>>
>>
>> > On 19 Feb 2019, at 05:48, David Mertz  wrote:
>> >
>> > You either have much better eyes to read tiny fonts than I do, or maybe
>> a much larger monitor (it's hard for me to fit a 30"" monitor in my laptop
>> bag).
>> >
>> > But that's not even the real issue. If the characters were in giant
>> letters on billboards, I still would never want more than 80 of them on a
>> line (well, rarely, I violate PEP 8 sometimes). Centuries if not millennia
>> of experience with writing show that cognitive burden goes up
>> exponentially, not linearly, as lines get to be more than about 60
>> characters.
>>
>> If that is the issue then we should be talking about non-space
>> characters, not a 68 column limit right? No way does 40 spaces due to
>> indent count towards the cognitive burden :)
>>
>> Also, if the cognitive burden is the issue then we should talk about
>> short forms for keyword arguments again. The way the 68 column limit works

Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
Thankfully, style guidelines are based upon the limitations of humans like
the size of the fovea and the general ability for people to follow long
lines, NOT on the limitations of tools like grep.

On Tue, Feb 19, 2019 at 10:29 AM Anders Hovmöller 
wrote:

>
> If it were me, I'd probably write (or would have re-written when I added
> the type hints) that as follows:
>
>def resolve_annotations(
>*,
>raw_annotations: Dict[str, Type[Any]],
>module_name: Optional[str]
>) -> Dict[str, Type[Any]]:
>
>
> I would like to point out here that breaking up a line breaks grepping
> quite badly. I've had to write AST-based searches to find simple usages of
> arguments in the code base at work precisely because of code that is split
> on likes like this. (This tool is available here:
> https://github.com/boxed/parso_utils)
>
> I would vastly prefer a soft like break algorithm that formatted the code
> as per your examples and having the code on disk be single line no matter
> what.
>
> In proprietary projects where one can agree on the tools used for the code
> this can be quite doable, but I agree it's not great for open source
> projects.
>
> / Anders
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Abe Dillon
[Samuel Colvin]
>
>  I don't see how anyone can say that would be more readable with a 80
> character line limit.

For starters, type annotations don't add anything that good documentation
would have required before. In most docstring style guides that I know of,
the arguments list is supposed to be at least one line per argument, so
really it should look like so:

def resolve_annotations(raw_annotations, module_name):
"""
description of what the function does

Arguments:
raw_annotations (type annotation): description of raw_annotations
module_name (type annotation): description of module name

Returns (type annotation): description or return value
"""

Which can easily be replaced with:

def resolve_annotations(
raw_annotations: Dict[str, Type[Any]],
module_name: Optional[str])
-> Dict[str, Type[Any]]:
"""
description of what the module does

Arguments:
raw_annotations: description of raw_annotations
module_name: description of module name

Returns: description or return value
"""

Often, I find, people make add a lot of redundant noise to names which is
either clear from context like; math.log, not
math.mathematical_log_function, or doesn't add anything like; user_data
instead of user, or job_info instead of job, or raw_annotations instead of
annotations. It's often just as good to write:

def resolve(annotations: Dict[str, Type[Any]], module: Optional[str])
-> Dict[str, Type[Any]]:
"""..."""

On Tue, Feb 19, 2019 at 8:30 AM Samuel Colvin  wrote:

> I too would argue that it's time to reconsider line length limits.
>
> But the reason is not monitor changes, or any particularly strong personal
> opinion, but changes to python:
>
> Let's take a real life example from here
>  
> (changed
> very slightly for this example), in tranitional python the signature might
> be:
>
> def resolve_annotations(raw_annotations, module_name):
>
> 55 characters, all fine. Now let's look at that same function in modern
> python with type hints:
>
> def resolve_annotations(*, raw_annotations: Dict[str, Type[Any]],
> module_name: Optional[str]) -> Dict[str, Type[Any]]:
>
> 119 characters! No daft 5-word variable names, just a clean (if strict)
> function definition. I don't see how anyone can say that would be more
> readable with a 80 character line limit. And that's not even an extreme
> case, we don't have lots of "Optional[..]" or "Tuple[ThingA, ThingB,
> ThingC]".
>
> Type hints (for good or bad depending on your view point) have made python
> code more verbose, that's just a fact. Code that used to fit on one line
> with 80char limit now require 120 (or more), therefore in my opinion the
> recommendation should change to keep up with changes in python.
>
> My preference is 120 characters (that's also the default in pycharm I
> believe). It works well on a desktop monitor, leaving room for a file
> browser and part of another window, it's also fine on a 13" laptop screen.
>
> Then again, every IDE and linter I've used (even black) allows the line
> length to be varried, so this is only really a problem in the standard
> library and libraries which adhere closely to pep8.
>
> Samuel
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Paul Ferrell
Opinion first - I don't see a need to change PEP 8. I recommend 100 char
width for Python, which is acceptable under PEP 8 anyway. I think the real
limit should be around 70 characters per line, not including leading
white-space, but I realize that's impractical.

I work mostly at 100 character line width, and the question of line width
came up for me recently.  Otherwise, I follow PEP 8. I want to see where,
and why I exceed 79 chars, so I dove into a decently sized module file of
mine and tallied the results. This is what I found.

563 total lines
448 non-blank lines

For the non-blank lines:
49.6 characters per line on average
36.7 non-leading-whitespace characters per line
13.1 leading spaces per line on average
15.5% of lines exceeded 79 chars.

The 69 lines that exceeded 79 characters fell into the following
categories, listed according to how annoying they would be to fix.

1 - with statements
I have a with statement that contains two context managers "with open(blah)
as b, open(foo) as f:". There isn't a really good way to wrap this without
adding another with statement or a backslash.

3 - function calls
Function calls, even with the arguments put one per line, often exceed 80
(and sometimes 100) character limit. The issue tends to be a combination of
tabbing, kwarg names, and the context in which all of this is used. It's
often unavoidable.
variable = some_class.method(argument=value,
   argument2=value)

5 - Overly deep logic
There were a couple of blocks of code that should have been pushed into
separate methods/functions. I do occasionally run into issues where there
simply isn't room (in 79 chars) for the logic required, and that logic
can't reasonably be separated out.

8 - Format calls
While I love the new format syntax, I almost always end up moving the
format call to a new line with 4 spaces of extra indentation. These were
instances of when I didn't.

21 - Comments
There's plenty of space for readable comments in most cases. Under several
nested scopes, however, the space gets pretty tight. Those extra 20 chars
go a long way.

12 - Strings
Like comments, having a few extra chars for strings (mostly exception
messages in this case) goes a long way when even moderately nested.

2 - Chained conditionals
if A and B and C
Should have been:
if (A and
B and
C):

16 - Doc strings
These are easily fixable with no change in readability, and rarely have
issues with padding.

On Wed, Feb 20, 2019 at 12:57 PM Chris Angelico  wrote:

> On Thu, Feb 21, 2019 at 6:48 AM Jonathan Fine  wrote:
> > Here's a suggestion, at least for people projects that use black.py
> > (such as Samuel's). It is to use black.py with a line-length of say 80
> > characters for code that is saved in version control. And when editing
> > code, use whatever line-length that happens to suit the tools you are
> > using.
> >
> > Indeed, like a word-processor, one could use black.py to 'line-wrap'
> > the Python code to what is the current width of the editor window.
>
> From my experience (granted, I work heavily with students, so maybe
> it's different if everyone involved in the project has 5+ or 10+ years
> coding), autoformatters are a blight. They take a simple, easy-to-find
> missed parenthesis, and completely obscure it by reindenting the code
> until it finds something unrelated that seems to close it. The
> indentation in the code of even a novice programmer is valuable
> information about *programmer intent*, and throwing that away
> automatically as part of checking in code (or, worse, every time you
> save the file) is a bad idea. Easy bugs become hard.
>
> Of course, if you assume that everything in your code is perfect, then
> by all means, reformat it however you like. If you're 100% confident
> that nobody writes any buggy code, then the formatting doesn't matter,
> and you can display it in whichever way looks prettiest. But if you
> appreciate ways of discovering bugs more easily, preserve everything
> that represents the programmer's intention.
>
> ChrisA
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Paul Ferrell
pfl...@gmail.com
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Chris Angelico
On Thu, Feb 21, 2019 at 6:48 AM Jonathan Fine  wrote:
> Here's a suggestion, at least for people projects that use black.py
> (such as Samuel's). It is to use black.py with a line-length of say 80
> characters for code that is saved in version control. And when editing
> code, use whatever line-length that happens to suit the tools you are
> using.
>
> Indeed, like a word-processor, one could use black.py to 'line-wrap'
> the Python code to what is the current width of the editor window.

>From my experience (granted, I work heavily with students, so maybe
it's different if everyone involved in the project has 5+ or 10+ years
coding), autoformatters are a blight. They take a simple, easy-to-find
missed parenthesis, and completely obscure it by reindenting the code
until it finds something unrelated that seems to close it. The
indentation in the code of even a novice programmer is valuable
information about *programmer intent*, and throwing that away
automatically as part of checking in code (or, worse, every time you
save the file) is a bad idea. Easy bugs become hard.

Of course, if you assume that everything in your code is perfect, then
by all means, reformat it however you like. If you're 100% confident
that nobody writes any buggy code, then the formatting doesn't matter,
and you can display it in whichever way looks prettiest. But if you
appreciate ways of discovering bugs more easily, preserve everything
that represents the programmer's intention.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Jonathan Fine
Steven D'Aprano wrote:

> > I wasn't making a point. I was providing evidence.
>
> Evidence of what?
>
> What was the point of this evidence?
>
> If it was to demonstrate that it is possible to reformat function
> parameter lists to split over multiple lines, we already knew that.
>
> If it was to demonstrate something else, I have no idea what.

One idea arising from the evidence I provided was that like a
word-processor, one could use black.py to 'line-wrap' the Python code
to what is the current width of the editor window. Which may vary from
person to person.

(I did not say it at the time, because I did not have it at the time.
And because others might have different useful ideas coming from the
same piece of evidence.)

See https://mail.python.org/pipermail/python-ideas/2019-February/055424.html

-- 
Jonathan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-20 Thread Jonathan Fine
I wrote:



def resolve_annotations(raw_annotations: Dict[str, AnyType],
module_name: Optional[str]) -> Dict[str, AnyType]:
pass

After using https://black.now.sh/

def resolve_annotations(
raw_annotations: Dict[str, AnyType],
module_name: Optional[str],
) -> Dict[str, AnyType]:
pass


Samuel Colvin then told us that his example was already formatted with
black.py, using a long line length.

Here's a suggestion, at least for people projects that use black.py
(such as Samuel's). It is to use black.py with a line-length of say 80
characters for code that is saved in version control. And when editing
code, use whatever line-length that happens to suit the tools you are
using.

Indeed, like a word-processor, one could use black.py to 'line-wrap'
the Python code to what is the current width of the editor window.

Indeed, this might be a useful feature in Jupyter - see
https://github.com/drillan/jupyter-black.  And I've created
https://github.com/drillan/jupyter-black/issues/3
Perhaps set the black line length to the width of the text box

-- 
Jonathan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Bruce Leban
On Wed, Feb 20, 2019 at 11:03 AM Rhodri James  wrote:

> On 20/02/2019 18:24, Bruce Leban wrote:
> > a = [1,2,3]
> > (_:=a,_.append(4),_.sort())
>
> I'm not sure what problem you are solving here, but if that's the
> solution I'd rather have the problem.  There is absolutely nothing in
> that syntax that suggests what's going on.
>
>
Given the responses, I think I was a bug more obtuse than necessary. My
apologies.

This is already in Python 3.8. I am NOT actually suggesting a change to the
language. I'm showing how to "solve" the "problem" of wanting to write
chained method calls on a single line. I agree the solution is unreadable
and worse than the problem. Any other proposed solution is merely
bikeshedding the syntax and I think suffers from the same non-readability
problem. For example these are essentially the same:

_:= a  ,_. append(4) ,_. sort()
a :: append(4) :: sort()

--- Bruce
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Rhodri James

On 20/02/2019 18:24, Bruce Leban wrote:

Here's a syntax that solves this using the new operators _:= and ,_


a = [1,2,3]
(_:=a,_.append(4),_.sort())


I'm not sure what problem you are solving here, but if that's the 
solution I'd rather have the problem.  There is absolutely nothing in 
that syntax that suggests what's going on.


--
Rhodri James *-* Kynesim Ltd
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Jonathan Fine
I think this

>>> a = [1,2,3]
>>> _ = a
>>> ( _ .append(4), _ .sort())
(None, None)

is clearer than

a = [1,2,3]
(_:=a,_.append(4),_.sort())

And it works in every version of Python3 (and Python2 I expect).

-- 
Jonathan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Bruce Leban
On Wed, Feb 20, 2019 at 10:34 AM Jonathan Fine  wrote:

> There's a problem with introducing ,_ as a new operator.
>

I should have put "new" in scare quotes to be more clear as it's not really
new. As you've observed this is already implemented. For it to work as in
my example you also need to use the "new" _:= operator which requires
Python 3.8.

--- Bruce
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Jonathan Fine
There's a problem with introducing ,_ as a new operator.

$ python3.6
Python 3.6.2 (default, Jul 29 2017, 00:00:00)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 2
4
>>> 4 ,_ + 6
(4, 10)

Hint:
>>> _
(4, 10)
>>> 3 ,_
(3, (4, 10))

-- 
Jonathan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Bruce Leban
Here's a syntax that solves this using the new operators _:= and ,_


a = [1,2,3]
(_:=a,_.append(4),_.sort())


Personally, I find this a bit harder to read on one line and would break it
up like this:

(_:=a
,_  .append(4)
,_ ..sort()
)


--- Bruce
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Dan Sommers

On 2/20/19 9:10 AM, Steven D'Aprano wrote:

> That's possibly a matter of familiarity. I'd be very surprised if you
> preferred this:
>
>  mystr = mystr.strip()
>  mystr = mystr.expandtabs()
>  mystr = mystr.lower()
>  mystr = mystr.replace('ham', 'spam')
>  result = function(mystr)
>
> over this fluent version:
>
>  result = 
function(mystr.strip().expandtabs().lower().replace('ham', 'spam'))


Those two blocks of code don't quite do the same thing.  What is the
value of mystr at the end of each block?  Yes, as a matter of fact, I do
think that that's the important question.

Consider these two similar blocks of code:

f(mylist):
mylist.sort()
mylist.pop()
mylist.reverse()

g(mystr):
return mystr.strip().expandtabs().replace('ham', 'spam')

The difference is more than a matter of which syntax I prefer, the
difference is a matter of how I build software.

Python lists and dicts are classic objects.  I don't interact with the
underlying data, I send the object a request to operate on that data,
and rest assured that the object is doing the right thing.  I can create
one at the top of my application, pass it around, make a series of
request against it, and ask that very same object for the end result:

some_list = get_some_data()
f(some_list)
print(some_list) # what happened to my original?

Python strings, however, don't work that way.  If I create one at the
top of my application, I can pass it around, but my original remains as
is.

some_string = get_some_data()
another_string = g(some_string) # why do I need a new string?
print(some_string)
print(another_string)

It's a different way of doing things.  Please don't conflate them.

> Or if you're worried about the line length:
>
>  result = function(mystr.strip()
> .expandtabs()
> .lower()
> .replace('ham', 'spam')
> )
>
> works for me.

I am no longer impressed that you squeezed the original into exactly 80
columns.  ;-)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Steven D'Aprano
On Tue, Feb 19, 2019 at 01:52:34PM -0800, Brett Cannon wrote:
> On Tue, Feb 19, 2019 at 6:23 AM Jimmy Girardet  wrote:
[...]
> > I would be happy to have
> >
> > >>> [1,2,3].append(4)::sort()::max() +1
> >
> > It makes things very easy to read: first create list, then append 4,
> > then sort, then get the max.
> >
> 
> Easy for you, but not necessarily everyone else. For instance, I find the
> explicit writing out of the lines easier.

That's possibly a matter of familiarity. I'd be very surprised if you 
preferred this:

mystr = mystr.strip()
mystr = mystr.expandtabs()
mystr = mystr.lower()
mystr = mystr.replace('ham', 'spam')
result = function(mystr)

over this fluent version:

result = function(mystr.strip().expandtabs().lower().replace('ham', 'spam'))

Or if you're worried about the line length:

result = function(mystr.strip()
   .expandtabs()
   .lower()
   .replace('ham', 'spam')
   )

works for me.


-- 
Steven
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] add fluent operator to everything

2019-02-20 Thread Dan Sommers

On 2/20/19 1:58 AM, Jimmy Girardet wrote:


You're right on it. The str class is a  straightforward swiss army knife
with methods you can chain. list or dict do not fit this idea.


Python strings are immutable.  Python lists and dicts are
not.  Both classes are straightforward.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] About PEP-582

2019-02-20 Thread Joni Orponen
On Wed, Feb 20, 2019 at 4:49 AM Brett Cannon  wrote:

> On Tue, Feb 19, 2019 at 3:29 PM Philip Bergen via Python-ideas <
> python-ideas@python.org> wrote:
>
>> First attempt at this, so please be gentle. :)
>> I am very interested in the overall goal of not needing virtualenvs, but
>> I'm curious about the motivations behind pep-582.
>>
>
> In a word, simplicity. Teaching newcomers about virtual environments is a
> stumbling block, but so if when they accidentally pollute their global
> installation when they get started.PEP 582 is an attempt to handle the
> simple case nicely.
>

Is Buildout forgotten? It's not dead and achieves the same in this regard.
It works by flushing out meaningfully-shebanged wrapper scripts with
exactly injected sys.path.

http://docs.buildout.org/en/latest/

-- 
Joni Orponen
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-20 Thread Chris Angelico
On Wed, Feb 20, 2019 at 9:09 PM Ben Rudiak-Gould  wrote:
> That problem, of an inadvertently leaked implementation detail
> masquerading as a proper alternate return value, used to be a huge
> issue with StopIteration, causing bugs that were very hard to track
> down, until PEP 479 fixed it by translating StopIteration into
> RuntimeError when it crossed an abstraction boundary.

That's because a generator function conceptually has three ways to
provide data (yield, return, and raise), but mechanically, one of them
is implemented over the other ("return" is "raise StopIteration with a
value"). For other raised exceptions, this isn't a problem.

> I think converting exceptions to RuntimeErrors (keeping all original
> information, but bypassing catch blocks intended for specific
> exceptions) is the best option. (Well, second best after ML/Haskell.)
> But to make it work you probably need to support some sort of
> exception specification.

The trouble with that is that it makes refactoring very hard. You
can't create a helper function without knowing exactly what it might
be raising.

> I'm rambling. I suppose my points are:
>
> * Error handing is inherently hard, and all approaches do badly
> because it's hard and programmers hate it.

Well, yeah, no kidding. :)

> ... I was bitten several times by
> that StopIteration problem.
>

There's often a completely different approach that doesn't leak
StopIteration. One of my workmates started seeing RuntimeErrors, and
figured he'd need a try/except in this code:

   def _generator(self, left, right):
while True:
yield self.operator(next(left), next(right))

But instead of messing with try/except, it's much simpler to use
something else - in this case, zip.

Generally, it's better to keep things simple rather than to complicate
them with new boundaries. Unless there's a good reason to prevent
leakage, I would just let exception handling do whatever it wants to.
But if you want to specifically say "this function will not raise
anything other than these specific exceptions", that can be done with
a decorator:

def raises(*exc):
"""Declare and enforce what a function will raise

The decorated function will not raise any Exception other than
the specified ones, or RuntimeError.
"""
def deco(func):
@functools.wraps(func)
def convert_exc(*a, **kw):
try: return func(*a, **kw)
except exc: raise
except Exception as e: raise RuntimeError from e
convert_exc.may_raise = exc # in case it's wanted
return convert_exc
return deco

This way, undecorated functions behave as normal, so refactoring isn't
impacted. But if you want the help of a declared list of exceptions,
you can have it.

@raises(ValueError, IndexError)
def frob(x):
...

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-20 Thread Ben Rudiak-Gould
On Tue, Feb 19, 2019 at 3:19 PM Steven D'Aprano  wrote:
> And I note that in Java, where the idea of checked exceptions
> originated, it turned out to be full of problems and a very bad idea.

What should be the default behavior of a language when the programmer
doesn't explicitly handle an error? Options include:

1. Type error (Java, ML/Haskell)
2. Ignore it (C)
3. Pass it as-is to the caller
4. "Genericize" it, e.g. wrap it in a RuntimeError, then pass to the caller

The problem with the Java approach is that people don't want to think
about how to properly handle every error, and just wrap their code in
catch (...) {} instead. I think it works much better in ML/Haskell,
though perhaps only because the average skill level of the programmers
is higher.

The problem with the C approach is that people don't want to think
about how to properly handle every error, and just call every function
in a void context.

The problem with passing exceptions as-is to the caller is that
they're very often implementation details. If you're lucky, they will
propagate to a generic catch-all somewhere which will generate a
traceback that a human may be able to use to fix the problem. If
you're unlucky, the caller wrote `return d[k].frobnicate()` inside a
try block and frobnicate's internal KeyError gets misinterpreted as a
lookup failure in d.

That problem, of an inadvertently leaked implementation detail
masquerading as a proper alternate return value, used to be a huge
issue with StopIteration, causing bugs that were very hard to track
down, until PEP 479 fixed it by translating StopIteration into
RuntimeError when it crossed an abstraction boundary.

I think converting exceptions to RuntimeErrors (keeping all original
information, but bypassing catch blocks intended for specific
exceptions) is the best option. (Well, second best after ML/Haskell.)
But to make it work you probably need to support some sort of
exception specification.

I'm rambling. I suppose my points are:

* Error handing is inherently hard, and all approaches do badly
because it's hard and programmers hate it.

* Stronger typing is only bad if you just want your code to run and
are tired of fixing it to be type-correct. The people who voluntarily
add type annotations to Python programs probably aren't those kinds of
people; they're probably much more likely than the average programmer
to want checked exceptions.

* Declaring that a function only raises Foo doesn't have to mean "it
raises Foo, and also passes exceptions from subfunctions to the caller
unchanged, no matter what they are." It could also mean "it raises
Foo, and converts other exceptions into RuntimeError." This would
actually be useful because it would mean that you could safely put
longer expressions in try blocks, instead of defensively just putting
the one method call whose KeyError you want to handle in the try:
block, and moving everything else to the else: block, as I tend to do
all the time because I'm paranoid and I was bitten several times by
that StopIteration problem.

-- Ben
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/