Python 2.7 - clean syntax for lvalue modification

2024/11/17 4:43:50

It is very common to have struct-like types that are not expected to be modified by distant copyholders.

A string is a basic example, but that's an easy case because it's excusably immutable -- Python is unusual in even allowing things like method calls on literal strings.

The problem is that (in most languages) we frequently have things like, say an (x,y) Point class. We occasionally want to change x and y independently. I.e., from a usage perspective, a Point LVALUE should be mutable (even though copies will not see the mutation).

But Python 2.7 doesn't seem to provide any options to enable automatic copy-on-assignment. So that means we actually MUST make our Point class IMMUTABLE because inadvertent references are going to get created all over the place (typically because somebody forgot to clone the object before passing it to somebody else).

And no, I'm not interested in the countless hacks that allow the object to be mutated only "while it's being created", as that is a weak concept that does not scale.

The logical conclusion of these circumstances is that we need our mutation methods to actually modify the LVALUE. For example %= supports that. The problem is that it would be much better to have a more reasonable syntax, like using __setattr__ and/or defining set_x and set_y methods, as shown below.

class Point(object):
# Python doesn't have copy-on-assignment, so we must use an immutable
# object to avoid unintended changes by distant copyholders.def __init__(self, x, y, others=None):object.__setattr__(self, 'x', x)object.__setattr__(self, 'y', y)def __setattr__(self, name, value):self %= (name, value)return self # SHOULD modify lvalue (didn't work)def __repr__(self):return "(%d %d)" % (self.x, self.y)def copy(self, x=None, y=None):if x == None: x = self.xif y == None: y = self.yreturn Point(x, y)def __eq__ (a,b): return a.x == b.x and a.y == b.ydef __ne__ (a,b): return a.x != b.x or  a.y != b.ydef __add__(a,b): return Point(a.x+b.x, a.y+b.y)def __sub__(a,b): return Point(a.x-b.x, a.y-b.y)def set_x(a,b): return a.copy(x=b) # SHOULD modify lvalue (didn't work)def set_y(a,b): return a.copy(y=b) # SHOULD modify lvalue (didn't work)# This works in Python 2.7. But the syntax is awful.def __imod__(a,b):if   b[0] == 'x': return a.copy(x=b[1])elif b[0] == 'y': return a.copy(y=b[1])else:             raise AttributeError,  \"Point has no member '%s'" % b[0]my_very_long_and_complicated_lvalue_expression = [Point(10,10)] * 4# modify element 0 via "+="   -- OK
my_very_long_and_complicated_lvalue_expression[0] += Point(1,-1)# modify element 1 via normal "__set_attr__"   -- NOT OK
my_very_long_and_complicated_lvalue_expression[1].x = 9999# modify element 2 via normal "set_x"  -- NOT OK
my_very_long_and_complicated_lvalue_expression[2].set_x(99)# modify element 3 via goofy "set_x"   -- OK
my_very_long_and_complicated_lvalue_expression[3]    %='x',   999print my_very_long_and_complicated_lvalue_expression

The result is:

[(11 9), (10 10), (10 10), (999 10)]

As you can see, += and %= work just fine, but just about anything else doesn't seem to work. Surely the language inventors have created a basic syntax for LVALUE modification that is not limited to goofy-looking operators. I just can't seem to find it. Please help.

Answer

In Python, the typical pattern is to copy before modification rather than copying on assignment. You could implement some kind of data store with the semantics you want, but it seems like a lot of work.

https://en.xdnf.cn/q/120245.html

Related Q&A

Python - Global name date is not defined [closed]

Closed. This question needs debugging details. It is not currently accepting answers.Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to repro…

Python update user input with tkinter button

Im just starting with python and im having a problem. Ive tried various solutions, but i cant update the field that says 19. When i click on plus, i want it to be 20, then 21,... and when i click - it …

Python Unique DF in loop [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.Want to improve this question? Update the question so it focuses on one problem only by editing this post.Closed 5…

TypeError: unsupported operand type(s) for +=: NoneType and str

I am new to Python and Im sure that Im doing something wrong - I would like to ask a user for three numbers and print their sum, heres my current code:for i in range(0, 3):total = Nonenum = input(Pleas…

multiply list of ndarrays by list

I want to multiply a list of numbers, by a ndarray, that is, each number in the list multiply by the first ndarray. This is the list: list1 = [840,845,897]This is the list of ndarray list = df[Example]…

Python skipping last element in while iterating a list using for loop [duplicate]

This question already has answers here:Strange result when removing item from a list while iterating over it in Python(12 answers)Closed 9 years ago.class Sample:def __init__(self):self.lst_report_foot…

can this code be shortened or improved? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.This question does not appear to be about programming within the scope defined in the help center.Cl…

Count Running and Stopped Ec2 Instances with AWS Lambda

How can I count number of running and stopped EC2 instances in a particular region using boto3 and an AWS Lambda function?

Python2.7: How to split a column into multiple column based on special strings like this?

Im a newbie for programming and python, so I would appreciate your advice!I have a dataframe like this.In info column, there are 7 different categories: activities, locations, groups, skills, sights, t…

python - return and print does not give same result

what Im trying to do is take the entered string separated by commas and change it to list then for each list as a key print the associated value.def main():myDict = {a:1, b:2, c:3, d:4, e:5....}u_input…