i have the problem where i set a variable but it creates a new one instead, i am not quite sure what is going on here. I have tried using global, setting the variables first and tried to use a tupple but just can't get it working. but this is the problem:
>>> variable = 1
>>> variableList = [variable]
>>> variableList[0] = 2
>>> print(variable)
1
as you can see it variable stays 1 although i set it to 2, is there a easy way to fix this?
Doing variableList = [variable] actually created a new reference(variableList[0]) to the object 1. And when you did variableList[0] = 2, it removed one reference from 1 and assigned variableList[0] to 2. So, using an assignment you can never modify other references.
>>> import sys
>>> variable = 1000
>>> sys.getrefcount(variable)
2
>>> variableList = [variable]
>>> sys.getrefcount(variable) # Reference count increased by 1
3
>>> variableList[0] = 2
>>> sys.getrefcount(variable) #Reference count decreased by 1
2
In fact even you've used +=, that too wouldn't have affected variable because you don't modify a immutable object, you simply assign a new object to that variable name.
>>> a = 100
>>> b = a
>>> b += 10 #This too only affects b
>>> a
100
>>> b
110
But, if variable points to a mutable object and you perform some in-place operation on that object from either variable or variableList[0], then you'll see that both of them have changed.
>>> a = []
>>> b = [a]
>>> b[0].append(1) #in-place operation on a mutable object affects all references
>>> a
[1]
>>> b
[[1]]
you don't set variable. you just change variableList content.
variableList[0] it's a variable like variable so the command variableList = [variable] just copy its value.
it is just like this:
>>> a = 1
>>> b = a
>>> b = 2
>>> print(a)
1
You're reassigning the 0th element of the list (not Array), to the Integer 2, you are not overwriting the variable variable.
>>> variable = 1
>>> variableList = [variable]
>>> variableList[0] = 2
>>> print(variable)
>>> 1
>>> print(variableList)
[2]
It suggest you also look up mutability, as it's important to note that integers are immutable:
The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable.
When you did :variableList = [variable]
you created the first element of veribleList and made its value to balue of variable but it dont makes this first element a varible you just coppied its value so when you change variableList[0] it has nothing to do with variable
Related
List reference append code
a = [1,2,3,4,5]
b = a
b.append(6)
print(a)
print(b)
#ans:
[1,2,3,4,5,6]
[1,2,3,4,5,6]
Integer reference in int
a = 1
b = a
b +=1
print(a)
print(b)
#ans:
1
2
how reference works in python integer vs list ? in list both value are same, why is in integer section a value is not 2 ?
In Python, everything is an object. Everything is a name for an address (pointer) per the docs.
On that page you can scroll down and find the following:
Numeric objects are immutable; once created their value never changes
Under that you'll see the int type defined, so it makes perfect sense your second example works.
On the top of the same page, you'll find the following:
Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory.
Python behaves just like C and Java in that you cannot reassign where the pointer to a name points. Python, like Java, is also pass-by-value and doesn't have a pass-by-reference semantic.
Looking at your first example:
>>> a = 1
>>> hex(id(a))
'0x7ffdc64cd420'
>>> b = a + 1
>>> hex(id(b))
'0x7ffdc64cd440'
>>> print(a)
1
>>> print(b)
2
Here it is shown that the operation b = a + 1 leaves a at 1 and b is now 2. That's because int is immutable, names that point to the value 1 will always point to the same address:
>>> a = 1
>>> b = 2
>>> c = 1
>>> hex(id(a))
'0x7ffdc64cd420'
>>> hex(id(b))
'0x7ffdc64cd440'
>>> hex(id(c))
'0x7ffdc64cd420'
Now this only holds true for the values of -5 to 256 in the C implementation, so beyond that you get new addresses, but the mutability shown above holds. I've shown you the sharing of memory addresses for a reason. On the same page you'll find the following:
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 your example:
>>> a = [1, 2, 3, 4, 5]
>>> hex(id(a))
'0x17292e1cbc8'
>>> b = a
>>> hex(id(b))
'0x17292e1cbc8'
I should be able to stop right here, its obvious that both a and b refer to the same object in memory at address 0x17292e1cbc8. Thats because the above is like saying:
# Lets assume that `[1, 2, 3, 4, 5]` is 0x17292e1cbc8 in memory
>>> a = 0x17292e1cbc8
>>> b = a
>>> print(b)
'0x17292e1cbc8'
Long and skinny? You're simply assigning a pointer to a new name, but both names point to the same object in memory! Note: This is not the same as a shallow copy because no external compound object is made.
Suppose I co-assign two python variables to zero:
>>> x = y = 0
When I now assign to one value it changes independently of the other:
>>> y = 2
>>> x
0
>>> y
2
Now suppose I co-assign two python variables to an empty set:
>>> a = b = set([])
When I now add to one set, it changes the value of the other. Why?
>>> b.add(2)
>>> a
set([2])
>>> b
set([2])
As commments to OP answer are just implicit clues I am making them explicit:
y = 0
x = y
Names x and y reference the same int object with 0 value.
int objects are immutable. As you can't alter them, it actually doesn't
matter what object with zero value you are pointing to, if there were several.
When you assign y again with
y = 2
y now refers to a different int object with value 2.
x still refers to the old 0 value object.
If you consider mutable types like sets,
b = set()
a = b
a and b reference the same empty set object.
If you change the set object with an in-place assignment, or using an object method that changes it in-place, the object remains the same (but with its value content changed).
So you can see the changed object either through a or through b.
However, to compare apples with apples and follow the int sample, if you make
b = set() # a new empty set
b becomes a new different set empty object, while a still references the original.
>>> a = set()
>>> b = a
>>> id(a) == id(b)
True
>>> b = set()
>>> id(a) == id(b)
False
>>>
So behaviour is actually the same in both cases. But in int case you can't make changes to the object value.
Why is it that:
>>> a = 1
>>> b = a
>>> a = 2
>>> print(a)
2
>>> print(b)
1
...but:
>>> a = [3, 2, 1]
>>> b = a
>>> a.sort()
>>> print(b)
[1, 2, 3]
I mean, why are variables really copied and iterators just referenced?
Variables are not "really copied". Variables are names for objects, and the assignment operator binds a name to the object on the right hand side of the operator. More verbosely:
>>> a = 1 means "make a a name referring to the object 1".
>>> b = a means "make b a name referring to the object currently referred to by a. Which is 1.
>>> a = 2 means "make a a name referring to the object 2". This has no effect on which object anything else that happened to refer to 1 now refers to, such as b.
In your second example, both a and b are names referring to the same list object. a.sort() mutates that object in place, and because both variables refer to the same object the effects of the mutation are visible under both names.
Think of the assigned variables as pointers to the memory location where the values are held. You can actually get the memory location using id.
a = 1
b = a
>>> id(a)
4298171608
>>> id(b)
4298171608 # points to the same memory location
a = 2
>>> id(a)
4298171584 # memory location has changed
Doing the same with your list example, you can see that both are in fact operating on the same object, but with different variables both pointing to the same memory location.
a = [3, 2, 1]
b = a
a.sort()
>>> id(a)
4774033312
>>> id(b)
4774033312 # Same object
in your first example you've reassigned a's value after making b's value a. so a and b carry different values.
the same would've occurred in your second example if you had reassigned a to a new sorted list instead of just sorting it in place.
a = [3,2,1]
b = a
a.sort()
print b
[1,2,3]
but...
a = [3,2,1]
b = a
sorted(a)
print b
[3,2,1]
Code:
>>> a = 1
>>> b = 2
>>> l = [a, b]
>>> l[1] = 4
>>> l
[1, 4]
>>> l[1]
4
>>> b
2
What I want to instead see happen is that when I set l[1] equal to 4, that the variable b is changed to 4.
I'm guessing that when dealing with primitives, they are copied by value, not by reference. Often I see people having problems with objects and needing to understand deep copies and such. I basically want the opposite. I want to be able to store a reference to the primitive in the list, then be able to assign new values to that variable either by using its actual variable name b or its reference in the list l[1].
Is this possible?
There are no 'primitives' in Python. Everything is an object, even numbers. Numbers in Python are immutable objects. So, to have a reference to a number such that 'changes' to the 'number' are 'seen' through multiple references, the reference must be through e.g. a single element list or an object with one property.
(This works because lists and objects are mutable and a change to what number they hold is seen through all references to it)
e.g.
>>> a = [1]
>>> b = a
>>> a
[1]
>>> b
[1]
>>> a[0] = 2
>>> a
[2]
>>> b
[2]
You can't really do that in Python, but you can come close by making the variables a and b refer to mutable container objects instead of immutable numbers:
>>> a = [1]
>>> b = [2]
>>> lst = [a, b]
>>> lst
[[1], [2]]
>>> lst[1][0] = 4 # changes contents of second mutable container in lst
>>> lst
[[1], [4]]
>>> a
[1]
>>> b
[4]
I don't think this is possible:
>>> lst = [1, 2]
>>> a = lst[1] # value is copied, not the reference
>>> a
2
>>> lst[1] = 3
>>> lst
[1, 3] # list is changed
>>> a # value is not changed
2
a refers to the original value of lst[1], but does not directly refer to it.
Think of l[0] as a name referring to an object a, and a as a name that referring to an integer.
Integers are immutable, you can make names refer to different integers, but integers themselves can't be changed.
There were a relevant discussion earlier:
Storing elements of one list, in another list - by reference - in Python?
According to #mgilson, when doing l[1] = 4, it simply replaces the reference, rather than trying to mutate the object. Nevertheless, objects of type int are immutable anyway.
I don't know if the heading makes sense... but this is what I am trying to do using list
>>> x = 5
>>> l = [x]
>>> l
[5]
>>> x = 6
>>> l
[5] # I want l to automatically get updated and wish to see [6]
>>>
The same happens with dict, tuple. Is there a python object that can store the dynamic value of variable?
Thanks,
There's no way to get this to work due to how the assignment operator works in Python. x = WHATEVER will always rebind the local name x to WHATEVER, without modifying what previously x was previously bound to.(*)
You can work around this by replacing the integers with a container data type, such as single-element lists:
>>> x = [5]
>>> l = [x]
>>> l
[[5]]
>>> x[0] = 6
>>> l
[[6]]
but that's really a hack, and I wouldn't recommend it for anything but experimentation.
(*) Rebinding may actually modify previously bound objects when their reference count drops to zero, e.g. it may close files. You shouldn't rely on that, though.
A variable is a place to store data. A datastructure is a place to store data. Pick the one which meets your needs.
You can do it with the numpy module.
>>> from numpy import array
>>> a = array(5)
>>> a
array(5)
>>> l = [a]
>>> l
[array(5)]
>>> a.itemset(6)
>>> a
array(6)
>>> l
[array(6)]
Generally a 0-D numpy array can be treated as any regular value as shown below:
>>> a + 3
9
However, if you need to, you can access the underlying object as such:
>>> a.item()
6
Here's a kind of hacky method of dynamic access that isn't very extensible/flexible in its given form, but could be used as a basis for something better.
>>> a = 7
>>> class l:
def a_get(self):
global a
return a
def a_set(self, value):
global a
a = value
a = property(a_get, a_set)
>>> c = l()
>>> c.a
7
>>> a = 4
>>> c.a
4
>>> c.a = 6
>>> a
6