2

I want to assign the value to a list in a function

a = []
def bar(a):
    b = [1,2,3]
    a = b[1:]
    return
bar(a)
print(a)

But I fount a is still an empty list, The only way I can think of is to declare a global list

a = []
def bar():
    global a
    b = [1,2,3]
    a = b[1:]
    return
bar()
print(a)

Is there a better way to do this without returning anything.

Zesong
  • 57
  • 2
  • 4
    "Is there a better way to do this without returning anything.", no the better way is to return a value – Sayse Mar 29 '22 at 14:21
  • From such a trivial example, I'd suggest: don't. Global state is generally a bad idea. – jonrsharpe Mar 29 '22 at 14:21
  • 2
    `a.extend(b[1:])`, if you want to mutate the object passed as an argument. – chepner Mar 29 '22 at 14:23
  • "Is there a better way to do this without returning anything." Do what exactly? Modifying globals instead of returning results is generally a bad thing to do, so there isn't really any way to do that well. What is the *purpose* of the assignment? – MisterMiyagi Mar 29 '22 at 14:27

3 Answers3

2

lists are mutable, so you can pass a list to a function that modifies the list and you wouldn't have to return it. You'd have to change the logic slightly in your function to modify a instead of redefining a:

a = []
def bar(a):
    b = [1,2,3]
    a.extend(b[1:])
bar(a)
print(a)
>>> print(a)
[2, 3]
1

The solution is the code below, but the best way is always to return a value.

a = []

def foo():
    b = [1,2,3]
    a.extend(b[1:])

foo()
# a = [1, 2, 3]

Explanation: You are creating a new list in the scope of the function instead, but by using built in function like append, the list will be modified as python instead uses the one defined in global scope. This is because in python variables are not declared through the use of key words like for example javascript:

let x = 3; // variable x is created
x = 4; // variable x is redeclared

they are declared automatically this causes python to create a new variable in the scope of the function called list:

a = []

def foo():
    a = [1, 2, 3] # creates list in the scope of this function

foo()
# a = []

But if we instead call methods on the list "a" in the function it will instead use the list defined in the global scope, like this:

a = []

def foo():
    a.append(1) # uses list defined in global scope
    a.append(2)
    a.append(3)

foo()
# a = [1, 2, 3]
0

Using global is a bad idea -- it makes your code more confusing, and it can easily lead to bugs if you rename (or reuse) a variable in one part of the code that interacts with your use of global in an unexpected way.

A mutable object that's passed to a function can be mutated within the function; they key is that you have to act on that object, rather than assigning a new object to the same name within the function. Taking your first example:

a = []
def bar(a):
    b = [1,2,3]
    a = b[1:]

bar(a)
print(a)

you could do this in place of a = b[1:]

    a[:] = b[1:]  # slice assignment overwriting all of a with b[1:]

Another option is to return the new list to the caller, rather than overwriting the caller's data within the function. That allows the caller to control what is done with the data. For example:

a = []
def bar():
    b = [1,2,3]
    return b[1:]

a = bar()
print(a)  # [2, 3]
Samwise
  • 68,105
  • 3
  • 30
  • 44