-1

Say I have a function foo that takes a list baz, and in foo I wanted to clear baz like so:

baz = []
foo(baz)

foo(baz):
    baz = []

Now, this code does not do what I would want it to do, because it creates a new local list called baz. I know that there are other ways of doing this, but I would like to know Python resolves ambiguities like this where the statement

 baz = []

could be interpreted as telling Python to point the outer scope baz variable at a new empty chunk of memory or to create a new pointer pointing to an empty chunk of memory.

EDIT

Please be aware that I am not asking how to clear a list. I am asking about the behavior of the Python interpreter. Please read the question clearly before downvoting.

Luca
  • 515
  • 5
  • 17
  • 1
    Well I know how to clear the list. I just used del foo[:] I was wondering about how the Pyhton interpreter views such a situation. – Luca Jun 30 '16 at 22:04
  • Assignment is always interpreted as a local variable unless you use the `global` keyword. However, you've named the parameter `baz`, so you won't be allowed to reference the global `baz`. Python variables are not like C,Java etc. variables. See this great talk: https://www.youtube.com/watch?v=_AEJHKGk9ns – juanpa.arrivillaga Jun 30 '16 at 22:06
  • You can see the interpreter's behavior by running code. What are you actually asking about? Variable scope? – TigerhawkT3 Jun 30 '16 at 22:08
  • @TigerhawkT3: You can see the decision the interpreter makes (if you can interpret what you're seeing correctly), but you can't see how the decision is made so easily. – user2357112 Jun 30 '16 at 22:09
  • Yes, I am asking why does the interpreter make that decision. What is the design reason? – Luca Jun 30 '16 at 22:10
  • @LucaDelSignore you should really read the post linked in Luca's answer – juanpa.arrivillaga Jun 30 '16 at 22:16
  • Thanks. I will check it out. – Luca Jun 30 '16 at 22:19

5 Answers5

2

Python will only treat variable assignment as assigning to a variable from an outer scope if you explicitly tell it to with the global or nonlocal keywords. global is for global variables, and nonlocal is a Python 3-exclusive keyword for closure variables:

x = 1
def change_x():
    global x
    x = 2
def dont_change_x():
    # no global
    x = 3

change_x()
print(x)  # prints 2

dont_change_x()
print(x)  # still prints 2

Otherwise, it will always interpret assignment as assigning to a local variable.

user2357112
  • 260,549
  • 28
  • 431
  • 505
1

If you intend to clear the items in your list, you would not need to reassign the current name to a new list, just clear the old one by slicing:

foo(baz):
    baz[:] = [] # clears out list baz

baz[:] is a way of indexing all the items in your list and assigning them a new value

Update:

If you use the same in an assignment to a new list, the interpreter simply reassigns that name to a new list object:

>>> baz = []
>>> id(baz)
14832064
>>> baz = []
>>> id(baz)
14834304

Except you use slicing to refactor the old list, the name baz will no longer be a reference to the old list.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
1

Take a look at this post to understand python way of passing parameters by assignment.

What is happening is that you are redefining the variable baz to another list, so it doesn't have the reference to the outer baz anymore. You need to manipulate the elements in the list directly.

For example, if you're adding an element to baz, the outer list will get the changes:

def foo(baz):
    baz.append('baz')

But by doing this:

def foo(baz):
    baz = []

You assign a new list to baz and the reference to your outer baz is now broken.

In your case, you have 2 options to clear the list:

del baz[:]
baz[:] = []
Community
  • 1
  • 1
Simon
  • 774
  • 4
  • 21
0

Use slicing:

>>> def foo(baz):
...     baz[:] = []
...
>>> baz = [1, 2]
>>> foo(baz)
>>> baz
[]

The my_list[:] tells Python to replace all of the elements in my_list with the content on the right side of the assignment statement, referring to the same my_list object.

TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
-1

If you want to clear the list, use .clear() instead of creating a new list:

def foo(baz):
    baz.clear()

Side note: To access the outer baz in your foo() you can to use global keyword. However in that case there will be no ambiguity, as python will force you to rename the argument by throwing SyntaxError.

def foo(baz2):
    global baz
    baz = []

Plase note that usage of global is discouraged.

Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162