When do python functions affect the caller's arguments?

What is passed in the argument of the python function? If you don't know it, you will destroy the original object. This time is an experiment to confirm it. The version of python is 3.4.3.

Copy the array

In python, changing the arguments passed in a function does not affect the original arguments.

mystr = "test"
myint = 100

def modify_str_and_int(mystr, myint):
    mystr = "after"
    myint = 200

modify_str_and_int(mystr, myint)
print("mystr = %s" % mystr)
print("myint = %s" % myint)

# =>
# mystr = test
# myint = 100

Taking an array as an argument also affects the calling array. Therefore, it is not necessary to return the processed array as a return value.

mylist = ["foo","bar",100]
def modify_list(mylist):
    mylist.append("new")

print(mylist)
modify_list(mylist)
print(mylist)

['foo', 'bar', 100]
['foo', 'bar', 100, 'new']

However, there are times when you do not want to change it. For example, when reusing the calling array. In this case, define a new variable in the function and move the value.

mylist = ["foo","bar",100]
def modify_list(mylist):
    new_list = mylist
    new_list.append("new")
    return new_list

print(mylist)
modify_list(mylist)
print(mylist)

# =>
# ['foo', 'bar', 100]
# ['foo', 'bar', 100, 'new']

The original value has been rewritten. This is because you are passing a reference to new_list, not a copy of the value. So the two variables new_list and mylist point to the same list object. This can be confirmed by id.

mylist = ["foo"]
new_list = mylist

print(id(mylist))
print(id(new_list))
print(id(mylist) == id(new_list))

# =>
# 4528474888
# 4528474888
# True

So let's create a new list object with the same value as mylist. The built-in function list is a function for converting a sequence type to list, but it is also possible to create a new list object from list.

mylist = ["foo"]
new_list = list(mylist)

print(id(mylist))
print(id(new_list))
print(id(mylist) == id(new_list))

# =>
# 4313320328
# 4313327816
# False

If used in a function in the same way, it will not affect the original array.

mylist = ["foo","bar",100]
def modify_list(mylist):
    new_list = list(mylist)
    new_list.append("new")
    return new_list

print(mylist)
new_list = modify_list(mylist)
print(mylist)
print(new_list)

# =>
# ['foo', 'bar', 100]
# ['foo', 'bar', 100]
# ['foo', 'bar', 100, 'new']

Int and str are also passed by reference

In the first sample I saw, changing ints and strs in a function didn't affect the original object. The reason the array was affected was because it was pointing to the same object. That is, the objects had the same id. Then, is the id different for int and str?

mystr = "test"
myint = 100

def modify_str_and_int(mystr, myint):
    print("mystr = %s" % id(mystr))
    print("myint = %s" % id(myint))

print("mystr = %s" % id(mystr))
print("myint = %s" % id(myint))
modify_str_and_int(mystr, myint)

# =>
# mystr = 4308535648
# myint = 4305807456
# mystr = 4308535648
# myint = 4305807456

that? Both are the same. This should also affect the original value. Let's try again.

mystr = "test"
myint = 100

def modify_str_and_int(mystr, myint):
    mystr = "after"
    print("mystr = %s" % id(mystr))
    print("myint = %s" % id(myint))

print("mystr = %s" % id(mystr))
print("myint = %s" % id(myint))
modify_str_and_int(mystr, myint)

# =>
# mystr = 4557928800
# myint = 4555208800
# mystr = 4557705768
# myint = 4555208800

that! ?? This time, only mystr has changed id. This is a scope issue. Since python is all objects, the id of the object is passed as it is in the argument. If you define the same variable in a new function, the behavior will be different for arrays and ints and strs. This time, the id of str has changed. This criterion is the difference between an object being mutable (variable) and immutable (immutable). If it is immutable, an object with the same value is created, so the id has changed.

You can see that the same id value is passed to the variable even if it is not in the function. One difference is that if you use the same argument name, you will point to yourself. Within the function, the first time it is treated as a new variable.

mystr = "test"
myint = 100
mylist = ['foo', 'bar']

new_str = mystr
new_int = myint
new_list = mylist

print(id(new_str) == id(mystr))
print(id(new_int) == id(myint))
print(id(new_list) == id(mylist))
# =>
# True
# True
# True

def display_outer():
    print("mystr = %s" % mystr)
    print("myint = %s" % myint)
    print("mylist = %s" % mylist)

display_outer()
# =>
# mystr = test
# myint = 100
# mylist = ['foo', 'bar']

Functions can refer to outer variables

It turns out that the id value is passed as it is as an argument. This means that it is possible to refer to the outer variable inside the function.

mystr = "test"
myint = 100
mylist = ['foo', 'bar']

def display_outer():
    print("mystr = %s" % mystr)
    print("myint = %s" % myint)
    print("mylist = %s" % mylist)

display_outer()
# =>
# mystr = test
# myint = 100
# mylist = ['foo', 'bar']

Recommended Posts

When do python functions affect the caller's arguments?
Keyword arguments for Python functions
Check the behavior when assigning Python
What to do when the value type is ambiguous in Python?
Python functions
How to pass arguments when invoking python script from blender on the command line
#Python basics (functions)
[Beginner] Python functions
Python Easy-to-use functions
Python basics: functions
When will the default arguments be bound in python? When variables are bound in closure lazy evaluation.
What I do when imitating embedded go in python
[Python for Hikari-] Chapter 06-04 Functions (arguments and return value 3)
Receive the form in Python and do various things
Initial settings when using the foursquare API in python
[Python] logging.logger Outputs the caller's log correctly from the wrapper
(◎◎) {Let's let Python do the boring things) ......... (Hey? Let's let Python do the homework} (゜) (゜)
Specifies the function to execute when the python program ends
What to do when "cannot import name xxx" [Python]
About the --enable-shared option when building Python on Linux
[Python for Hikari-] Chapter 06-03 Functions (arguments and return value 2)
To do the equivalent of Ruby's ObjectSpace._id2ref in Python
How much do you know the basics of Python?
I want to do something in Python when I finish
What to do when you can't bind CaboCha to Python
Not surprisingly known! ?? What about the arguments of built-in functions? What school are you from? [Python]
Effective Python Note Item 20 Use None and the documentation string when specifying dynamic default arguments