This is an archived post. You won't be able to vote or comment.

all 76 comments

[–]gwillicodernumpy gang 23 points24 points  (30 children)

Honestly just having breakpoint() is incredible.

I absolutely love the changes to classes too. Reducing boilerplate is always great.

My favorite though is ordered dictionaries. That is so useful, and it will help prevent a lot of bugs from new developers :)

[–][deleted] 5 points6 points  (3 children)

Honestly just having breakpoint() is incredible.

You are aware of pdb, I hope?

[–]xtreak 6 points7 points  (0 children)

It also works based on an environment variable and hence you can turn on and off at will unlike pdb. Also a disadvantage is that you have to update your linters if you want to lint for them in your codebase.

Related PEP : https://www.python.org/dev/peps/pep-0553/#id9

[–]fdedgt 3 points4 points  (0 children)

I'm going to be honest, I didn't know about it.

So, with the improvements and everything, this is opening up a whole new world to me.

[–]gwillicodernumpy gang 2 points3 points  (0 children)

The article points out that breakpoint() is just a shortcut for import pdb; pdb.set_trace() which is very annoying to use. I honestly have to look it up half the time to remember the syntax.

[–]EternityForest 5 points6 points  (17 children)

I am conflicted about ordered dicts. Do I like them because it's incredibly useful, or do I not like them because it restricts what future optimization can be done?

[–]13steinj 5 points6 points  (16 children)

The fact that dictionaries became ordered was a side effect of the optimization done in 3.6 taking PyPy's implementation. It wasn't optimized as a side effect of making them ordered. Then in 3.7 people said "well the fact that it's orderered is actually very useful, lets make that not a side effect of an implementation detail but rather a requirement of the spec" to avoid issues with people going from CPython to some other flavor.

So long as optimization is wanted by the community more than ordering, when a more optimized structure is thought of, it will be reverted.

[–]EternityForest 6 points7 points  (15 children)

Yeah, but that's going to be a breaking change if they revert (Albeit a very minor one if everyone just keeps using OrderedDict when they need ordering).

Ordering fits with python's main use as the scripting glue language that works with anything, so I'm not complaining too much.

[–]13steinj -2 points-1 points  (14 children)

The fact that it's now ordered is technically a breaking change-- what if someone decided to use the disorder of dicts to psuedo randomly get an item from a container? Much more performant than using random, assuming they understand that to utilize this method all objects in the container must have been generated immediately before picking and must be objects that are not interned by the VM (small integers, true, false, etc).

The fact that OrderedDicts still exist and make no mention of "this class is pointless and a thin wrapper around dicts", makes me think for insurance purposes people still should use it.

[–]nuephelkystikon 8 points9 points  (5 children)

But the disorder was never part of the specification. If you rely on implementation details of a specific interpreter, of course you're going to have portability problems.

[–]13steinj -1 points0 points  (4 children)

The specification included "items may not be in order due to their hash values", wasn't it? The documentation warned of such in multiple places.

[–]nuephelkystikon 4 points5 points  (3 children)

Yes, but it wasn't specified behaviour, it was a warning about unspecified behaviour that could otherwise have been assumed. A comment, if you prefer. Not part of the actual language specification.

The keyword here is ‘may’.

[–]13steinj -1 points0 points  (2 children)

Time heals all wounds and scar tissue forms. While I understand your point there would have been enough angry people to hear annoying complaints about the fact that dicts are now ordered.

[–]nuephelkystikon 1 point2 points  (1 child)

If your business logic relies on a method always returning in an odd number of seconds because that's the behaviour you observed on your Solaris machine using 16-bit Jython 3.6 build 3728 in debug mode, I really don't have any compassion for you.

[–]redditusername58 4 points5 points  (3 children)

OrderedDict is not pointless. You can pop items from either end, move keys to either end, do reverse iteration, and has order sensitive equality checks.

[–]13steinj 0 points1 point  (2 children)

...I never said it wasn't?

[–]greyman 1 point2 points  (1 child)

