Using Python 3.4 and working through examples in a book by O'Reily.
The example shows:
A = ['spam']
B = A
B[0] = 'shrubbery'
Result after running print A:
'shrubbery'
Now my thought process is thatA was defined but never changed.
This example yields a different result
A = 'string'
B = A
B = 'dog'
This is the result after running print A:
'string'
Can someone explain?
In the first example, you are modifying the list referenced by B.
Doing:
B[0] = 'shrubbery'
tells Python to set the first item in the list referenced by B to the value of 'shrubbery'. Moreover, this list happens to be the same list that is referenced by A. This is because doing:
B = A
causes B and A to each refer to the same list:
>>> A = ['spam']
>>> B = A
>>> A is B
True
>>>
So, any changes to the list referenced by B will also affect the list referenced by A (and vice-versa) because they are the same object.
The second example however does not modify anything. Instead, it simply reassigns the name B to a new value.
Once this line is executed:
B = 'dog'
B no longer references the string 'string' but rather the new string 'dog'. The value of A meanwhile is left unchanged.
As is the case in most modern dynamic languages, variables in python are actually references which are sort of like C pointers. This means that when you do something like A = B (where A and B are both variables), you simply make A point to the same location in memory as B.
In the first example you are mutating (modifying) an existing object in place -- this is what the variable_name[index/key] = value syntax does. Both A and B continue to point at the same thing, but this things first entry is now 'shrubbery', instead of 'spam'.
In the second example, you make B point at a different (new at this point) object when you say B = 'dog'.
I hope you could understand it with this way :-)
As you see in first method, both of them refers to same list, second one different.So in second way changes not effects on another one.
Mutable objects are Lists while Strings are immutable that's why you can change the memory address and the lists itself but not the string.
We are talking here about shared references and mutable / immutable objects . When you do B = A, both variables points to same memory address ( shared reference) .
First case , list is a mutable object ( it's state can be change ) but object memory address remains the same . So if you change it's state , then the other variable will see those changes as it points to same memory address .( A and B have same value as they point to same object in memory )
Second case , string is immutable ( you cannot change it ) .By doing
B = 'dog' , basically you create another object and now B points to another object ( another memory address ) . In this case A still points to same old memory reference ( A and B have different values )
Here are the differences between the two:
Here's a step by step analysis:
A = ['spam']
"A points to a list whose first element, or A[0], is 'spam'."
B = A
"B points to what A points to, which is the same list."
B[0] = 'shrubbery'
"When we set B[0] to 'shrubbery', the result can be observed in the diagram.
A[0] is set to 'shrubbery' as well."
print (A):
A = 'string'
"A points to 'string'."
B = A
"B points to what A points to, which is 'string'."
B = 'dog'
"Oh look! B points to another string, 'dog', now.
So does what A points to change? No."
The result can be observed in the diagram.
print (A):
Related
Given a list a = [1,2,3], why is the following statement true
id(a[:]) == id(a[:]) # true
while the following one is false?
b = a[:]
id(b) == id(a[:]) # false
Also, if I instead use a string (in place of a list), then both statements are true. Why? What am I missing?
The id is defined to be unique for an object across its lifetime. That is, two separate objects existing at the same time cannot have the same id. However, two separate objects existing at different time as well as objects not required to be separate may have the same id.
id(object)
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
Thus, one has to be mindful of two things when reasoning about id: When must the lifetime of objects overlap, and when must two objects be separate.
When the objects whose id we look at are created only for the id:
>>> # / / first a[:]
>>> # v v v v second a[:]
>>> id(a[:]) == id(a[:])
True
then the object are not required to exist at the same time. Each id(a[:]) expression can create the slice, get its id and then discard the slice before the equality between the ids is ever checked. This means both slice can have the same id as they never exist at the same time.
In contrast, when a slice is assigned to a variable it has to exist at least as long as the variable. Thus, when we check the id of an object via a variable
>>> b = a[:] # < ------------- first a[:]
>>> id(b) == id(a[:]) # < second a[:] |
False
>>> b # < ----------------/
…
its lifetime overlaps with that of the temporary slice. This means both slices must not have the same id as they never exist at the same time…
… iff slicing must create separate objects.
When comparing the behaviour of list and str, the key difference is that the latter does not have behaviour depending on its identity – roughly, this corresponds to mutable and immutable types.
When working with lists, identity is important because we can mutate a specific object. Even if two objects have the same initial value, mutation has a different effect:
>>> a, b = [1, 2, 3], [1, 2, 3]
>>> c = a # a, b, c have same value
>>> c += [4] # changing c has different effect on a and b
>>> a == b
False
When working with str, identity is irrelevant because we cannot mutate a specific object. If two objects have the same initial value, immutability guarantees they will always have the same value:
>>> a, b = "123", "123"
>>> c = a # a, b, c have same value
>>> c += "4" # changing c has *no* effect on a and b
>>> a == b
True
As a result, slicing a mutable list to a new list must always create a new object. Otherwise, mutating the slice would have unreliable behaviour.
In contrast, slicing an immutable str to a new str may create a new object. Even if it always provides the same object the behaviour is the same.
As a result of how id is defined – in respect to lifetime and separation – a Python implementation must use separate ids in specific cases but may use separate ids in all other cases.
In specific, a Python implementation is free to re-use ids if objects don't exist at the same time and is free to share ids if behaviour does not depend on identity.
CPython implementation detail: This is the address of the object in memory.
Memory has limited room and you can treat them as a storage house with shelves, you might want to label every shelf with some digits or somewhat so you can find their precise position for convenience.
Every time you create new stuff they all must have a place to put it somewhere. you create a variable a, which means it's an object and it was labeled some address on it. you create a value [1, 2, 3], it's another object and it still labeled some address on it.
Then you say
a = 50; you allocate 50 to a variable named a.
Under the hood, it says a's address will reference to another address where 50 lives. (it's pointer)
A variable is an object. A pile of data is an object. Actually, a computer itself doesn't need a variable called a. It already has the address of [1, 2, 3], it knows where it is in memory. The reason we need a variable called a is that we human beings need a name to represent this pile of data instead of using an address.
The example in C:
#include <stdio.h>
int main()
{
int a ;
printf("The address of a is %p\n\n", &a);
a = 55;
printf("The address of a is %p\n", &a);
printf("The address of 55's pointer is %p\n\n", 55);
a = 30;
printf("The address of a is %p\n", &a);
printf("The address of 30's pointer is %p\n\n", 30);
}
// The address of a is 0x7fffb44b83dc
// The address of a is 0x7fffb44b83dc
// The address of 55's pointer is 0x37
// The address of a is 0x7fffb44b83dc
// The address of 30's pointer is 0x1e
you can check this for further reading
Back to here, whatever value we create after there existing a = [1, 2, 3]
a[0], a[1], a[:2], a[:], a[::-1], etc. will occupy new space memory and has their own address individually, They are brand new objects since the script interpreted.
The a's address won't change whether you assign other value to it, it only leads to point to another value's address.
just print the ids
a = [1,2,3]
print(id(a), id(a[:])) # "a" has id#001 and its copy id#002
b = a[:] # here "b" inherits id#002 and the first copy of "a" dies
print(id(b), id(a[:])) # here "b" is still id#002, "a" is a new copy with id#003
I have been reading the Python Data Model. The following text is taken from here:
Types affect almost all aspects of object behavior. Even the
importance of object identity is affected in some sense: for immutable
types, operations that compute new values may actually return a
reference to any existing object with the same type and value, while
for mutable objects this is not allowed. E.g., after a = 1; b = 1, a
and b may or may not refer to the same object with the value one,
depending on the implementation, but after c = []; d = [], c and d are
guaranteed to refer to two different, unique, newly created empty
lists. (Note that c = d = [] assigns the same object to both c and d.)
So, it mentions that, for immutable types, operations that compute new values may actually return a reference to an existing object with same type and value. So, I wanted to test this. Following is my code:
a = (1,2,3)
b = (1,2)
c = (3,)
k = b + c
print(id(a))
>>> 2169349869720
print(id(k))
>>> 2169342802424
Here, I did an operation to compute a new tuple that has same the value and type as a. But I got an object referencing to different id. This means I got an object which references different memory than a. Why is this?
Answering the question based on comments from #jonrsharpe
Note "may actually return" - it's not guaranteed, it would likely be
less efficient for Python to look through the existing tuples to find
out if one that's the same as the one your operation creates already
exists and reuse it than it would to just create a new one.
Suppose we have two variables A and b(containing non-dictionary type element) and initially i make A=B.Now,i do operations on A and A only,and eventually value of A changes.The value of B should not change since,I want B to be the same value as it was initially that is equal to the previous value of A.But as A changes B changes too.How to store the initial value of A at variable B so that it does not change?
e.g.-
A=B
<operations on A> only
print B
This gives the value of A after operation.I want to modify this such that,when printed B gives the initial value of A,not the changed value.
The value of B should not change since,I want B to be the same value as it was initially that is equal to the previous value of A.
This is not true. Using the equal sign = means that the variable name will be pointing to an object on the right-hand side.
For example:
a = list(1, 2)
b = a
means that both a and b point to the object list(1, 2).
Therefore, changing a changes b.
As suggested in the comments, this is solved by using copy/deepcopy and in case of immutable data types this problem does not occur. Consider this:
a = 1
b = a # points to the same object as `a`
b = a + 1
Here in the last line a new object is created since ints are immutable and there is no way of changing the object 1.
Similarly with strings.
Hope this helps.
I was making a code, and variables started to behave strangely and get assigned to things which I thought they shouldn't. So, I decided to reduce the situation to minimal complexity in order to solve my doubts, and this is what happened:
The following code:
a = [2]
def changeA(c):
d = c
d[0] = 10
return True
changeA(a)
print(a)
prints '[10]'. This doesn't make sense to me, since I never assigned the list "a" to be anything after the first assignment. Inside the function changeA, the local variable d is assigned to be the input of the function, and it seems to me that this assignment is happening both ways, and even changing the "outside". If so, why? If not, why is this happening?
I've also noticed that the code
a = [2]
def changeA(c):
d = list(c)
d[0] = 10
return True
changeA(a)
print(a)
behaves normally (i.e., as I would expect).
EDIT: This question is being considered a duplicate of this one. I don't think this is true, since it is also relevant here that the locality character of procedures inside a function is being violated.
Python variables are references to objects, and some objects are mutable. Numbers are not, neither are strings nor tuples, but lists, sets and dicts are.
Let us look at the following Python code
a = [2] # ok a is a reference to a mutable list
b = a # b is a reference to the exact same list
b[0] = 12 # changes the value of first element of the unique list
print(a) # will display [12]
In the first example, you simply pass the reference of c(which is a) to d.
So whatever you do to d will happen on a.
In the second example, you copy the value of c(which is a) and give it to a new variable d.
So the d now has the same value as c(which is a) but different reference.
Note: you can see the reference or id of a variable using the id() function.
a = [2]
print id(a)
def changeA(c):
d = c
pirnt id(d)
d[0] = 10
return True
changeA(a)
print(a)
a = [2]
print id(a)
def changeA(c):
d = list(c)
print id(d)
d[0] = 10
return True
changeA(a)
print(a)
Its because when you do:
d = list(c)
that creates a new object. But when you do
d = c
You are making a reference to that object.
if you did
d.append(5)
to the first example you would get
[10,5]
Same operation to the second one and the list isn't modified.
Deeper explanation in the following link: http://henry.precheur.org/python/copy_list
In Python, names refer to values, so you have 2 names pointing to the same value.
In version 1 you create a list a, pass it in to the function under the pseudonym c, create another pseudonym d for the very same list, and then change the first value in that list. a, c, and d all refer to the same list.
In version 2, you're using list(c) which, to Python, means "take the contents of this iterable thing named c and make a new, different, list from it named d". Now, there are two copies of your list floating around. One is referred to as a or c, and the other is d. Therefore, when you update d[0] you're operating a second copy of the list. a remains unchanged.
'd=c' means reference copy as stated before. What it means, is that now d will reference the same object as c. As you are doing a direct manipulation on the referenced object, the value of the object a was referencing to is changed as well.
When you do 'd = list(c)' what it means that a new list object is created, with the baked of c. However, d is not referencing the same object as a anymore. Hence, the changes within the function doesn't impact a.
Except from http://www.stavros.io/tutorials/python/
# This swaps the variables in one line(!).
# It doesn't violate strong typing because values aren't
# actually being assigned, but new objects are bound to
# the old names.
>>> myvar, mystring = mystring, myvar
I don't understand the point he is making.
He means to say the two variables are essentially swapped without knowing their types or explicitly using an intermediate variable as you normally would. A weakly-typed swap looks like this:
temp = A
A = B
B = temp
A previously-unitialized temporary variable temp must be created in order to perform the swap. However, because no type is specified when temp is first created, it violates strong typing. Here is a strongly-typed swap:
int temp = A
A = B
B = temp
A swap like A, B = B, A does not violate strong typing because an intermediate variable doesn't need to be explicitly defined with or without a type. It's simply an assignment operation, and a basic assignment operation is always ambiguously typed (aka: A = B is the same regardless of whether you are using a strong-typed language or a weak-typed one).
An assignment like a=1 , conceptually Python will perform three distinct steps to carry out the request.
1.Create an object to represent the value 1
2.Create the variable a.
3.Link(or bound as in the link) the variable a to new object 1.
In your case, the statement
myvar, mystring = mystring, myvar
will change the variable-object bound relationship.