125 comments

[ 2.4 ms ] story [ 220 ms ] thread
(comment deleted)
This is the first time I've learned of this. How it compares to PyPy [1]:

> PyPy is an implementation of Python with its own JIT. The biggest difference compared to Pyjion is that PyPy doesn't support all C extension modules without modification unless they use CFFI or work with the select subset of CPython's C API that PyPy does support. Pyjion also aims to support many JIT compilers while PyPy only supports their custom JIT compiler.

Apparently it's originally a Microsoft project, and it requires .NET. The project already exists for a few years, but it looks like they've gained net performance improvements over CPython only the past few months [2].

[1] https://github.com/tonybaloney/Pyjion

[2] https://github.com/tonybaloney/Pyjion/issues/198

Isn't this what the GraalVM [1] guys are also trying to do? Seems like today the competition is between who is more polyglot than the other, JVM, CLR or WASM.

[1] https://github.com/oracle/graalpython

A big difference is the Pyjion generates .NET compiler IR manually, while GraalVM generates Graal compiler IR automatically through partial evaluation of a declarative specification of an interpreter specialised to the program (the first Futamura Projection.) In my opinion that's far more powerful in terms of removing abstraction. But Pyjion also seems like a very cool project.
Damn I didn't know any of the Futamura Projections where actually implemented in practice.
Sounds to me like PyPy has been using Futamura projections for a decade or so.
Can you link me to some sources? I'm not familiar with PyPy but I thought it's a normal tracing JIT. In fact quick googling shows a blog post explicitly saying PyPy does NOT use PE: https://www.pypy.org/posts/2018/09/the-first-15-years-of-pyp....

Besides not every PE instance is a Futurama Projection.

PyPy is two projects.

1. RPython + the PyPy _compiler_ which is a compiler for JIT compilers (like GraalVM as I understand it)

2. An implementation of the Python language _using_ RPython to produce a JIT for Python scripts.

There are other languages _using_ RPython + PyPy compiler to produce JIT compilers for languages other than Python too.

https://doc.pypy.org/en/latest/architecture.html#layers

I see. This doesn't look like a Futaruma Projection to me. What PyPy does is run a python program under their own RPython based interpreter. Then it uses a tracing JIT to JIT the RPython based interpreter. There is no PE going on. No residual specialized program is created.

The first Futaruma Projection would be if PyPy would specialize the interpreter based on the python program yielding an executable.

That's exactly what PyPy does do. You get a specialized version of the interpreter which is specialized to the particular program.
No you don't get that. A tracing JIT is not capable of producing an executable like that under normal circumstances. If a certain path is not taken during execution it might not be compiled at all. The point of the first futurama projection is that you get a fully runnable executable that is semantically equivalent to running the original program in the interpreter. A JIT only produces what it sees during execution. I guess it might be possible if you carefully run your program with inputs that exhaust every possible path.
Clearly PyPy has to produce executable code if it wants to jump into it. The CPU wouldn't understand if it were asked to jump into something that isn't executable code.

> The point of the first futurama projection

...was to delight viewers with what would turn out to be a wonderful pilot episode?

It produces executable code ad hoc based on the dynamic environment. Not an executable. That's not the same thing.
I don't see how the frequency or laziness of the process makes a meaningful difference. It takes an interpreter, evaluates it with partial information (like, "type of x is integer"), and delays the rest till the execution is possible with the remaining information (like, "x is 7").
An pure executable no, but a JIT cache certainly.

Used across Java implementations, and modern Android.

