0

I stumbled upon a low-level Python problem that I cannot understand. I want to do something to a string inside a function and keep those alterations.

name = 'name'

def get_new_name(name):
    name = 'new_name'

get_new_name(name)

print(name)  # expected 'new_name', got 'name'

I would expect that I get new_name printed, however, the result is name.

I know I could get what I want by using return in the function, but can I somehow use a void-like function as described here to get what i want?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
G.Brown
  • 214
  • 2
  • 12
  • Are you forced to use a void function? If you can modify the function, why can't you just return the new value? And no, you can't modify immutable objects. – cs95 Nov 05 '17 at 11:28
  • I am absolutely not forced. This is just something that surprised me a lot and I would like to understand it. The only reason is the immutability? When I debug, name DOES have the value 'new_name' inside the function. – G.Brown Nov 05 '17 at 11:30
  • 2
    `name` inside the function is local, it's the parameter. It's **not** the global `name`. I'd advise reading https://nedbatchelder.com/text/names.html to get a better idea of how scopes and identifiers work. – jonrsharpe Nov 05 '17 at 11:31
  • It's like declaring variables inside of a scope. They don't affect the outside. You can use the "global"-keyword though. Just try: global name = 'new_name' – Basti Nov 05 '17 at 11:33
  • @jonrsharpe Thanks, I will. – G.Brown Nov 05 '17 at 11:33

4 Answers4

4

You cannot modify immutable objects in python, no. Any reassignment does not modify the original object, but simply changes the reference that the variable points to.

With mutable objects, you can modify it contents, and the changes will be seen when accessing the object via any variables/references that point to it.

Understanding the difference between objects and references is the key to understanding this.


Since you're curious to know if this is possible... it is! But only if you wrap your string inside something else, say, a dict.

def get_new_name(d):
     d['name'] = 'new_name'

name = 'name'
d = {'name' : name}

get_new_name(d)

name = d['name']

print(name)
'new_name'

You'd also need to decide on some protocol that you and the function agree upon for smooth communication between each other.

Sure, you could also use a global variable, but your question wasn't really about that... and I wouldn't recommend doing it either - it's bad practice to create impure functions.

cs95
  • 379,657
  • 97
  • 704
  • 746
2

Don't pass name to the function, and change the value of the global one. But it's not recommended...

def get_new_name():
  global name  
  name = 'new_name'
ValLeNain
  • 2,232
  • 1
  • 18
  • 37
  • This would especially not help in my specific case, as to other reasons I really want to pass the name as an argument. And then I get problems having name as parameter and trying to access the global name. – G.Brown Nov 05 '17 at 11:42
  • you want to pass the name to not use it ? You cannot just call the parameter another name (like `def get_new_name(_):` ? – ValLeNain Nov 05 '17 at 11:47
2

your name variable in your void function is only local and does not share the same scope as your global variable name. Once your function finishes running, it discards the local variable with 'new_name' in it. Unless you include the print statement inside the function, which is pretty redundant.

Nicholas
  • 21
  • 3
1

If you want to simply access a global variable you just use its name. However to change its value you need to use the global keyword.

From https://stackoverflow.com/a/10588342/6225257

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Basti
  • 517
  • 4
  • 19
  • I understand this solution, but it gets me in trouble, as I want to use name as parameter. Using this AND accessing some global name in the same time is not possible. – G.Brown Nov 05 '17 at 11:43
  • I don't see a problem there. Do you have an example where that doesn't work? When you are receiving the parameter you don't have to include the global-keyword, just make sure it's the global variable you are sending when calling the function. If you are calling from another function just write: global name and then myFunction(name) – Basti Nov 05 '17 at 11:50