Could something just heuristically add del statements with an AST transformation that we could review with source control before committing?

When the gc pause occurs is something I don't fully understand. For example:

FWIW, this segfaults CPython in 2 lines:

import ctypes
ctypes.cast(1, ctypes.py_object)

Interestingly, this (tends to?) work; even when there are ah scope closures?:
import ctypes, gc
x = 22
_id = id(x)
del x
y = ctypes.cast(_id, ctypes.py_object).value
assert y == 22

Adding explicit calls to del with e.g. redbaron or similar would likely be less surprising.

Or something like a @jit decorator that pros would be aware of (who could just add del statements to free as necessary)

On Wed, Apr 8, 2020, 10:29 PM Caleb Donovick <> wrote:
This would almost certainly break my code.   As a DSL developer I do a lot of (exec | eval | introspection | ... ) shenanigans, that would make doing liveness analysis undecidable.

On Wed, Apr 8, 2020 at 10:51 AM Andrew Barnert via Python-ideas <> wrote:
On Apr 8, 2020, at 09:57, Guido van Rossum <> wrote:
> Look at the following code.
> def foo(a, b):
>     x = a + b
>     if not x:
>         return None
>     sleep(1)  # A calculation that does not use x
>     return a*b
> This code DECREFs x when the frame is exited (at the return statement). But (assuming) we can clearly see that x is not needed during the sleep (representing a big calculation), we could insert a "del x" statement before the sleep.
> I think our compiler is smart enough to find out *some* cases where it could safely insert such del instructions.

It depends on how much you’re willing to break and still call it “safely”.

    def sleep(n):
        global store
        store = inspect.current_frame().f_back.f_locals['x']

This is a ridiculous example, but it shows that you can’t have all of Python’s dynamic functionality and still know when locals are dead. And there are less ridiculous examples with different code. If foo actually calls eval, exec, locals, vars, etc., or if it has a nested function that nonlocals x, etc., how can we spot that at compile time and keep x alive?

Maybe that’s ok. After all, that code doesn’t work in a Python implementation that doesn’t have stack frame support. Some of the other possibilities might be more portable, but I don’t know without digging in further.

Or maybe you can add new restrictions to what locals and eval and so on guarantee that will make it ok? Some code will break, but only rare “expert” code, where the authors will know how to work around it.

Or, if not, it’s definitely fine as an opt-in optimization: decorate the function with @deadlocals and that decorator scans the bytecode and finds any locals that are dead assuming there’s no use of locals/eval/cells/etc. and, because you told it to assume that by opting in to the decorator, it can insert a DELETE_FAST safely.

People already do similar things today—e.g., I’ve (only once in live code, but that’s still more than zero) used a @fastconst decorator that turns globals into consts on functions that I know are safe and are bottlenecks, and this would be no different. And of course you can add a recursive class decorator, or an import hook (or maybe even a command line flag or something) that enables it everywhere (maybe with a @nodeadlocals decorator for people who want it _almost_ everywhere but need to opt out one or two functions).

Did Victor Stinner explore this as one of the optimizations for FAT Python/PEP 511/etc.? Maybe not, since it’s not something you can insert a guard, speculatively do, and then undo if the guard triggers, which was I think his key idea.

Python-ideas mailing list --
To unsubscribe send an email to
Message archived at
Code of Conduct:
Python-ideas mailing list --
To unsubscribe send an email to
Message archived at
Code of Conduct: