[Python-ideas] Define a method or function attribute outside of a class with the dot operator

Steven D'Aprano steve at pearwood.info
Mon Feb 13 20:48:15 EST 2017


On Fri, Feb 10, 2017 at 09:05:49PM -0500, Terry Reedy wrote:

> >    def foo(self):
> >        pass
> >    Foo.foo = foo
> >
> >Becomes:
> >
> >    def Foo.foo(self):
> >        pass
> 
> Saving about 10 keystrokes is close to trivial.

The same argument can be made for @decorator syntax.

And, if I understand correctly, the same argument *was* made against 
decorator syntax: that it was trivial, unnecessary and confusing.

In a realistic example, the function definition line:

    def method(self, arg):

and the line which actually injects it into the class:

    MyClass.method = method

may be separated by *many lines of code*. Yes, short methods are better 
than long methods, but even so, sometimes you have a long method. 
Arguably the most important part of the definition of this method (that 
it belongs to MyClass) may be lost way down the end, past the 
implementation.

Just as with decorators, the current idiom for method injecting repeats 
the method name too many times:

# the bad old way of using decorators
def function():
    ...
    ...
    ...
    ...
function = decorator(function)

# the nice clean way
@decorator
def function():
    ...
    ...
    ...
    ...


Likewise this proposal:

# the bad current way repeats the method name at least three times:
def method(self):
    ...
    ...
    ...
    ...
MyClass.method = method
del method

# and for injecting into an instance, the instance twice:
def method(self):
    ...
    ...
    ...
    ...
instance.method = types.MethodType(method, instance)
del method


# the clean proposed way:
def instance.method(self):  # or MyClass.method
    ...
    ...
    ...
    ...


We can reasonably argue that the benefit is not worth the cost; we can 
even reasonably argue that we don't wish to encourage the Interceptor 
design pattern, method swizzling, extension methods or method 
injection, whatever name you want to call it. Even monkey-patching.

But I don't think that we can reasonably argue that the suggested syntax 
isn't a clear, non-trivial win over the status quo, not unless we're 
also going to argue that introducing decorator syntax was a waste of 
time.


> I am not enthusiastic about enablin the following style of 
> class definition.
> 
> class Foo: "Object that implement the Foo protocol.
> 
> def Foo.__init__(self, x):
>     self.x = s
> 
> def Foo.__getitem__(self, key):
>     return vars(Foo)[key]

Neither am I, but why would anyone write classes that way? Do you have 
evidence that people in the C#, VB, Objective-C, Swift or Lua 
communities routinely do that?


> The problem with two-phase initialization is that one temporarily has a 
> partially initialized and likely useless object.  I am not enthusiastic 
> about encouraging this.

Indeed. But in practice, I don't believe that two-phase initialization 
is the usual reason for using method injection. It seems to be more 
commonly used for "introspection, overriding default behavior, or maybe 
even dynamic method loading".

https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/



-- 
Steve


More information about the Python-ideas mailing list