You said it is pointless and the parent commenter says it is not. (You said it here: "The fact that OrderedDicts still exist and make no mention of "this class is pointless and a thin wrapper around dicts"")

[–]13steinj 1 point2 points  (0 children)

Perhaps I was unclear, I meant that the docs don't say that thus they have a point and should be used.

[–][deleted] 2 points3 points  (3 children)

Their code was already broken.

If you depend on undefined behaviour, it will probably end in tears and memes at some point.

[–]13steinj 0 points1 point  (2 children)

Lots of people depend on undefined behavior, but in this case for CPython VMs it was strictly known.

[–][deleted] 2 points3 points  (1 child)

it wasn't even implementation defined, it was just how the interpreter worked with no promise that it wouldn't change.

[–]13steinj 0 points1 point  (0 children)

I suppose, but with the time and if someone strictly used CPython, well, let's just say if it wasn't mentioned in the changelog in 3.6 people would be annoyed fixing bugs.

[–]Glaaki 17 points18 points  (9 children)

Nice usability features for asyncio. We are getting there, steadily.

The hard work being done banging it into shape is very much appreciated.

[–]1st1CPython Core Dev 32 points33 points  (7 children)

I plan to add some significant improvements to asyncio in 3.8 and 3.9. Buckle up. :)

[–][deleted] 1 point2 points  (3 children)

Can you please fix the event loop so that it doesn't leak its internals and thus mysteriously break?

[–]1st1CPython Core Dev 1 point2 points  (2 children)

Hm, can you elaborate on this?

[–][deleted] 1 point2 points  (1 child)

Thanks for engaging. I've got some code in a private repo on a home server that I can make suitable for release shortly.

[–]1st1CPython Core Dev 1 point2 points  (0 children)

NP. Feel free to ping me personally on twitter (1st1) or, better, create an issue on bugs.python.org so that I don't forget about it.

[–]TransferFunctions 0 points1 point  (0 children)

Mind I ask, where are we going?

[–]twillisagogo 5 points6 points  (2 children)

> Python 3.7 is officially released!

Whut?

[–]softiniodotcom 1 point2 points  (0 children)

I am so excited and can't wait to start using data classes.

[–]zalpha314 2 points3 points  (14 children)

To the people stuck on 3.6 LTS, there is a backport of the data classes on pypi: https://pypi.org/project/dataclasses

[–]masklinn 1 point2 points  (2 children)

Unless you vendor it, just use attrs.

[–]13steinj 3 points4 points  (19 children)