As far as I remember, PyPy uses a Python interpreter written in RPython that's being specialized with respect to the actual Python code to be executed, with the residual program implementing the semantics of that one Python program that's been fed into it.
You're right, PyPy _used_ to base it's wizardry on PE (I don't know if it's Futurama or not, that's honestly the first time I hear of that term), but now they are using something called meta-tracing JIT, where, instead of JIT-tracing the program that your language's source describes, they JIT-trace your interepreter while it's running your language's source.

The extremly cool and awesome thing about this is that this is effectively a general purpsoe JIT, one JIT to rule all interpreted languages that could ever be written. There is nothing specific about Python in the toolchain. For _Any_ interpreted language:

- You write only your naive-but-readable interpreter in Rpython, a restricted subset of python that tries to preserve the readability but ditch the dynamic madness. (This is not python, this is an entirely different language. It just happens that every valid Rpython program is also a valid Python program. There is nothing special about Rpython here either, they could have theoretically picked any readable language to write your naive interpreter in, but they chose Rpython)

- The compilation pipeline produces two things: an exectuable image of your naive interpreter*, and a bytecode image for the general-purpose JITer.

- Normally, it's the executable image of your interpreter that runs your language's programs, but once it detects a user-program-level loop (e.g. because it has encountered a backward jump.), it invokes the supporting runtime (the general-purpose JITer) and delegates to the bytecode version of itself.

- The GP JITer starts tracing the bytecode image of your interpreter (which, remember, is itself executing the user-level program the whole time), once it detects that the user-level loop is done, it says so. Now the general-purpsoe JITer has a record of all the operations that your interpreter executed while it was running the user-level path, which is the same as {all the operations that the user-level path executed} (minus all the interpreter-specific operations, which the GP JITer also knows about because this info is contained in the bytecode)

- The GP JITer treats the execution record as any other JIT, it produces an optimised native version from it, and bingo!, you got yourself a native image of that user-level loop.

- The original interpreter, the executable, now goes back into the picture. It puts that native version of the loop in its pocket, ready for the next time it encounteres the loop.

It's so f*ing cool, that's why their logo is a snake eating itself: there's so much meta shenanigans going on. Their implementation of Python is merely the application, it's the amazing toolchain they built to build it that is the real treasure.

*: One of the steps in creating the exectuable is, I kid you not, is running the standard Cpython interpreter on your Rpython source (as it's valid python), waiting for interpreter to do it's expensive startup, then freezing the whole enviroment it produced to package it with the executable. This couldn't be done to speed up normal Python because its extremly dynamic nature messes with this.*

(comment deleted)
https://gist.github.com/tomykaira/3159910

This gist talks specifically about PyPy using the Futamara projection.

The linked text is pretty bad, having many mistakes. Please see the two comments at the end of the page.

For a better overview on what the projections are, please see http://blog.sigfpe.com/2009/05/three-projections-of-doctor-f... , or the original paper by Futamura.

Thank you, this is super helpful -- I didn't look close enough to spot that myself. :)
For some reason I read this as Futurama projections.
WASM isn't on the same league until it offers GC support.
So this is basically a newer, cooler IronPython?
No, it's cpython in a trenchcoat, not written in .net, not ridding the .net vm. But it uses the JIT from .net.
From FAQ[1]:

> IronPython is an implementation of Python that is implemented using .NET. While IronPython tries to be usable from within .NET, Pyjion does not have a compatibility story with .NET. This also means IronPython cannot use C extension modules while Pyjion can.

[1] https://github.com/tonybaloney/pyjion#ironpython

So it basically uses .NET in place of something like, LLVM, in order to generate native code. Clever.
One of the Pyjion contributor worked on IronPython before.
Why is there so little mention of https://cython.org/ ?

It's very fast, it compiles to C code, then compiles the C code with a normal compiler.

My understanding is that Cython does not run unmodified standard Python code.
It can run most unmodified Python code, but it needs types for the big speedups.
That's misleading as normal type annotations don't give you any performance benefit at all and you may need to do a lot more than just add type annotations.

I think it's far more accurate to say that Cython is a programming language of its own that is a hybrid of Python and C++, that happens to produce CPython extension modules when compiled.

The performance benefits are really achieved by incrementally changing your Python code to something that looks a lot more like C(++).

This is also reflected in the Cython documentation which literally mentions the "Cython language".

Cython is great as an alternative to writing C extension modules for performance reasons or to creating bindings to libraries written in C or C++. It's not so great just to make Python applications faster as it's not fully compatible[1].

[1]: https://cython.readthedocs.io/en/latest/src/userguide/limita...

"This page used to list bugs in Cython that made the semantics of compiled code differ from that in Python. Most of the missing features have been fixed in Cython 0.15. A future version of Cython is planned to provide full Python language compatibility."
> The performance benefits are really achieved by incrementally changing your Python code to something that looks a lot more like C(++)

I completely agree. Cython can become quite attractive if your alternative is "write a python extension library by hand in C / C++". I first started using Cython after doing exactly that, writing my extension library in C, then realising that Cython might save a lot of work in generating the bindings and packaging/distribution -- it did, and it ran at exactly the same speed as my pure C library with hand crafted python bindings. After that I've been pretty excited about Cython.

If you've got a python program that needs to do a core of compute-heavy work, if you were to optimise this by writing a C / C++ library for python to use, the work would be: (i) think hard about how the library design will enable performance, (ii) implement that high performance library in C / C++ , (iii) figure out the interface so that python can call into the library, and (iv) figure out how to package and distribute the library so it can be used by python programs.

Cython doesn't really help with parts (i) designing for performance or (ii) writing that high performance code. But it helps a lot with parts (iii) and (iv), generating Python bindings and producing wheel archives that can be managed by existing python package management tooling.

It usually does work on individual small functions, in my experience.

I've seen 2x improvement on string processing code (cleaning text for input to a ML model) by doing nothing other than sticking `%%cython` at the top of a notebook cell.

I don't know if this technique scales to other applications; probably not. But Cython syntactically is a superset of Python.

(comment deleted)
I mainly programmed in Cython for a few years, and never came across standard Python code it wouldn't run. It's just usually only a few times faster than Python using unmodified Python, as opposed to 50x-200x faster or more with type annotations, GIL turned off for bottleneck functions, @ decorators etc.

I loved it, being able to float between Python and C in a program, writing in Python whatever was more convenient in Python, in C whatever was more convenient in C, or anywhere in between.

"While pure Python scripts can be compiled with Cython, it usually results only in a speed gain of about 20%-50%."

https://cython.readthedocs.io/en/latest/src/tutorial/pure.ht...

That's not Hacker News, it's Hacker Olds.
Cython is much easier to implement than people realize. A few import statements and a few types, and then you're good to go. I urge people to give it a try. The speedups can be dramatic.
It certainly is good, but I've never found a great dev setup. It seems like you have to force a full recompile of all cython in the project any time you make a change. At least that was the stated process for the statsmodels library. And it was always a little unclear whether I was running the latest code or hadn't yet actually compiled it.
I've never used cython before. Is it 1-to-1 with standard Python? If so, can you do development using the regular Python binary, and leave the compilation step as a pre-commit operation?
The workflow with Cython is that it produces native python modules (e.g. .so shared objects / .dll dynamic link libraries) that the python interpreter can import.

So if you change some of your Cython code, for it to be used at runtime you need to invoke the Cython build tools to rebuild the new version of your python native module.

I usually use Cython for a small core of compute heavy operations, and leave the rest of the project as pure python. That way I only need to rebuild Cython code if I change something inside that small core.

> Is it 1-to-1 with standard Python?

Not for the best speedups, no.

E.g. you might be able to get a modest speedup, say 50%, taking a pure python file, renaming it to *.pyx, and getting Cython to compile it. But that's not why I use Cython. I use it when I have compute-heavy code that I want to run at native speed (think matrix-vector product type stuff), by carefully rewriting in Cython, thinking carefully about memory allocation, data structures (prefer C arrays!) and performance, it is fairly achievable to get a 500x speedup.

Cython relies on you writing specialised Cython code that is quite close to C code -- strongly typed Cython variables work like statically typed C variables, not dynamically typed Python names. You end up with Cython code that cannot be executed as if it were normal Python code by a python interpreter.

But, Python code can usually not be executed very efficiently, whereas Cython can translate small loops of strongly-typed numeric code into small loops of strongly-typed C code, which can often compile to very small loops of native CPU instructions, which then run blazing fast.

Under the hood, Cython works by translating the not-quite-python code into C code that uses the python interpreter's C extension API. Then it compiles the C code into a python native module using a C compiler.

Thanks for pointing this out. I didn't realize this until I read further into this thread and started looking at optimized cython projects. Now I understand what you're talking about.
It's not 1-1. Cython can compile regular Python, but you only really get significant speedups when you declare the types of things using cython-specific syntax.
Cython is used very widely in the Python ecosystem. It's rarely mentioned precisly because it's so pervasive.

But it's also not the same thing - AOT doesn't always mesh well with how dynamic Python is, but JIT can take care of all the more advanced scenarios with runtime-loaded or runtime-generated types and code.

Can the dotnet dependencies be installed in Python?
Does it have GIL? IronPython and Jython does not. https://wiki.python.org/moin/GlobalInterpreterLock

How about Numpy performance?

It's not an alternate runtime, so the GIL is still there and Numpy performance should be unchanged, though any pure-Python modules from Numpy could potentially benefit from the JIT speedup.
It is not a complete rewrite. It basically just replaces the bytecode interpreter (which is a documented extensibility point) in regular CPython.
> Some benchmarks have a slow max/mean value because the time includes JIT-compiling large libraries like Pandas.

So why do not they warm the JIT up first? Moreover the graph does not contain any notion of mean/max values at all. Any idea where I can see a more comprehensive benchmark?

The overall speed-up factor (calculated from the numbers in the Benchmarks diagram, geomean of factors) is 1.6, which is much less than the factor 4 achieved with PyPy (or the even higher factor claimed by Graal Python). CLI is not very well suited for dynamic languages; as far as I remember the results presented here correspond with Iron Python, which is to be expected based on the proposed concept.

EDIT: Yes, indeed pretty much the same factor, see e.g. https://web.archive.org/web/20090324020143/http://www.codepl...

Assuming zero compatibility problems and a simple drop in, I say 1.6 is pretty damn good from the start.

Ruby' drop in YJIT barely managed ~20% speed up.

From the details on https://pypi.org/project/pyjion/

> Goal #1 is explicitly to add a C API to CPython to support JIT compilers.

Given the plural compilers, hopefully this means it's going to support multiple JITs, which would be interesting. Choose the right JIT for your particular workload.

That particular statement was written several years ago. In practice, the API in question boils down to letting you plug in your own implementation of PyEval_EvalFrameEx. This has already been added in Python 3.9:

https://www.python.org/dev/peps/pep-0523/

As the PEP notes, this is useful for a lot more than just JIT. In particular, modern Python debuggers use it to dynamically patch bytecode to make breakpoints more efficient.

Pyjion requires: CPython 3.10 and .NET 6

.NET 6 Release: 19 hours ago (https://github.com/dotnet/core/blob/main/release-notes/6.0/6...)

... ok.

We found the Arch Linux developer XD "All hail rolling releases, why haven't you updated yet? I published it 15 minutes ago!"
.NET 6 has been in prerelease for a while, and it's the next LTS release. Makes sense that it would be used as soon as it was available. Upgrading from 5 to 6 should be pretty trivial.
I've tried it on Fedora:

https://docs.microsoft.com/en-us/dotnet/core/install/linux-f...

> The latest version of .NET that's available in the default package repositories for Fedora is .NET 5. Installing .NET 6 through the default package repositories is coming soon. For now, you'll need to install .NET 6 in one of the following ways:

> Install the .NET SDK or the .NET Runtime with Snap.

> Install the .NET SDK or the .NET Runtime with a script.

> Install the .NET SDK or the .NET Runtime manually.

Nope, thank you

.NET 6 was just released this morning, so I'd assume it will take at least a little bit of time to get into the default package repositories.
Well, if one wants stability and production releases, why would they be trying a new, experimental, JIT compiler for Python?
If it just required doing "pip install" then I'd try it to see how fast my test suite runs. But since it only works with Python 3.10 and .NET 6, realistically even just spending five minutes messing with it will require first waiting 18 months or whatever.
Seems like it would take no more than 5 minutes to download and untar the listed dependencies, though. I don’t understand this attitude about experimentation.
I might mess up my computer!!

some people are helpless without their package manager and the maintainers that tell them what software that can run

You can even neatly do it in a docker container that you throw away after if you don't want to mess up anything locally.
Haha that's the rabbit hole. Two weeks later you're compiling your own kernel from sources just to be able to get that specific version of libc so that you can get libfoo working so that you can get libbar working so that you can get... You get the idea.
been there, done that, got the tshirt and worthless equity ;)

these days, just spin up some disposable container/vm and tinker...

> waiting 18 months or whatever

Seems like a problem with however your system distributes software, not with Pyjion.

What does it take 18 months to do?

Well for one I can't run Python 3.10 in production because I use AWS Elastic Beanstalk, which currently only supports 3.8. And my development environment is Ubuntu, which also doesn't support it out of the box. So short of scheduling two weeks to retool both my production and local development environments, which I'm not going to do because it would be a complete waste of time, there is zero benefit to me to even looking into this.
Right, but those are you-problems. You use a way to get dependencies that's very slow. That's not a Pyjion problem.
> That's not a Pyjion problem.

I wasn't criticizing Pyjion, I was responding to coldtea's comment saying that people who can't run this in production would likely not be interested in trying it. I have zero issue with Pyjion, and I'm also happy with my production setup as is.

>Well for one I can't run Python 3.10 in production because I use AWS Elastic Beanstalk

And why wouldn't you want to try this in production in the first place?

Check out pyenv, you can run whatever versions of python you want to without messing with the system or other virtualenvs.
(comment deleted)
Pyjion 1.0 was released yesterday, so that checks out? :)
I don't really see the benefit over Nuitka, or even a JIT like Numba. Can someone help?
Neither of those is a drop-in replacement for CPython.

It would be better to compare this project to, in addition to CPython: PyPy, GraalPython, Pyston, Cinder, Jython, and IronPython. As well as the now-inactive Psyco project, and possibly also Stackless Python.

It should be noted that Pyjion in particular is CPython. It's not even a fork - it's a native CPython module that provides a replacement for the stock bytecode interpreter (for which CPython has an API). Everything else is the same, so it's compatible with pretty much any random native module compiled for CPython.
Known Limitations With statements Pyjion does not currently support with blocks.

This is on the roadmap (and related to try..except).

=====

I thin with block is used all of the places, so this limitation make it not usable to a lot of projects

Python is in a situation where it is enormously popular, due to a winning aesthetic in syntax/ergonomics that appeals to both newbies and experienced programmers. And due to this success, there is a lot of demand and interest in speeding the language up and getting rid of the GIL.

But paradoxically, this veneer of simplicity hides an incredible amount of complexity. You have to read hundreds of lines of CPython to understand the full semantics of a statement like "a + b". The semantics are complicated/compromised by many optimizations and implementation details of CPython. This is a fantastic talk that goes into these details: https://youtu.be/qCGofLIzX6g

It is not good for anybody that the semantics are this quirky. But it's especially not good for people trying to optimize the language, who basically have to implement quirk-for-quirk identical semantics to what CPython has ended up with after 30 years of evolution and optimization.

I wish Python 3.0 had included a more formalized and cleaned up set of semantics. These things can't be simplified without a breaking change to the language (even if only a small number of programs truly depend on these quirks). I would say Python should fix this in 4.0, but the 2->3 transition was so painful and long that I'm not sure the ecosystem can take it.

It wouldn't be too bad if it was complicated, but explicitly documented and tested.

For example people joke about JavaScript comparison semantics posting things like this https://i.stack.imgur.com/35MpY.png and laughing about it. But I wish Ruby and Python were this explicit and easy to understand!

Python docs have pages on the execution model and data model, with notes in implementation details. What more do you want?

https://docs.python.org/3/reference/executionmodel.html

https://docs.python.org/3/reference/datamodel.html

Reading these documents is not hard, and it’s been an enormous help over the years for writing effective efficient Python.

> What more do you want?

Something formal, so I can actually reason about it and test it.

These documents are just informal prose. Are they sound? I don't know. Do you? Does anyone? Does my implementation match what they say? Who knows. Does CPython even match it? Does anyone know?

Out of curiosity, how many languages would meet those criteria? Only one I can think of off the top of my head is CompCert's C dialect. Are there others?
It's a spectrum - some languages do it a lot better than others. Not having anything more than a conversational English description of what it does is definitely the lower end of the spectrum. I'm sure very few are doing it perfectly, but for example Java has a formal semantics.
> but for example Java has a formal semantics.

I don't think that's really true. The Java language specification is entirely prose. The book you linked to was written by "outsider" authors and published in 1999 (!).

Standard ML certainly has clear specifications and proofs of soundness of the type system.
As an outsider this may be your perception, but this is not how python's documentation works.

> These documents are just informal prose.

Not true. They're the language spec. Every guaranteed behavior of python is described clearly and concretely in these documents.

> Are they sound?

Yes.

> Does my implementation match what they say?

Yes.

> Does CPython even match it?

Yes.

> Does anyone know?

Yes! There's a very rigorous and thorough set of unit tests that specifically test an implementation's ability to match precisely the behavior described in these documents. All implementations (that I'm aware of, eg. cpython, pypy, jython, etc) state which versions of the spec they are compatible with, in other words they pass the unit test suite for that version.

Further, the maintainers of python (and by that I mean, regular contributors to the python-dev mailing list, not a cabal of robed individuals in a cave somewhere) are deeply aware of the language of the spec, the way the test suite implements it, and the importance of maintaining this relationship.

>> Are they sound?

> Yes.

That's great! Can you point me at the formal proof? I haven't seen it myself.

> There's a very rigorous and thorough set of unit tests that specifically test an implementation's ability to match precisely the behavior described in these documents.

How can you test against English prose? You can't. So someone's manually translated the prose into tests elsewhere I guess. Have they done that correctly? How can we verify that? Was there any ambiguity when they were interpreting the English?

It's easy to see where these simple English descriptions aren't covering everything. To give you a practical example - look at https://docs.python.org/3/reference/datamodel.html#object.__... - 'should return False or True' - what if it doesn't? Where's that specified? Is it somewhere else in this document? That's the kind of practical issue we work with when implementing languages.

> That's great! Can you point me at the formal proof? I haven't seen it myself.

Can you point me at the proof for the soundness of the documented behavior java or javascript or C++ docs? A cute little table isn't a substitute for soundness, and none of the languages you mentioned are mores soundly implemented (at least in their popular implementations).

> It's easy to see where these simple English descriptions aren't covering everything. To give you a practical example - look at https://docs.python.org/3/reference/datamodel.html#object.__... - 'should return False or True' - what if it doesn't? Where's that specified? Is it somewhere else in this document? That's the kind of practical issue we work with when implementing languages.

Cpython raises an exception, and in general, cpython is the spec unless otherwise specified is how things turn out.

> How can you test against English prose? You can't. So someone's manually translated the prose into tests elsewhere I guess. Have they done that correctly? How can we verify that? Was there any ambiguity when they were interpreting the English?

This is sort of a silly complaint. every spec is implemented in english prose[1]. That's why we end up with arguments about SHALL vs. MUST in the specs. Except in the rare cases where the spec is a test suite, which usually reduces to the case of cpython: the popular implementation is the spec (or maybe the popular implementation forks its test suite out into a different repo to make it more "independent")

[1]: Please don't make a irrelevant point about an obscure implementation of C that's implemented in agda and the "spec" is the proof of soundness or whatever, that's fundamentally the same as the implementation is the spec, especially given that said C implementation probably isn't ANSI compliant or whatnot.

> Can you point me at the proof for the soundness of the documented behavior java or javascript or C++ docs?

https://link.springer.com/book/10.1007/3-540-48737-9

Java does have a formal semantics, with a whole chapter on its soundness.

> in general, cpython is the spec

Well there we go - turns out the written document doesn't cover everything after all. A second ago we were at 'Every guaranteed behavior of python is described clearly and concretely in these documents.' Turns out not.

I'm not criticising Python as being exceptionally bad, but we can certainly do it much better.

> Java does have a formal semantics, with a whole chapter on its soundness.

No, there's a chapter on the soundness of its type system. The spec being sound and the type system being sound are very different things. If we consider typescript to be JS's type system, then JS's type system is unsound. If we consider cpython in isolation, under the definition you're using, cpython cannot be unsound, as it is untyped, QED.

If you're talking about whether the language's type system is sound, asking "These documents are just informal prose. Are they sound?" isn't even a well defined question.

> I'm not criticising Python as being exceptionally bad, but we can certainly do it much better.

You absolutely were when you said "But I wish Ruby and Python were this explicit and easy to understand!"

You're arguing with the guy who did truffleruby. I'd say he knows a thing or 2 about the soundness of dynamic languages and adhering to a formal spec.
(comment deleted)
Argumentum ab auctoritate.
Have you seen the Python docs which have pages on the execution model and data model, with notes in implementation details?

https://docs.python.org/3/reference/executionmodel.html

https://docs.python.org/3/reference/datamodel.html

In your second link it says:

> For instance, to evaluate the expression x + y, where x is an instance of a class that has an __add__() method, x.__add__(y) is called.

The talk I linked to (https://youtu.be/qCGofLIzX6g) is a deep dive on how there is much more to the story than the simplified statement above.

What I wish for is not better docs, but rather simpler language in which the statement above would actually be an accurate specification of the behavior implemented by the interpreter.

I guess you are trying to imply that those documents cover a formal-enough description of what the execution and data model is. Well, even for the section "names" it just forgets to say if imported and non-imported names all share the same encoding and which should it be - just a nitpick, but with less than 5 seconds. Do you know that there are some behavioral limitations of dict that arise from a specific optimization in the implementation in C of dictionary iterators? If you create a new python following those documents, it is possible that you will allow a perfectly reasonable behavior that would fail in most other python interpreters.
> Well, even for the section "names" it just forgets to say if imported and non-imported names all share the same encoding and which should it be - just a nitpick, but with less than 5 seconds

https://www.python.org/dev/peps/pep-0263/

Names aren't unique.

> Do you know that there are some behavioral limitations of dict that arise from a specific optimization in the implementation in C of dictionary iterators?

I'm rather curious what you're referring to here, do you mean dict-ordering, or something else?

Sorry, but "names aren't unique" does not even begin to define uniqueness - "from ... import X" imports and X; great; should it replace an "X" in a different encoding in the local namespace, or not?

I can tell you it has to do with iterators, and maybe someone will comment on what that is.

I mean... I had not even yet heard the talk that others have pointed you to (from Armin Ronacher); after having gone several times down the rabbit hole of looking at what the interpreter is doing in specific scenarios (and I like lots of things, at the language level, that python does, the terseness and expresiveness that it brings) I also think that python is a very complex language under a soft-looking skin.
I follow Python since 1.6, and occasionally use it for portable scripting when on UNIX platforms (PowerShell on Win), and many aren't really aware that Python is Ada/C++ level of complexity, even if on the first contact seems like the new BASIC.

Besides the nuances of how everything is executed, there are occasionally breaking changes between minor language revisions.

You cannot just pick up a random Python script and be sure it still behaves the same way across all minor revisions.

By names aren't unique, I mean with respect to "encoding", everything is the same. It seems like you're using "encoding" to mean something it doesn't? Do you just mean like "value"?

> I can tell you it has to do with iterators, and maybe someone will comment on what that is.

This sounds like you don't know what it is.

(comment deleted)
> By names aren't unique, I mean with respect to "encoding", everything is the same. It seems like you're using "encoding" to mean something it doesn't? Do you just mean like "value"?

I think the GP means character encodings.

So the intent here is to ask whether (for example) a foo defined in a ISO 8859-1 encoded file is overidden by a foo imported from a Windows-1256 encoded file.

> I think the GP means character encodings.

Then the link I posted answers their question. Names aren't unique in how encodings are handled. Files are decoded and canonicalized as a unicode string. If the identifiers are the same after canonicalization, then yes they are equivalent. If they aren't, then they aren't.

Ah, I misunderstood what you meant by "aren't unique". I would have phrased that as "names aren't treated differently", or something similar.
My gut instinct is that many of Python's quirks are the reason for it's popularity. Though I might not be understanding your suggestion. Could you give a specific example of something you would clean up if you were able to? I have the video in a tab but won't be able to watch until later.
I think "a + b" is a good example.

I really recommend the talk I linked (https://youtu.be/qCGofLIzX6g), it gets deep into this stuff. I don't think anyone benefits from "a + b" having so many special cases.

Forget about language quirks, package management and version management in python is a nightmare. The ammount of time I wasted dealing with python environment related issues alone makes me avoid it if I can.
> Pyjion does not currently support with blocks.

> Pyjion does not currently support async..await (YIELD_FROM) statements.

Those are some major limitations for modern Python code.

https://pyjion.readthedocs.io/en/latest/limitations.html

The point for with blocks claims that this is related to exceptions. How can it handle CPython reference counting during exceptions but fail at cleaning up with blocks?