On Tue, Jun 22, 2021 at 10:40 AM Steven D'Aprano <st...@pearwood.info> wrote:
> > True, all true, but considering that this is *not* actually part of
> > the class, some of that doesn't really apply. For instance, is it
> > really encapsulation? What does that word even mean when you're
> > injecting methods in from the outside?
>
> Sure it's encapsulation. We can already do this with non-builtin
> classes:
>
>     class SpammySpam:
>         def spam(self, arg):
>             ...
>
>         from another_module import eggy_method
>
>     def aardvarks(self, foo, bar):
>         ...
>
>     SpammySpam.aardvarks = aardvarks
>
>
> The fact that two of those methods have source code that wasn't indented
> under the class statement is neither here nor there. Even the fact that
> eggy_method was defined in another module is irrelevant. What matters is
> that once I've put the class together, all three methods are fully
> encapsulated into the SpammySpam class, and other classes can define
> different methods with the same name.
>
> Encapsulation is less about where you write the source code, and more
> about the fact that I can have
>
>     SpammySpam().spam
>
> and
>
>     Advertising().spam
>
> without the two spam methods stomping on each other.

Hmm, that's not what I'd usually understand "encapsulation" to mean.
That's what would normally be called "namespacing".

"... encapsulation refers to the bundling of data with the methods
that operate on that data, or the restricting of direct access to some
of an object's components."
https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)

> Extension methods let us extend classes without the downsides of
> monkey-patching. Extension methods are completely opt-in while
> monkey-patching is mandatory for everyone. If we could only have one,
> extension methods would clearly be the safer choice.

I don't think it's safer necessarily. With this proposal, we have the
notion that obj.method() can mean two completely different things *at
the same time* and *on the same object* depending on how you refactor
the code.

# file1.py
from file2 import func
# and apply some extension methods
def spamify(obj):
    print(obj.method())
    print(func(obj))

# file2.py
def func(obj):
    return obj.method()

Is that really beneficial? All I'm seeing is myriad ways for things to
get confusing - just like in the very worst examples of
monkey-patching.

And yes, I have some experience of monkey-patching in Python,
including a situation where I couldn't just "import A; import B", I
had to first import a helper for A, then import B, and finally import
A, because there were conflicting monkey-patches. But here's the
thing: extension methods (by this pattern) would not have solved it,
because the entire *point* of the monkey-patch was to fix an
incompatibility. So it HAD to apply to a completely different module.

That's why, despite its problems, I still think that monkey-patching
is the cleaner option. It prevents objects from becoming
context-dependent.

> We don't make heavy use of monkey-patching, not because it isn't a
> useful technique, but because:
>
> - unlike Ruby, we can't extend builtins without subclassing;
>
> - we're very aware that monkey-patching is a massively powerful
>   technique with huge foot-gun potential;
>
> - and most of all, the Python community is a hell of a lot more
>   conservative than Ruby.

And the Ruby community is starting to see the risks of
monkey-patching. (There's a quiz floating around the internet - "Ruby
or Rails?" - that brings into sharp relief the incredibly far-reaching
effects of using Rails. It includes quite a few methods on builtin
objects.) So I am absolutely fine with being conservative.

We have import hooks and MacroPy. Does anyone use them in production?
I certainly don't - not because I can't, but because I won't without a
VERY good reason.

> Even basic techniques intentionally added to the language (like being
> able to attach attributes onto function objects) are often looked at as
> if they were the worst kind of obfuscated self-modifying code. Even when
> those same techniques are used in the stdlib people are still reluctant
> to use it. As a community, we're like cats: anything new and different
> scares us, even if its actually been used for 30 years.
>
> We're a risk-adverse community.
>

I'm not sure why attaching attributes to functions is frowned upon;
I'd personally make very good use of this for static variables, if
only I could dependably refer to "this_function". But risk-averse is
definitely preferable to the alternative. It means that Python is a
language that can be learned as a whole, rather than being fragmented
into "the NumPy flavour of Python" and "the Flask flavour of Python"
and so on, with their own changes to the fabric of the language.

So far, I'm not seeing anything in extension methods to make me want
to change that stance.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/BQJI5YYZW4BCTXUCO2QLXCWJIPO2LU7E/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to