I'm sorry Soni, I don't understand what you are arguing here. See below.
On Mon, Jun 21, 2021 at 10:09:17PM -0300, Soni L. wrote:
>
>
> On 2021-06-21 9:39 p.m., Steven D'Aprano wrote:
>
>
> >
> > Fourth step is that you go ahead and use lists as normal. Whether you
> > use getattr or dot syntax, any extension methods defined in spam.py will
> > show up, as if they were actual list methods.
> >
> > hasattr([], 'head') # returns True
> > list.tail # returns the spam.tail function object (unbound method)
> >
> > They're not monkey-patched: other modules don't see that.
> >
> >
>
> Python is a dynamic language. Maybe you're using hasattr/getattr to
> forward something from A to B. If "other modules don't see that" then
> this must work as if there were no extension methods in place.
What's "forward something from A to B" mean? What are A and B?
If "this" (method lookups) "must work as if there were no extension
methods in place" then extension methods are a no-op and are pointless.
You write an extension method, register it as applying to a type, the
caller opts-in to use it, and then... nothing happens, because it "must
work as if there were no extension methods in place".
Surely that isn't what you actually want to happen. But if not, I have
no idea what you mean.
The whole point of extension methods is that once the caller opts in to
use them, method look ups (and that includes hasattr and getattr) must
work as if the extension methods **are in place**.
The must be no semantic difference between:
obj.method(arg)
and
getattr(obj, 'method')(arg)
regardless of whether `method` is a regular method or an extension
method.
> So you
> actually wouldn't want the local load_attr override to apply to those.
> If you did... well, just call the override directly.
I have no idea what that means. What is "the local load_attr override"?
> If the override was
> called __opcode_load_attr_impl__ you'd just call
> __opcode_load_attr_impl__ directly instead of going through getattr.
As a general rule, you should not be calling dunders directly.
You seem to have missed the point that extension methods are intended as
a mechanism to **extend a type** by giving it new methods on an opt-in
basis. I want to call them "virtual methods" except that would add
confusion regarding virtual subclasses and ABCs etc.
Maybe you need to read the Kotlin docs:
https://kotlinlang.org/docs/extensions.html
and the C# docs:
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
Wikipedia also has a broad overview from a language-agnostic
perspective:
https://en.wikipedia.org/wiki/Extension_method
Here's an example in TypeScript and Javascript:
https://putridparrot.com/blog/extension-methods-in-typescript/
In particular note these comments:
# Kotlin
"Such functions are available for calling in the usual way as if they
were methods of the original class."
# C#
"Extension methods are only in scope when you explicitly import the
namespace into your source code with a using directive."
Both C# and Kotlin are statically typed languages, and Python is not,
but we ought to aim to minimise the differences in semantics. Aside from
extension methods being resolved at runtime instead of at compile time,
the behaviour ought to be as close as possible.
Just as single dispatch in Python is resolved dynamically, but aims to
behave as close as possible to single dispatch in statically typed
languages.
Another important quote:
"Because extension methods are called by using instance method syntax,
no special knowledge is required to use them from client code. To enable
extension methods for a particular type, just add a `using` directive
for the namespace in which the methods are defined."
"No special knowledge is required" implies that, aside from the opt-in
step itself, extension methods must behave precisely the same as regular
methods. That means they will be accessible as bound methods on the
instance:
obj.method
and unbound methods (functions) on the type:
type(obj).method
and using dynamic lookup:
getattr(obj, 'method')
and they will fully participate in inheritance heirarchies if you have
opted in to use them.
> There needs to be an escape hatch for this.
The escape hatch is to *not* opt-in to the extension method. If the
caller doesn't opt-in, they don't get the extension methods.
That is the critical difference between extension methods and monkey-
patching the type. Monkey-patching effects everyone. Extension methods
have to be opt-in.
> Or you *could* have getattr be special (called by load_attr) and
> overridable, and builtins.getattr be the escape hatch, but nobody would
> like that.
Huh? Unless you have shadowed getattr with a module-level function,
getattr *is* builtins.getattr.
--
Steve
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/IR6Q5ENBEXFYCIEHLCDR5XJB3FZ77CYO/
Code of Conduct: http://python.org/psf/codeofconduct/