There should be one-- and preferably only one --obvious way to do it.
the author used two different ways of hyphenating (three, if you count the whole PEP 20). PEP 20 is clearly not meant to be taken as law. Nor PEP 8. Nor PEP 257.People frequently mistake "one obvious way" with "one way". There are lots of ways to iterate through something, for example, but there is really one obvious way. And the philosophy here still applies: when you read anyone else's python code, the obvious way is probably doing the obvious thing. I think that is the more appropriate takeaway from PEP 20.
No, first, it doesn't use hyphenating at all, it uses hyphens as an ASCII approximation for typographical dashes used to set off a phrase (a distinct function from hyphenation), and, second, in that quote they used one way of doing it: “two dashes set closed on the side of the main sentence and set open on the side of set-off phrase”.
It is an unusual way of doing it—just as with actual typographical dashes, setting open or closed symmetrically would be more common—but it's not two ways.
EDIT: And the third use (in the heading and later in the body) is seperating parts where neither is a mid-sentence appositive phrase, and uses open-on-both sides. So that's not a different way of doing the same thing, it's a different way of doing a semantically different thing.
Actually, I think the dash use makes a good illustration of how the “it” in “one way to do it” is intended.
Eh, I don't think that's the interpretation the author was going for. The author wanted to show two different ways of approximating a dash, and he had limited options.
If he'd done this-- for example-- he would have been showing one way, not two.
If he'd done this --for example-- you would have called it "two dashes set open on the side of the main sentence and set closed on the side of set-off phrase".
If he'd done this-- for example -- it would have been too obvious (on the same line).
I suppose he could have done this-- for example--but I still think that would have been too obvious. You're not supposed to see it on a first read.
> And the third use (in the heading and later in the body) is seperating parts where neither is a mid-sentence appositive phrase, and uses open-on-both sides. So that's not a different way of doing the same thing, it's a different way of doing a semantically different thing.
It's a different use of a dash, but it's still a place where you'd typically use a dash.
-----
Edit: You know what, thinking about it again—perhaps both interpretations are valid. That almost adds to the effectiveness of the whole thing.
I don't get what you mean by this.
When I read someone else's code, what is obvious to me isn't necessarily what was obvious to the author. For an illustration of this, have a look at the day 1 solution thread from this year's Advent of Code - https://www.reddit.com/r/adventofcode/comments/r66vow/2021_d... (you can search for Python solutions) - and see how many different ways there are to solve a fairly straightforward problem.
For example, you'll sometimes see people do bad stuff like this:
>>> lst = []
>>>
>>> [lst.append(i + i) for i in range(10)]
[None, None, None, None, None, None, None, None, None, None]
>>>
>>> lst
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
When they should be doing this: >>> lst = []
>>>
>>> for i in range(10):
... lst.append(i + i)
...
>>> lst
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
Or just this: >>> lst = [i + i for i in range(10)]
>>>
>>> lst
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> lst = [range(0, 10, 2)] lst = list(range(0, 20, 2))To iterate through it without doing one of those things, you use a for loop.
In “one obvious way to do it”, “it” refers to a concrete task; the same is not necessarily intended to be true of arbitrarily broad generalizations of classes of tasks.
There should be at least one-- preferably only one --obvious way to do it.
Kinda funny meta joke considering everybody conflates "one" and "only one" to mean the same thing. Preferably there would only be one obvious way to describe "one". :pNot in comparison to Perl, which usually has multiple ways to do anything, each 'obvious' to different sets of people (each Perl codebase therefore seems to have a distinct dialect based on which 'obvious' alternatives are chosen).
The other direction languages can take that is being contrasted, is there being one non-obvious way to do something.
Python's 'most obvious way' isn't necessarily the fastest/most concise/most efficient/scalable/etc. way to do something in Python, but it will usually be obvious to most Python developers. And although broad styles have certainly developed over time (imperative, functional, OO) as Python has gained power and flexibility, the dictum still largely holds true.
ie, instead of
for line in lines: print(line)
we are supposed to be using
while line := f.readline(): print(line)
I've not been super impressed with this type of thing.
That said, string formatting is better with f strings.
They also rolled back some the forced breakage from trying to force unicode with 3 which made a big difference. 3.3 added back u''
Lots of good cleanups lstrip vs removeprefix etc.
Underscores in numeric literals (10000000 vs 10_000_000)
So lots of good stuff still landing.
> for line in lines: print(line)
> we are supposed to be using
> while line := f.readline(): print(line)
No, we’re not. Walrus, in loops, IME, is more for replacing this pattern:
while True:
myvar = get_it()
if not ok(myvar):
break
# code that uses myvar
with this pattern: while ok(myvar := get-it()):
# code that uses myvarI'm not the only one who looked at the recommended examples of the use case here and went, huh?
https://news.ycombinator.com/item?id=17450890
Recommended new way:
if any(len(longline := line) >= 100 for line in lines):
print("Extremely long line:", longline)
Old way: for line in lines:
if len(line) >= 100:
print("Extremely long line:", line)
break
I prefer the old way. These were examples in the PEP!In your example get_it() might be better as a generator or iterable. A lot of code looks great if you push that type of thing down a bit, and sometimes memory is helped as well. Then you iterate over it, for values in get_it. This keeps python very natural. You start to get a lot of weird line noise type code with := vs the old python style which while a bit longer was basically psudo-code.
All it does is increase line-noise, and for what? So we don't have to write 2 short lines, or save an indentation level somewhere?
There is a good reason why assignments in Golang are not expressions, even though they are in C, and the language is otherwise deliberately close to the mindset of C; The added convenience makes the code much harder to read.
Sure;
char c;
while((c = getch()) != EOF) {
// do something
}
requires less lines than; char c;
while(1) {
c = getch();
if (c == EOF)
break;
// do something
}
but it's also easier to read, because each line carries less information. That's what people call "line noise".IMO, := is a step in the wrong direction, and sadly I see python take more and more of these, going from the deliberately simple and clear language to something that's becoming needlessly hard to read by piling on things it doesn't even need.
I knew Python wasn't for me in my first foray into it when I fired its REPL and then went to exit it with control-C or whatever and it literally printed out the right way to do it but then didn't do it. Python was more interested in having me do things a certain way even when it knew what I intended to do, just to be a twit.
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
You will get that error response. The goal of this is to have the REPL language the exact same as the scripting language. exit() is supposed to be called as a function to make the language more consistent, so just typing `exit` will do nothingUseful would be, if the default handler for SIGINT would not raise an exception, but have a useful default like eg. terminating the program. Go handles SIGINT this way by default.
If I want an exception, I can just tell the program:
import signal
signal.signal(signal.SIGINT, throwException())
The way it is now, the exception bubbles up to runtime, and if it isn't handled (eg. in the REPL) the program crashes, or worse, hangs if there are other threads of execution running: import threading
import time
def sleepN():
for i in range(20):
time.sleep(1)
threading.Thread(target=sleepN).start()
time.sleep(20)
Press c-C here, and the thread will still run, because the bubbled up Excp only kills the main thread. This is a real footgun in applications which rely on SIGINT being a termination signal, and have long running threads. $ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>> exit.eof
'Ctrl-D (i.e. EOF)'
>>> exit.name
'exit'
>>> exit = 42
>>> exit
42
>>> exit()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>>
I would have special-cased exit, though.from that context it makes sense, because the only goal of python in the 1990s was to be more popular than perl, which was notorious in having many ways of doing the same thing.
but yeah, python had had significant feature creep over the years, it's nowhere near the small clear lang it used to be.
match/case (not a drop in switch statement)
>breaking out of loops
break
>ending scripts early (for explorative programming) exit() or sys.exit()There's match/case in 3.10 - https://www.python.org/dev/peps/pep-0636/
Is it really that crazy do set up a figure, axes on that figure, and plot on the axes, returning an artist object for each plotting command?
The Figure is the final image that may contain 1 or more Axes.
The Axes represent an individual plot (don't confuse this with the word "axis", which refers to the x/y axis of a plot).
This is infuriatingly bad and I firmly believe that it makes sense only to people who already know how it works. There's an image, axes (this word alone is a crime), plot, figure... it's like they took a bunch of synonyms and arranged them randomly to put together an API.why so? you prefer something like axiis?
> Axes object is the region of the image with the data space.
In matplotlib axes is not the plural of axis. It has its own meaning specific to the API. And at the same time it's the plural form of another word (axis) which is also relevant in this context and it sounds almost identical when pronounced.
https://www.mathworks.com/help/matlab/ref/axes.html
https://www.mathworks.com/help/matlab/ref/axis.html
https://www.mathworks.com/help/matlab/ref/figure.html
So they emphasize the cartesianess of the axes.
If I was designing something like it, I wouldn't recommend either. The global one has many fewer WTFs per character, but the objects one looks like it works in a multithreaded program or that you can create more than one plot without displaying them (but I've never tested this).
Personally, I like plotting in R way better than in python. It has a lot better developer UX.
What? Something being complex is artificial, we try to avoid it. Problems can be complicated, we try to simplify them, and more complicated the problem is, we tend to develop more complex solutions. So comparing them does not make sense?
Or did I always know them wrong?
Complicated: consisting of many interconnecting parts or elements; intricate.
Nothing specifically artificial about either one. Software that is well decomposed is Complex (made of many smaller connected parts). Software that is is poorly decomposed is Complicated (made of many smaller interconnected parts).
Connected vs interconnected?
Interconnected: connected at multiple points or levels (aka spaghetti code)
Complex: we took all of these simple steps, lumped them together, now we have this
I always took it to mean 'complex' as in having many connected parts, and 'complicated' more as in over-complicated or convoluted - the opposite of 'simple'. In other words, breaking something complicated into a system of intentionally-designed pieces is probably better than a chunk of opaque code to brute-force the current case. A good system is probably also 'simpler', despite having more pieces and interconnects.
My understanding is that: * Complex domains lend themselves to experimentation and emergent behavior. * Complicated domains lend themselves to analysis, expertise, and rule following.
The Wikipedia article offers the domains as containing "unknown unknowns" and "known unknowns" respectively.
I'm trying to think how this maps to Python -- the language is complicated, while the problems we're solving are expected to be complex? Or, maybe, the language lives at the boundary between complicated and complex. We push complicated procedures into the language, and let the programmers deal with complex issues?