new feature in Python.

Chris Angelico rosuav at gmail.com
Wed Sep 30 12:35:32 EDT 2020


On Thu, Oct 1, 2020 at 2:14 AM Jason C. McDonald
<codemouse92 at outlook.com> wrote:
>
>
> > I have a great idea, there are __iX__` methods, such as `__ior__`,
> > `__iadd__`, `__iand__` etc.., which implements the |=, +=, &=
> > behavior,
> > it would be nice if you could implement also `__igetattr__` or
> > something, which means:
> >
> > instead of
> > con = "some text here"
> > con  = con.replace("here", "there")
> >
> > we could do
> >
> > con = "some text here"
> > con  .= replace("here", "there")
>
> I have three concerns about this. First, there's a lot of wizardry
> under the covers with getattr() and dot access to begin with, so this
> would be significantly non-trivial. I suspect the behavior would wind
> up being "surprising" too often.
>
> Second, explicit is better than implicit. It's better to explicitly
> rebind the name (or mutate on the name) rather than have a fancy
> shorthand for trampling over an existing mutable value. In the case of
> the compound operators on numbers, you're dealing with immutable types
> anyway, so you're really just rebinding the name. The same is true of
> your string there. But what about a list?
>
> spam = [1, 2, 3]
> eggs = spam
> eggs .= append(4)  # what is happening????
> eggs .= sort()  # how about now?
> eggs .= sorted(eggs) # and now?
>
> You see? It's going to be a lot of surprises, because you're stripping
> the usual visual cues of explicit assignment:
>
> spam = [1, 2, 3]
> eggs = spam
> eggs.append(4)  # mutating spam too
> eggs.sort()  # mutating spam too
> eggs = eggs.sorted() # rebinding eggs to a new value, spam is safe
>

These examples reveal a few other issues, though, which can best be
highlighted by this:

x = 5
x *= 2 + 3
print(x)

x = 5
x = x * 2 + 3
print(x)

Augmented assignment works with a single other operand. It's not
textually equivalent to "x = x <op> other"; it's closer to "x = x <op>
(other)", putting the right hand side in parentheses. That doesn't
work with a hypothetical igetattr, because you're invariably going to
want to do more than just get an attribute.

It's also notable that the in-place *methods* are actually used
something like this (omitting detaily bits about slots):

x += y
# is roughly equivalent to
x = x.__iadd__(y)

So there's assignment *as well as* the in-place method call. The only
value of the __iadd__ family of methods is with types that can
implement them directly; for instance, a list can append to itself,
rather than copying itself and then reassigning (which is semantically
different, as well as being far less efficient). The ".=" operator
wouldn't be able to take advantage of that.

If you find yourself frequently writing long chains of statements that
all do "thing = thing.method()", it may be better to consider writing
them as a single statement instead:

name = (name
    .capitalize()
    .expandtabs()
    .lstrip(" ")
    .replace(", ", ",")
)

It'd be as efficient and readable as the augmented assignment form would be.

ChrisA


More information about the Python-list mailing list