[Python-ideas] Pseudo methods

Nick Coghlan ncoghlan at gmail.com
Wed Aug 9 00:18:58 EDT 2017


On 7 August 2017 at 18:48, Victor Stinner <victor.stinner at gmail.com> wrote:
> Ruby provides this feature. A friend who is a long term user of Rails
> complained that Rails abuses this and it's a mess in practice. So I
> dislike this idea.

Right, Python's opinionated design guidance is to clearly distinguish
between "data first" designs using methods on objects and "algorithm
first" designs using functools.singledispatch (or similar mechanisms),
since they place different constraints on how new implementations are
added, and where you should look for more information about how an
algorithm works.

Part of the intent behind this guidance is to better enable local
reasoning about a piece of code:

    from my_string_utils import has_vowels

    if has_vowels(input("Enter a word: ")):
        print("Contains vowels!")
    else:
        print("Does not contain vowels!")

Here, it is clear that if we want to know more about what "has_vowels"
does, or if we want to request changes to how it works, then
"my_string_utils" is where we need to go next.

By contrast, that's significantly less clear if our string utils
module were to implicitly modify the behaviour of input() or builtin
strings:

    import my_string_utils

    if input("Enter a word: ").has_vowels():
        print("Contains vowels!")
    else:
        print("Does not contain vowels!")

To analyse and investigate this code, we need to "just know" that:

- the result of "input()" doesn't normally have a "has_vowels()" method
- therefore, importing "my_string_utils" must have either replaced the
input builtin or mutated the str type
- therefore, "my_string_utils" is probably the place to go for more
information on "has_vowels"

If our import line had instead looked like "import my_string_utils,
my_other_utils", we'd have to go look at both of them to figure out
where the "has_vowels()" method might be coming from (and hope it
wasn't happening further down as a side effect of one of the modules
*they* imported).

Injecting methods rather than writing functions that dispatch on the
type of their first argument also creates new opportunities for naming
conflicts: while "my_string_utils.has_vowels" and
"your_string_utils.has_vowels" can happily coexist in the same program
without conflicts, there's only one "input" builtin, and only one
"str" builtin.

Can this level of explicitness be an obstacle at times? Yes, it can,
especially for testing and interactive use, which is why Python offers
features like wildcard imports, runtime support for monkeypatching of
user-defined types, and runtime support for dynamically replacing
builtins and module globals. However, the concerns around the
difficulties of complexity management in the face of implicit action
at a distance remain valid, so those features all fall into the
category of "supported, but not encouraged, except in specific
circumstances".

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list