An extension of variable += value

Hi everyone!

I am a complete noob at programming and Python in particular, and am JUST HAVING FUN. I’m sure there are a million things wrong with this (as I have been aggressively told by Reddit) but, just for shits and giggles, I want to make a suggestion. I hope you don’t mind.

Right now, we have variable += value which, of course, is the same as variable = variable + value

Changing the notation to =variable + value doesn’t change any of the characters and so, it probably doesn’t really impair readability in any way once you get used to it. So why not use this second notation to EXTEND this functionality?

This would make the following possible, for example:

= (variable + 30) * 5/100

EDIT: and the result always gets evaluated and assigned to the only variable that can be included in the expression, even if it is repeated multiple times. This would allow for more complex operations while having the same exact benefit of not having to type the same variable once.

In fact, outside of production (I am aware it’s bad practice) it could even be used to do something like

moderately_long_variable_name = re.search('pattern', source_text)

if moderately_long_variable_name:
     = moderately_long_variable_name.group(1)

As I said, I am not a professional programmer but do use Python a lot at work and use a hell of a LOT of regex.

I know it’s bad practice to reuse variable names in this manner but I am frequently looking for 30 or more different things using regex so I always reuse my variables in this scenario so as not to waste 30 variables or more just to check if they are None. (DISCLAIMER: I work alone and am self-employed so nobody else is affected. All of my code is ultrasimple and is 80% throwaway).

If I could use this “self-assignment” operator my code would be considerably shorter. Plus, if we have +=, *=, etc. why not have them all together at the simple cost of shifting the equals sign?

You haven’t described the semantics of your proposal.

What would:

do?

What about
=(a if b else c)
?

Thanks a lot for replying!

Please excuse me, I guess I got a bit overexcited and did not fully describe it.

My proposal is you can only include one variable but can include it as many times as you wish. The result is evaluated and assigned to that variable.

= (variable + 30)/(variable * 150) + variable**1.25

would be equivalent to

variable = (variable + 30)/(variable * 150) + variable**1.25

Essentially having the same exact benefits as variable += value, variable *= value, etc. all combined into one.

There could, of course, be more complex use cases but I honestly feel like don’t know enough to suggest them without leading to ambiguous scenarios, etc. The use case above, however, does seem to be simple enough to incorporated without causing any problems.

So, for example, one could model much more complex functions inside for loops such as (of course this could be simplified into one line but I am just overemphasizing all that this syntax would allow to happen that can’t be done now):

variable = 10
for count in range(10):
    numerator = variable + 30
    denominator = variable * 150
    addend = variable ** 1.25
    partial_result = (numerator/denominator) + addend
    variable = partial_result
    
print(variable)
>> 2087768043.3477845

would be equivalent to:

variable = 10
for count in range(10):
    = (variable + 30)/(variable * 150) + variable**1.25`
    
print(variable)
>> 2087768043.3477845

Of course, it doesn’t need to get this complicated and the more times the variable is repeated the less benefit there is. However, it’s still the exact same economy of characters as the operators that already exist while combining them all and all that would need to be done is simply shift the equals sign to the left. The function could just as well be linear or what have you and in that scenario it would be super useful, particularly for crazies like me who like their variables long :grin:

Can you see any major problems with this? I am not a professional programmer even though 50% of what I do at work is program so I am unable to foresee deep complications.

Also, thanks for kindly replying and taking the time to simply consider this idea at all, I really appreciate it!

Thanks for your proposal and being understanding toward feedback. Unfortunately, there are many practical complexities, and it isn’t all that useful in most general real-world cases as you might imagine.

Sure it can. The second block in your syntax is (unless I’m misunderstanding what you’re proposing) is equivalent to simply adding variable to its LHS, while being less readible, and not exactly equivalent to the verbose (but clearer) block above, since that binds values to numerator, denominator, added and partial_result as well as variable. I.e. it is just

variable = 10
for __ in range(10):
    variable = (variable + 30)/(variable * 150) + variable**1.25`
    
print(variable)
>> 2087768043.3477845

If you import this, you’ll find the Zen of Python, among which guidelines include “explicit is better than implicit”. Unlike in a simple addition, subtraction, etc. operation, which already works with the current syntax, eliding the LHS variable name in a complex expression doesn’t typically save all that many characters, while making the meaning much less clear, and being inconsistent with the rest of Python’s syntax (and that of most other programming languages).

In practice, given this introduces new syntax, would require significant parsing changes, and partially duplicates current functionality, means that highly compelling reasons need to exist for this new syntax beyond mere convenience in specific situations. In fact, I’m not an expert in expression grammars like some on here, but I don’t believe what you propose would even be possible in a LL(1) parser, or perhaps even a PEG parser, due to the need to forward-search an arbitrary number of tokens to find the variable name to assign to.

