Python decorators are basically true proxies. The code being decorated or the code that calls it - does not need to be aware in any way of the decorator’s presence, and the decorator gets inserted into the call stack and has access to all call parameters, including the lambda of the decorated function.
Regarding context managers I would need to come back to this post, as I don’t think IDisposable is capable of solving the same use cases, but it’s not on top of my mind as to why.
I'm definitely not as fluent in python as I am in c#, but don't context managers just allow you to define an __enter__ and __exit__ methods that are called when a `with` block begins and ends, respectively? That closely aligns to defining a constructor and .close() method on an IDisposable class, then creating an instance with a `using` statement.
Genuinely curious: aren't Python decorators basically the same as C# annotations, and aren't context managers covering the same ground as a C# using statement?