[Python-ideas] Augmented assignment syntax for objects.

Jerry Hill malaclypse2 at gmail.com
Mon May 1 14:50:48 EDT 2017

On Thu, Apr 27, 2017 at 7:21 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Wed, Apr 26, 2017 at 03:54:22PM -0400, Jerry Hill wrote:
>> On Tue, Apr 25, 2017 at 8:05 PM, Ryan Gonzalez <rymg19 at gmail.com> wrote:
>> > def ___init__(self, self.attr):
>> I'm not a python developer, I'm just a developer that uses python.
>> That said, I really like this form.  It eliminates most of the
>> redundancy, while still being explicit.  It's true that you have to
>> repeat the 'self' name, but it feels like the right balance in my
>> mind.  It seems like anyone who's familiar with python function
>> definitions would immediately grasp what's going on.
> I don't like it, not even a bit. It's not general, "self" is effectively
> a special case. Consider:

I wasn't thinking that 'self' should be a special case at all.

> What happens if you use this syntax in a top-level function rather
> than a method? (Or a static method?)
> def function(x, y, x.attr):
>     ...
> (And don't forget that behind the scenes, methods *are* functions.) What
> would this syntax even mean?

It would mean the same thing as "def function(x, y, z):", which is:
take the first three positional arguments, and assign them to the
local names listed in the function definition.  The same as

def function(foo, bar, baz):
    x = foo
    y = bar
    x.attr = baz

> Or if you use some other name other than the first parameter?
> def method(self, spam, foo.eggs):
>     ...

What's the problem?  How is this any different from
def method(self, bar, baz):
    spam = bar
    foo.eggs = baz

I mean, it does imply that 'foo' is some globally writable bit of
data, being modified via side effect of calling a method, which is
certainly a code smell.  Still, we're all consenting adults here, and
it doesn't seem any worse than the already-legal variant I mention

> Conceptually, it is mixing up two distinct tasks:
> - declaring the parameter list of the function/method;
> - running part of the body of the method.

Is assigning your parameters to their local names really part of
'running the body of the method'?  I mean, I almost never write my
functions like this:

def fun(*args):
   foo = args[0]
   bar = args[1]
   baz = args[2]

Do you?  If not, aren't you using the function definition to assign
parameters to local names?  Also, if you do write functions that way,
aren't you *also* losing the semantic hints about what parameters are
acceptable and what they are used for?

> The parameter list of the method is the *interface* to the method: it
> tells you the public names and default values (and possibly types, if
> you use type annotations) of the method parameters. But this syntax
> overloads the parameter list to show part of the *implementation* of the
> method (namely, that some parameters are assigned directly to attributes
> of self). Every time the implementation changes, the parameter list will
> change too.

I guess I don't agree that the function definition only tells you the
'public names' of the parameters being passed.  Instead, I think the
function definition tells you the names those parameters are going to
go by inside the function.  That is, their local names. And if you're
taking the parameters and assigning them to attributes of self anyway,
then you have the exact same issue with your parameter list changing
every time the implementation changes anyway, don't you?

> it doesn't look so good in larger, more realistic cases, especially with
> other syntax. Here's a parameter list taken from some real code of mine,
> with the "self." syntax added:

I won't argue with that, I suppose.  I'm not convinced it's worse than
the status quo, but yes, if you pack all the possible options into
your parameters, you can end up with a messy function signature.  I
guess my python experience is atypical if most of your methods take 6+
parameters, including some that are keyword-only, most of which have
default values, and are annotated with type hints.

> class BinnedData(object):
>     def __init__(self, self.number:int,
>                        self.start:float=None,
>                        self.end:float=None,
>                        self.width:float=None,
>                        *,
>                        self.policy=None,
>                        self.mark=False
>                        ):
> The repetition of "self" is not only tedious and verbose, it adds
> noise to the parameter list and pushes the reader's attention away from
> the important part (the name of the parameter, e.g. "width") and to
> something irrelevant to the interface ("self").
> And I am not looking forward to having to explain to beginners to Python
> why this doesn't work:
> data = BinnedData(self.number = 8, self.start = 0, self.end = 20)

For what it's worth, if that construct wouldn't work, then I'm
convinced that the idea is a bad one. :)  I'm not sure I see why that
would have to be forbidden, though.


More information about the Python-ideas mailing list