-1

Let us have two functions:

def f1(x):
    x = do_stuff(x) # an instance of the same class as x
def f2(x):
    x.copy(do_stuff(x)) # ensures that x changes in-place to be identical to the argument of the method

The first one does not change the value of the global variable passed to it, since it just assigns the local name x to a new value. The second one does change it. Imagine a scenario, where the object passed to the function does not have a setter method. Is there a way to still change its global value?

P.S.: You can come up with workarounds like:

def f3(x):
    return do_stuff(x)
y = f3(y)

but what I am looking for is something like:

def f4(x):
    x inplace= do_stuff(x)
f1(y)

Each object has an ID that can be found using the id() function. Perhaps one could place a new value under that id? It looks like something that should be forbidden for immutable types, but is it possible for mutable types?


Clarifications

  • I am not looking for a way to change a specific global variable, but any global variable that happens to be passed to the function. This is why Python's global does not solve the problem.
  • Answers to this this question do not solve my problem. I know how variables are passed and I am not looking for an explanation. The answer closest to what I am asking was the one that suggests creating a wrapper that has a setter method. (Even a single membered list would do, since my_list[0] = new_value modifies the same list) Is there a solution without a wrapper? e.g. if you have an instance of a user-defined class, it is mutable. Maybe inside the function, you create another member of the class with different contents that you want to assign to the passed variable. Either your class has to have a "copy" method that takes another object of the same class and copies all the data. Or you have to go over the variables inside the function and copy them yourself. Is there a simpler or more general way of doing this?

Solution:

From the comments and answers below, it seems that the answer is no. In Python there is no general way that allows mutating any mutable object. The only way to mutate an object is via its methods or by directly accessing its variables. The solutions to this are either returning a new object that gets assigned to the global variable outside of the function, or creating a wrapper object.

Thanks to everyone helping me to figure this out and I hope this will help others, since I have not found this explicitly explained elsewhere.

AdamP
  • 3
  • 2
  • Does this answer your question? [Why can a function modify some arguments as perceived by the caller, but not others?](https://stackoverflow.com/questions/575196/why-can-a-function-modify-some-arguments-as-perceived-by-the-caller-but-not-oth) – mkrieger1 Jul 29 '20 at 16:06
  • 2
    What are you trying to achieve? Why can you not use one of the suggested workarounds shown in the other question you have linked (like, returning a value, which would be *the* simple and general way of doing this)? – mkrieger1 Jul 29 '20 at 16:08
  • This link does not answer my question. I understand that python basically passes the object identifier to the function, which means that the function can do something with the object, but not with the global name (like reassigning it to a new value, trying to do that would result in a new local name). However, for mutable objects, you can change the content of an object. The question is, can you do it as simply as when you define a new object without a specialised object method? (such that it resembles assignment) – AdamP Jul 29 '20 at 18:09
  • 2
    The answer is no. – mkrieger1 Jul 29 '20 at 19:27
  • Python would be a much more hazardous language if any function you called might go hunting around for other references to objects so it can reassign them. You wouldn't be able to keep control of your own variables. – khelwood Jul 29 '20 at 19:33
  • You say the object is mutable, but "the object passed to the function does not have a setter method". Objects are only mutable to the degree that they provide ways to mutate them. If an object does not provide a way to set its value, then it just doesn't have the functionality you're looking for. – user2357112 Jul 30 '20 at 00:50
  • Mutability isn't like, say, iterability. There's an iterator protocol, but there's no "mutator protocol". It's not like C++, where copy assignment is deeply embedded in the language. There is no uniform interface for mutating mutable objects. – user2357112 Jul 30 '20 at 00:53
  • Thank you for all your help. It is good to know that the answer is no, and not just something that I was missing. Also thank you for the additional explanation of the non-existence of a "mutator protocol" and comparison to C++. That helped, since I am familiar with C++. – AdamP Jul 30 '20 at 09:35

1 Answers1

0

Since variables in Python are not passed by reference. You're unable to do this for the general case.

If you're inside a closure, i.e. function inside another function, you may use the nonlocal keyword.

If you're changing a global, you may use the global keyword.

If non of these conditions are met, you cannot reassign to the passed function without using real trickery such as ast (abstract syntax tree) or frame modifications using sys._getframe(). I don't suggest using any of these options as it leads to complicated code for no benefit whatsoever.

Creating a new class which holds a single value might come handy:

class Value:
    __slots__ = ("value",)
    def __init__(self, value):
        self.value = value

x = Value(123)

def test(x):
    x.value = 456
Bharel
  • 23,672
  • 5
  • 40
  • 80
  • 2
    Your first sentence would be more accurate to say "Since variables are *not* passed by reference" – khelwood Jul 29 '20 at 16:19
  • You're right, but at the same time the value is a pointer, so while you pass by value, you pass a reference. How would you phrase that notion? – Bharel Jul 30 '20 at 00:46
  • It is true that you can pass a reference to an object, but not that variables are passed by reference. Variables and objects are different things. You can say that references are passed by value if you like, but it's not a very clear explanation for anyone that doesn't already understand the system. – khelwood Jul 30 '20 at 07:33