Beyond that, there’s one particularly glaring problem: what should

x = 1
y = 42
= (x + 10) * (y + 10)

do? Raise a SyntaxError?

While this new syntax may be marginally more convenient for complex assignment statements containing only one variable name that cannot be expressed by , such cases are not that common in real code, and special-casing that one case doesn’t really fit with the general patterns and programming conventions one sees in the wild, whereas it is likely more common to use one or more (other) variables in a typical assignment (both speaking from experience, and confirmed by a quick grep.app search).

There’s also another matter—the in place operators are overridable in custom classes; +=/__iadd__, -=/__isub__ and similar can potentially do something quite different entirely (that makes more sense for the given class) than their non-inplace equivalents. The above proposal doesn’t have anything like that; in reality, it isn’t really a replacement for the in place operators at all, which mean something semantically different, but are rather simply a syntactic shortcut for assignment in certain special cases, which isn’t quite so useful as you might imagine.

Perhaps you might consider posting a short example of some of the your code you find verbose and hard to read/write without this in the Users section, and we can provide suggestions for how to make it simpler and cleaner without it?

2 Likes

Thanks so much lot for replying!

Sure it can.

No, no, I meant with the variable (operation)(equals) value syntax, not the standard assignment variable (equals) value. My point being that the (operation)(equals) syntax exists to that you don’t have to type the variable name once, right? For example:

variable += 1
vs
variable = variable + 1

However, as you know, this syntax is limited to only one operation at a time. If we simply shift the equals sign to the left, then any number of operations can be performed. E.g.:
= (variable + 3)/2
vs
variable = (variable + 3)/2

It’s the same exact economy of characters (in this case 33%) as the syntax that already exists for all (operation)(equals), meaning the same exact benefits, except that more operations can be done while said benefits remain.

doesn’t typically save all that many characters

Not in the complex example I used, but for a linear equation like above it’s 33% and, if the variable were a bit larger, say, this_variable_name, it’s already 40% in that same linear example.

Raise a SyntaxError ?

Yes, my proposal is this “self-assignment” syntax would only work with one variable at a time and an error would be raised if people attempted to use more than one variable. Of course, it could be made to be more complex in a way that would allow more than one variable but even I agree right off the bat that’s unnecessary and too complicated.

In practice, given this introduces new syntax, would require significant parsing changes, and partially duplicates current functionality, means that highly compelling reasons need to exist for this new syntax beyond mere convenience in specific situations. In fact, I’m not an expert in expression grammars like some on here, but I don’t believe what you propose would even be possible in a LL(1) parser, or perhaps even a PEG parser, due to the need to forward-search an arbitrary number of tokens to find the variable name to assign to.

This is something that I quite literally know nothing about so I can’t really opine at all. Since all that would change would be the position of the equals sign, my uneducated train of thought was that maybe the changes wouldn’t be so significant as to be prohibitive.

There’s also another matter—the in place operators are overridable in custom classes; += / __iadd__ , -= / __isub__ and similar can potentially do something quite different entirely (that makes more sense for the given class) than their non-inplace equivalents. The above proposal doesn’t have anything like tha

I admit this is already above my full understanding but couldn’t, say, = (variable + 50)/3 simply be replaced by a succession of the in-place operators following the order of operations? So the user would simply override each of them separately.

Perhaps you might consider posting a short example of some of the your code you find verbose and hard to read/write without this in the Users section, and we can provide suggestions for how to make it simpler and cleaner without it?

To be honest I don’t have any specific examples. I just relatively often encountered situations in the past where I wanted to perform more than one operation using the (operation)(equals) syntax and wished it were possible. For a general example, when calculating fees and commissions that are composed of a fixed amount plus a percentage, which happens a lot in e-commerce. Plus, I personally like having fully descriptive variable names with few abbreviations that sometimes get a tad on the bigger side and am super lazy so I probably care a lot more about this than the average person.

To be clear, this suggestion is mostly for fun. I knew from the get go that it was going to have many implications that escape my understanding but just thought that, well, there’s nothing to lose, so I might as well just throw it out there. After all, and, again, this was my uneducated train of thought, if the (operation)(equals) syntax was deemed useful enough to be implemented, it followed that simply shifting the equals sign to the left could potentially be worthwhile in order to obtain the same exact benefits.

Thanks again for your time and feedback!

I would hazard a guess that some large percentage of the potential real-world uses for this type of construction would involve more than one variable, and so creating a feature that cannot be used in that way would not be well-received.

