Dot equals operator (.=)

For sets you could use | operator, i.e.

some_set |= some_other_set

1 Like

Nice, very elegant

It could also be used in constructors (actually not):

def __init__(self, first_argument, second_argument, third_argument):
    self .= first_argument
    self .= second_argument
    self .= third_argument
    # or even
    self .= first_argument, second_argument, third_argument

That’s another proposal, this would be an attribute error:

self = self.first_argument # has no attribute first_argument

What you want is more like PEP 736: Keyword Argument Shorthand: Final Draft, in which case it might be written like this:

self.first_argument=

Right, this is the opposite :slight_smile:

I like the idea. But I’m also more keen on the a = .method() form, mainly because if hopefully PEP-736 gets approved the mind process to visualize both of them would be the same, I mean:
fn(a=) is equivalent to fn(a=a)
ob = .method() is equivalent to ob = ob.method()

I think it’s useful, but I don’t like the syntax. The reason is really simple: take for example

x += 1

Here, both the right hand and the left hand are valid expressions, that can be evaled even if there’s no += operator. In your example on the contrary, method(x, y, z) alone will throw a NameError. It will have a meaning only because of the .= operator. I feel it too magical.

2 Likes

Any new syntax might appear magical when first introduced. I don’t feel this suggestion fits into this category. It’s very similar to other augmented assignment operators.

I don’t mentally decompose lines of code and expect their individual fragments to be valid syntax. Perhaps for Python I should?

That said, would you feel more comfortable with a placeholder syntax?

foo = ~.method(x, y, z)

This would reduce typing and ensure one doesn’t make typos like fu1 = ful.method(). However, the RHS would still raise an error if isolated on it’s own,

Similar, but still different. Consider:

a = 5
a -= 1 + 2
# This is NOT the same as "a = a - 1 + 2". The RHS is evaluated fully first.

a = Spam()
a .= level # a = a.level, this is fine
a .= level() # this should also be acceptable right?
a .= level(a) # probably okay??
a .= level + 1 # what would this mean though?
a .= level() * 2 # or this?
a .= 1 # SyntaxError I think?

All of the augmented assignments are defined the same way: there is a LHS and a RHS, and you call the object’s __iXXX__ and assign back to the LHS. This one will be different. Instead of an RHS expression, it will need to be magic syntax that supports precisely as much as you choose to define it as supporting, no more and no less.

That’s not to say that this feature can’t ever happen, but it IS going to be a bit more complicated to explain.

2 Likes

Instead of an RHS expression, it will need to be magic syntax that supports precisely as much as you choose to define it as supporting, no more and no less.

I completely agree.

As for some of your examples. I feel the first 3 should be pretty obvious. This is how I’d reason with the others.

a .= level + 1 # what would this mean though?
a .= level() * 2 # or this?
a .= 1 # SyntaxError I think?

These would be roughly equivalent to:

a = a.{level + 1} # syntax error
a = a.{level() * 2} # syntax error
a = a.1 # syntax error

All I’ve done here is explicitly write down a copy / paste of the transformation \1 .= \2 to \1 = \1.\2 with curly braces for additional clarity (hopefully it’s clear that the additional braces themselves aren’t valid python syntax and there to show where \2 is pasted).

But since they aren’t valid syntax, what does it mean? You can talk about a parenthesized expression as a stand-in for “evaluate this first and use that value”, but that simply doesn’t work here. If it’s strictly JUST syntactic sugar for “a = a.” and whatever’s on the RHS, this isn’t very useful and is very confusing; but if, as you say, it isn’t… then… what is it? What CAN be done here and what can’t? Clearly you want method calls to be valid, but what about a .= level[1] ?

You will need to design this carefully and answer all of these questions before it can be a viable proposal.

1 Like

Of course, I wouldn’t dispute a thorough analysis and several choices would need to be made. That’s what PEPs are for.

That all said, from previous threads and this one, I can see the suggestion isn’t popular with the folk here and that’s why I’ve not pursued it.

However, I will challenge suggestions that it comes across as magical, would hardly be used, isn’t useful or that variable rebindings are rarely used etc.

As for your last example, I would expect it to be the same as calling the underlying dunder, i.e.

a .= level[1]
a .= level.__getitem__(1)
a = a.level.__getitem__(1)
a = a.level[1]

The dunders are actually irrelevant here, since a.level can be fully evaluated, and then you just evaluate the rest as normal. But then you have to ask: Why is subscripting valid but addition not? You’re allowing getitem but not add? You’ve basically gotten right back to it being nothing more than syntactic sugar.

If your specification does not exist and you answer all questions with whatever “seems obvious” to you at that exact moment, you will end up with a complete mess of incompatible ideas. Start by laying out a plan. Figure out what you are actually suggesting, so that questions can be answered from that.

1 Like

@Rosuav, all I can say is I clearly disagree with you. i.e your point about the dunders being irrelevant, also why subscripting is different to addition, etc. I never said this was more than syntactic sugar. I also feel I made my suggestion clear from my original post even with examples in the cpython code base where this could be used. As I said earlier I’ve already given up pursuing this suggestion.

I would say, because it’s ambiguous:

a .= foo + bar # what does this mean?
a = foo + a.bar # no
a = a.foo + bar # no
a = a.foo + a.bar # maybe? but is this obvious?
1 Like