On Tue, Jun 22, 2021 at 3:55 AM Soni L.
On 2021-06-21 12:49 p.m., Chris Angelico wrote:
On Tue, Jun 22, 2021 at 1:44 AM Soni L.
wrote: On 2021-06-21 12:26 p.m., Stephen J. Turnbull wrote:
Soni L. writes:
The trick to extension methods is that they're only available when you explicitly use them.
What does "explicitly use them" mean? How does this help avoid the kinds of problems we know that monkey-patching causes?
Monkey-patching:
```py mod1.py import foo
foo.Bar.monkeymethod = ... ```
```py mod2.py import foo
foo.Bar.monkeymethod = ... ```
"Extension methods":
```py mod1.py import foo
def __getattr__(o, attr): if isinstance(o, foo.Bar) and attr == "monkeymethod": return ... return getattr(o, attr) ```
```py mod2.py import foo
def __getattr__(o, attr): if isinstance(o, foo.Bar) and attr == "monkeymethod": return ... return getattr(o, attr) ```
Note how the former changes foo.Bar, whereas the latter only changes the module's own __getattr__. You can't have conflicts with the latter. (Also note that this "module's own __getattr__" doesn't provide extension methods by itself, but can be used as a mechanism to implement extension methods.)
So what you're saying is that, in effect, every attribute lookup has to first ask the object itself, and then ask the module? Which module? The one that the code was compiled in? The one that is currently running? Both?
And how is this better than just using a plain ordinary function? Not everything has to be a method.
Quite the opposite. You ask the local module (the one that the code was compiled in), and the module decides whether/when to ask the object itself.
In other words, every
foo.bar
would be sugar for
__getattr__(foo, "bar")
(where __getattr__ defaults to builtins.getattr) instead of being sugar for
(foo, "bar") (where <> is used to indicate that it doesn't quite desugar that way - otherwise you'd need to recursively desugar it to builtins.getattr(builtins, "getattr") which uh, doesn't work.)
Thanks for clarifying. This doesn't change the problem though - it just changes where the issue shows up. (BTW, what you're describing is closer to __getattribute__ than it is to __getattr__, so if you're proposing this as the semantics, I strongly recommend going with that name.) So, here's the question - a clarification of what I asked vaguely up above. Suppose you have a bunch of these extension methods, and a large project. How are you going to register the right extension methods in the right modules within your project? You're binding the functionality to the module in which the code was compiled, which will make exec/eval basically unable to use them, and that means you'll need some way to set them in each module, or to import the setting from somewhere else. How do you propose doing this? ChrisA