If you wanted to pursue this line of thinking, you might consider some sort of syntax that would allow you to refer to the variable-being-assigned in the expression being evaluated. For example, you could have something like this:

x = 1
x = (_ * 10) / (_ + 5)

where _ is the back-reference to the variable-being-assigned.

Thanks a lot for chiming in!

I really like your idea as well. When I first came up with the idea my initial thought was to treat it a little bit like f-strings but I thought that it would probably be just too much. Something like:

= ({main_variable} + other_variable)/yet_another_variable

but the color coding would have to be excellent and I thought it might be a bit too much even without considering any of the deeper implications

Hi Python Millionaire,

You say:

"It’s the same exact economy of characters (in this case 33%) as

the syntax that already exists for all (operation)(equals), meaning

the same exact benefits, except that more operations can be done while

said benefits remain."

But that is not true, you have missed the benefits of augmented

assignment, and in some cases, eliminated them.

Augmented assignment is familiar to people who know other languages,

such as C. This proposal will be unique to Python, eliminating the

benefit of familiarity.

Augmented assignment puts the most important information, namely the

variable being operated on, right at the front where it is the most

obvious:

x += abs(J(y, 4) - I(z, 3)**2 + sin(3*y**n - 7*y + 1)**(4*x-z**y))

is instantly and obviously incrementing x, the complexity of the

expression on the right can be ignored until such time as you need to

dive into it. Whereas your proposal potentially hides that vital

information to somewhere buried deeply in a complex expression:

= (2.345**4.5 - 829.93*(273.945*x - 38.94))/x + 394.0124

You have to read halfway across the line before you have any clue what

variable is being operated on.

Augmented assignment is intentionally limited to a single operation at a

time, giving a simple interpretation:

n += 1

x *= 2

increments the value of n by 1 and doubles the value of x. By analogy,

we can extend that to other operations and types, and complex

expressions on the right hand side, but fundamentally it remains

conceptually a single, simple operation on the variable on the left.

In contrast, while your proposal can also be used for such simple

operations:

= n + 1  # increment n by 1

= x*2  # double x

(but why would we want to?), the reason for its existence is to be used

in more complex expressions:

= (3*x - 14)**5 - x**4/2 + 8*(x+2)**3/17 - 3*x**2/2 + 2*x + 31

which are not conceptually simple operations. As such, they don’t really

deserve the mental space of special syntax.

The typing benefits are likewise much reduced. In the n += 1 case we

save 33% (including spaces); your proposal saves 22% (2/9) whereas in

the above example only 3% (2/64).

2 Likes

A further problem with your proposal is this:

“My proposal is you can only include one variable

Taken at face value, that eliminates the possibility of using any named
functions, including builtin functions, since named functions are
themselves “variables” in Python. Calling a function:

func()

is an operation on a variable, namely calling the variable “func”'s
special method __call__.

So if your proposal is taken literally, you can’t call any functions,
not even builtins, on the right-hand side.

A more practical rule would have to be much more complex, to allow
variables on the right only if they are being subscripted or called:

= mylist[x]  # x = mylist[x]
= func(x)  # x = func(x)

I expect that would be almost impossible to enforce in the parser, you
would need an extra step in the interpreter just to check these lines.

But putting aside the difficulty of implementation, we are still left
with a major restriction. With augmented assignment, the right hand
expression can include anything. With your proposal, we can’t use any
other named constants or variables.

Let’s keep it simple: your proposal supports doing a basic increment of
a constant:

n += 1
= n + 1

so that’s fine. But how would you do this?

n += step

I don’t think you can, not with your rule of only allowing a single
variable.

Rather than generalising augmented assignments and being more useful,
it is actually restricting augmented assignment and being less
useful.

2 Likes

Alas! It seems I have reached the limits of my ability to play devil’s advocate. Unfortunately I don’t know anywhere near enough to try and think of a way around this. I guess either someone else steps in or this is where the suggestion dies.

Thanks everyone for considering it!

1 Like

First of all,
variable += other
is not the same as
variable = variable + other
in the general case where variable and other are two arbitrary objects.

The first statement performs an add in place operation on variable. The second performs an add operation and assigns the result to variable.

For simple types, such as int, float, etc., and the types are identical, sometimes the results of either statement are identical. But more often the results look like they are the same but are not identical. Sameness means str(x) == str(y). Identity means id(x) == id(y).

When the types are not identical, implicit or explicit type conversions, or special methods of the types need to be considered.

The principle of least surprise suggests that we should not do something special in the rare cases when the two statements have identical results.