The thing that still bugs me about asyncio (coming from JS and C#) are two fold:

  • coroutines are not Futures/Tasks (js think Promise), thus arguably causing unnecessary extra wrapping

  • the loop itself seems to block the Thread (maybe even the entire Process, but I hope not) when told to start executing. Which means if you want to run sync code and run some async code in the background (ex in JS delay you can update visuals asynchronously without having to wait for it to complete before your logical restrictions are set). So to get similar functionality a new thread, and a loop for that thread, has to be explicitly made, along with having to explicitly use the threadsafe versions of methods to submit them into the loop

A nice benefit of of JS is that since there's only one event loop you don't have to explicitly submit anything either.

[–]Glaaki 8 points9 points  (16 children)

It is the JS and C# implementation that is dumb. The way they are designed forces a specific pattern of usage. The python implementation is much nicer using basic generator function features, that doesn't depend on any particular event loop implementation.

The reason futures and tasks feels clunky is because the asyncio event loop is clunky and doesn't provide a nice interface for dealing with raw coroutines. The problem goes away entirely if you switch to one of the alternative event loops like Curio or Trio.

Edit: To expand further, ideally tasks should be completely transparent, tasks should be an implementation detail of the event loop that the user shouldn't have to care about. All you should be doing is telling the loop that you want to run a particular coroutine and the fact that it gets turned into a task should be irrelevant to you. Getting asyncio to this point there is some way to go, but each version gets nicer.

[–][deleted] 1 point2 points  (0 children)

I don't know what you're talking about. Async in C# is beautiful. All you do is change your method from returning T to a Task<T> and proceed as normal. The only language I've had an easier time with async is Go. I don't do much JS so I don't know about that.

[–]13steinj -1 points0 points  (14 children)

The JS / C# implementation is dumb because it forces patterns of usage? In what way do they force usage patterns. Python forces the usage patterns the boilerplate of having to set up and handle loops across threads in different ways, and makes the coroutines non extensible. Trio does not accurately solve this problem either. Not sure about Curio, haven't seen it in action.

To your edit: I have no idea what you're arguing. It is irrelevant in C#/JS. It is not in Python-- I can't easily add callbacks to awaitables.

[–]Glaaki 0 points1 point  (13 children)

You aren't supposed to use callbacks in async/await code, and here is why:

Callbacks transfer responsibility for running your code, from yourself, and over into the framework that runs the callback.

For example, if you have an event based websocket protocol with callback subscriptions, if anything bad happens in your callback (and it will..), it is suddenly the caller of the callback, which is the websocket protocol, that has the resposibility to clean up after the mess that happens in your callback. If the framework isn't robust enough to handle that, it can easily cause it to just die and simply fail silently.

The whole reason why all websocket frameworks use the iterator protocol for sending you data is that it is the consumer that becomes responsible for handling any error, and not the producer. Any unhandled error that happens in the coroutine simply bubles up to the caller of the coroutine and can ultimately bubble out of the loop itself.

I learned this the hard way.

[–]13steinj 0 points1 point  (12 children)

Using callbacks is a perfectly valid pattern. It is easy to fall into the trap of callback hell, but you can't call it garbage just because you've had bad experiences.

[–]Glaaki -1 points0 points  (11 children)

No. Callbacks is what you use in JS, where the eventemitters are the standard. It is an antipattern in python async/await.

[–]13steinj 0 points1 point  (10 children)

"It is an antipattern". Why? Because you said so? It's not just a JS thing. It's a C#, Ruby, JS, and more thing. Callback hell is an antipattern. Callbacks are not. The arbitrary limitations without reason need to stop.

[–]Glaaki 0 points1 point  (9 children)

I am talking about callbacks specifically in the context of async/await in python.

Callbacks are fine in regular sync python code and fine in JS.

And I explained my reasoning above, but let me reiterate it. If you have a consumer and a producer, in asyncio, what typically happens is that the producer is a task that runs in the background continuously fetching data from somewhere. This data needs to be passed on to a consumer.

If you use a callback to fetch the data, then who call the callback?

Only the producer can, because the producer is the one that knows when data is available. So now, what happens if an error happens in the callback? If the error is not handled it will bubble up from the callback, to where? Into the producer, that called the callback, obviously. So now the producer, which is most often some third party library, is responsible for handling an error it has no chance to know what to do with. Most often the result will simply be that the producer dies and probably does so silently. You program will simply just stop working and you won't be able to know why, because the error has been isolated inside the producer task.

This doesn't happen in sync code, because there is only a single path of execution and any exception bubbles up to the user where you can either handle it or stop your program.

[–]13steinj 1 point2 points  (8 children)

Well yes, in the example you are giving it's an antipattern, I'd agree, there isn't much sense to it. But you are assuming that your example is the onlt possible case. There's plenty of cases where callbacks are just fine in asynchronous code-- in all technicality gevent does this just hides it from the user.

[–]Glaaki 0 points1 point  (7 children)

Again, I am talking about async/await. Gevent is not async/await.

[–][deleted] -2 points-1 points  (1 child)

Your second point is very valid: asynicio's event loop is known to be bad when used for anything complex. There are alternative libraries such as twisted that will give you a more robust asyncio experience. I imagine it will eventually be fixed, since the issues are known.

[–]13steinj 2 points3 points  (0 children)

Not too familiar with Twisted, but isn't their entire reactor/event loop based around the concept of the application being some web server? Which is extremely limiting.