Posts: 142
Threads: 68
Joined: Jul 2023
hi
what is difference between f(b) and f(b[:]) in below? when i run them the outputs are different
1)
b=[1,2]
id(b)
def f(a):
a[0]=3
print("a: ",a, "id(a): ",id(a))
f(b)
print("b , id(b)",b,id(b)) 2)
b=[1,2]
id(b)
def f(a):
a[0]=3
print("a: ",a, "id(a): ",id(a))
f(b[:])
print("b , id(b)",b,id(b)) please explain, thanks
Posts: 6,802
Threads: 20
Joined: Feb 2020
Oct-04-2023, 11:17 AM
(This post was last modified: Oct-04-2023, 11:17 AM by deanhystad.)
b[:] makes a slice of b. The slice has all the elements as b. Did you try looking up "python [:]"?
Posts: 7,320
Threads: 123
Joined: Sep 2016
Oct-04-2023, 01:26 PM
(This post was last modified: Oct-04-2023, 01:26 PM by snippsat.)
The be more accurate when do f(b[:] you are making a copy of b then pass if to f .
func-1 you're passing the reference of the list,so the function modifies the original list.
func-2 you're passing a shallow copy of the list to the function,so the original list remains unchanged.
To give an other example,which also is a common mistake(modify a list you loop over) why is albatross in output?
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
for w in words:
if len(w) > 3:
words.remove(w)
print(words) Output: ['albatross', 'dog']
If loop over copy of words then it work.
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
for w in words[:]:
if len(w) > 3:
words.remove(w)
print(words) Output: ['dog']
Or better do not use copy or remove at all.
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
words = [w for w in words if len(w) <= 3]
print(words) Output: ['dog']
Posts: 6,802
Threads: 20
Joined: Feb 2020
I don't think that is more accurate at all. b.copy(), b[:] and b[0:] all create new lists that are populated with the all the elements from b, so they are all "copies", but the lists returned by b[:] and b[0::] are created through slicing. New python programmers need to learn about list slicing.
Posts: 142
Threads: 68
Joined: Jul 2023
(Oct-04-2023, 01:26 PM)snippsat Wrote: The be more accurate when do f(b[:] you are making a copy of b then pass if to f .
func-1 you're passing the reference of the list,so the function modifies the original list.
func-2 you're passing a shallow copy of the list to the function,so the original list remains unchanged.
To give an other example,which also is a common mistake(modify a list you loop over) why is albatross in output?
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
for w in words:
if len(w) > 3:
words.remove(w)
print(words) Output: ['albatross', 'dog']
If loop over copy of words then it work.
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
for w in words[:]:
if len(w) > 3:
words.remove(w)
print(words) Output: ['dog']
Or better do not use copy or remove at all.
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
words = [w for w in words if len(w) <= 3]
print(words) Output: ['dog']
hi
I copied and ran the two codes and their outputs was as yours. but I can not understand it.
why in the first code output, there is "albatross " ?
thanks
Posts: 7,320
Threads: 123
Joined: Sep 2016
(Oct-05-2023, 07:04 AM)akbarza Wrote: why in the first code output, there is "albatross " ? When modify a list while iterating over it,end up skipping some items in the list(mess up indexing).
First item: eagle' (length > 3) → Remove eagle from the list.
Due to the removal, albatross moves to the first position in the list.
But the loop has already processed the first position, so it moves to the second item, which is now mouse .
In this example are making a new list ,and not modifying the original list
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
words = [w for w in words if len(w) <= 3]
print(words) Output: ['dog']
If write code ove(list comprehension) as a ordinary loop.
words = ['eagle', 'albatross', 'mouse', 'dog', 'tiger']
filtered_words = []
for w in words:
if len(w) <= 3:
filtered_words.append(w)
print(filtered_words) Output: ['dog']
Then is easier to see that we append to new list filtered_words and not modifying the original list words
Posts: 5
Threads: 0
Joined: Feb 2024
Feb-21-2024, 08:02 PM
(This post was last modified: Apr-24-2025, 06:31 PM by bterwijn.)
You can use module 'memory_graph':
https://pypi.org/project/memory-graph
to see the call stack. Here stack frame "0: <module>" holds all the global variables and stack frame "1: f" holds the local variables of the f() function.
import memory_graph as mg # see install instructions at link above
id(b)
def f(a):
a[0]=3
print("a: ",a, "id(a): ",id(a))
mg.show( mg.stack() ) # draw call stack
f(b)
print("b , id(b)",b,id(b))
In the first program we see that after calling the f() function local variable 'a' shares its data with global variable 'b' of the calling frame. Therefore if 'a' is changed 'b' is also changed.
Now the second program:
import memory_graph as mg
id(b)
def f(a):
a[0]=3
print("a: ",a, "id(a): ",id(a))
mg.show( mg.stack() ) # draw call stack
f(b[:])
print("b , id(b)",b,id(b))
Here f() is called with 'b[:]' (list slicing), so a copy of its data is send to f(). Therefore the local variable 'a' does not share any data with global variable 'b' of the calling frame and when 'a' is changed is does not change 'b'.
Full disclosure: I am the developer of memory_graph.
|