elenaby
elenaby

Reputation: 167

Using parameters in function without changing it in Python

I fould that I can't use parameter in function without changing it.

For example:

l=[ 5, 0, 0,   0, 0, 0,   0, 0, 2 ]
def format_print(problem):
    print_out = problem
    for i in range(len(print_out)):
        if print_out[i] == 0:
            print_out[i] = "."
    print(print_out)

format_print(l)

I want l to stay equal l=[ 5, 0, 0, 0, 0, 0, 0, 0, 2 ] and print_out to be [5, '.', '.', '.', '.', '.', '.', '.', 2]

Now, they are both equal [5, '.', '.', '.', '.', '.', '.', '.', 2]

Is there a way to implement it?

Thank you in advance!

Upvotes: 0

Views: 939

Answers (3)

ludaavics
ludaavics

Reputation: 678

This is what is going on behind the scene:

  • you create a list object [ 5, 0, 0, 0, 0, 0, 0, 0, 2 ] and store it somewhere in memory
  • using the assignment operator =, you add a label l to that particular spot in your memory
  • when you execute format_print(l), you pass, via the name l the location of that particular spot in your memory
  • once inside your function, you assign a new label, problem, then a third label print_out to that exact same object you first created

During all this process, there is only one list that exists (even though it now responds to 3 different names). So as you modify l, print_out, or problem, you're modifying that one version of your object.

One solution, would be to explicitly create copies of your object. However, I think that can get quickly confusing. What if you start having nested lists? You now need to worry about copying those too.

While it may not be the most efficient, in general, the safest way, to write your functions is to create a brand new list which you will populate as you traverse your original list:

l = [ 5, 0, 0,   0, 0, 0,   0, 0, 2 ]
def format_print(problem):
    solution = [None] * len(problem)
    for i, v in enumerate(problem):
        solution[i] = v if v != 0 else '.'
    print(solution)

In your particular case, you can be quite concise:

solution = [v if v != 0 else '.' for v in l]

Upvotes: 0

joaquin
joaquin

Reputation: 85615

Don't made printout equal to l (because what you get is not a new object but a reference to the same object), use another list

l = [ 5, 0, 0, 0, 0, 0, 0, 0, 2 ]
def format_print(problem):
    print_out = []
    for item in problem:
        if item == 0:
            print_out.append(".")
        else:
            print_out.append(item)
    print(print_out)

In any case, you do not need any function because you can resolve the problem with a list comprehension:

problem = [ 5, 0, 0, 0, 0, 0, 0, 0, 2 ]    
print_out = [item if item !=0 else '.' for item in problem]

As said in another post map is also a good and more general option

Upvotes: 0

Oleg Butuzov
Oleg Butuzov

Reputation: 5395

Copy()

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.

You can use copy() function with will copy list, not point it to new var.

import copy
list1 = [1,2,3,4]
# First List
print(id(list1), " is ", list1 )

list2 = list1
# First List
print(id(list2), " is ", list2 )

list3 = copy.copy(list2)
# First List
print(id(list3), " is ", list3 )

map()

But, its better to use map(), in your example function to filter/map values in your list.

list1 = [0, 1,2,3,4]
# First List
print(id(list1), " is ", list1 )

def dot(x): 
    return "." if x == 0 else x;

list2 = map(dot, list1);
print(id(list2), " is ", list2 )
print(id(list1), " is ", list1 )

Upvotes: 1

Related Questions