Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Unlike many languages, Python doesn't really have variables: only objects and names. (And namespaces, I guess.) For example,

sage: a = [1,2]
sage: a
[1, 2]

doesn't declare a variable a and set it to the list [1,2]. We sometimes talk like this, because it's often close enough for government work, but it's not really accurate. What happens is that a list object is created and the name a is defined to refer to it (a process often called 'binding'). We can make other names refer to the same object:

sage: b = a
sage: b
[1, 2]
sage: b[0] = 17
sage: b
[17, 2]
sage: a
[17, 2]
sage: a is b
True

So in the case of a loop like this:

sage: a = [1,2]
sage: for item in a:
....:     print item
....:     item = 4
....:     
1
2
sage: a                                           
[1, 2]

a doesn't change because item = 4 isn't the equivalent of (*item) = 4. item isn't a pointer, it's just a name. item = 4 means "take the name 'item' and bind it to the integer object 4". From Python's perspective, why should alist care that you've decided to start using "item" to refer to the number 4?

If you want to affect alist, you have to grasp one of the elements, say by getting an index:

sage: for i, item in enumerate(a):
....:     print i, item
....:     a[i] = item * 10
....:     
0 1
1 2
sage: a
[10, 20]

Note that you can modify item directly, if the object referred to by item is mutable. For example:

sage: a = [[1,2], [3,4]]
sage: for item in a:
....:     print item
....:     item += [99]
....:     
[1, 2]
[3, 4]
sage: a
[[1, 2, 99], [3, 4, 99]]

and so on.

Unlike many languages, Python doesn't really have variables: only objects and names. (And namespaces, I guess.) For example,

sage: a = [1,2]
sage: a
[1, 2]

doesn't declare a variable a and set it to the list [1,2]. We sometimes talk like this, because it's often close enough for government work, but it's not really accurate. What happens is that a list object is created and the name a is defined to refer to it (a process often called 'binding'). We can make other names refer to the same object:

sage: b = a
sage: b
[1, 2]
sage: b[0] = 17
sage: b
[17, 2]
sage: a
[17, 2]
sage: a is b
True

So in the case of a loop like this:

sage: a = [1,2]
sage: for item in a:
....:     print item
....:     item = 4
....:     
1
2
sage: a                                           
[1, 2]

a doesn't change because item = 4 isn't the equivalent of (*item) = 4. item isn't a pointer, it's just a name. item = 4 means "take the name 'item' and bind it to the integer object 4". From Python's perspective, why should alist care that you've decided to start using "item" to refer to the number 4?

If you want to affect alist, you have to grasp one of the elements, say by getting an index:

sage: for i, item in enumerate(a):
....:     print i, item
....:     a[i] = item * 10
....:     
0 1
1 2
sage: a
[10, 20]

Note that you can modify item what item refers to directly, if if the object referred to by item is mutable. For example:

sage: a = [[1,2], [3,4]]
sage: for item in a:
....:     print item
....:     item += [99]
....:     
[1, 2]
[3, 4]
sage: a
[[1, 2, 99], [3, 4, 99]]

and so on.

Unlike many languages, Python doesn't really have variables: only objects and names. (And namespaces, I guess.) For example,

sage: a = [1,2]
sage: a
[1, 2]

doesn't declare a variable a and set it to the list [1,2]. We sometimes talk like this, because it's often close enough for government work, but it's not really accurate. What happens is that a list object is created and the name a is defined to refer to it (a process often called 'binding'). We can make other names refer to the same object:

sage: b = a
sage: b
[1, 2]
sage: b[0] = 17
sage: b
[17, 2]
sage: a
[17, 2]
sage: a is b
True

So in the case of a loop like this:

sage: a = [1,2]
sage: for item in a:
....:     print item
....:     item = 4
....:     
1
2
sage: a                                           
[1, 2]

a doesn't change because item = 4 isn't the equivalent of (*item) = 4. item isn't a pointer, it's just a name. item = 4 means "take the name 'item' and bind it to the integer object 4". From Python's perspective, why should alist the a list care that you've decided to start using "item" to refer to the number 4?

If you want to affect alista, you have to grasp one of the elements, say by getting an index:

sage: for i, item in enumerate(a):
....:     print i, item
....:     a[i] = item * 10
....:     
0 1
1 2
sage: a
[10, 20]

Note that you can modify what item refers to directly, if the object referred to by item is mutable. For example:

sage: a = [[1,2], [3,4]]
sage: for item in a:
....:     print item
....:     item += [99]
....:     
[1, 2]
[3, 4]
sage: a
[[1, 2, 99], [3, 4, 99]]

and so on.

Unlike many languages, Python doesn't really have variables: only objects and names. (And namespaces, I guess.) For example,

sage: a = [1,2]
sage: a
[1, 2]

doesn't declare a variable a and set it to the list [1,2]. We sometimes talk like this, because it's often close enough for government work, but it's not really accurate. What happens is that a list object is created and the name a is defined to refer to it (a process often called 'binding'). We can make other names refer to the same object:

sage: b = a
sage: b
[1, 2]
sage: b[0] = 17
sage: b
[17, 2]
sage: a
[17, 2]
sage: a is b
True

So in the case of a loop like this:

sage: a = [1,2]
sage: for item in a:
....:     print item
....:     item = 4
....:     
1
2
sage: a                                           
[1, 2]

a doesn't change because item = 4 isn't the equivalent of (*item) = 4. item isn't a pointer, it's just a name. item = 4 means "take the name 'item' and bind it to the integer object 4". From Python's perspective, why should the a list care that you've decided to start using "item" to refer to the number 4?

If you want to affect a, you have to grasp one of the elements, say by getting an index:

sage: for i, item in enumerate(a):
....:     print i, item
....:     a[i] = item * 10
....:     
0 1
1 2
sage: a
[10, 20]

Note that you can modify what item refers to directly, if the object referred to by item is mutable. For example:

sage: a = [[1,2], [3,4]]
sage: for item in a:
....:     print item
....:     item += [99]
....:     
[1, 2]
[3, 4]
sage: a
[[1, 2, 99], [3, 4, 99]]

and so on.

UPDATE:

Here's an example of how we would handle things like this in Python via a dictionary, without dynamically creating local variables:

sage: set_random_seed(3)
sage: vv = [var("x%d" % i) for i in [0..5]]
sage: vv
[x0, x1, x2, x3, x4, x5]
sage: vals = [random() for v in vv]
sage: vals
[0.43088005103813976, 0.8358366908518607, 0.8023253357960184, 0.4891524489091327, 0.7822037482240924, 0.7607638369816612]
sage: vdict = dict(zip(vv, vals))
sage: vdict
{x5: 0.7607638369816612, x3: 0.4891524489091327, x2: 0.8023253357960184, x0: 0.43088005103813976, x4: 0.7822037482240924, x1: 0.8358366908518607}
sage: some_expr = sum(random() * v**i for v in vv)
sage: some_expr
0.6925472846314387*x0^5 + 0.19968616753011514*x1^5 + 0.9416651257671081*x2^5 + 0.9556540407131406*x3^5 + 0.7656492351180494*x4^5 + 0.584583199716608*x5^5
sage: some_expr.subs(vdict)
0.804750970712524

Regarding the comments:

I'm afraid I don't understand what is meant by 'manually referring to variable names'. As opposed to what other methods of referring to them?

When the variables (or names) are kept in a dictionary I can do all sorts of nice things to them as a collection. Not so much if I rebind the local names something else. For example, say I do what you suggest, and type "A=B". I don't think it'll do what you want:

sage: var("A B")
(A, B)
sage: expr = A + B
sage: expr
A + B
sage: A = B
sage: A
B
sage: expr 
A + B

You can give the name "A" to anything you like, but it won't affect the object to which A refers, so I don't really the the point. What I mean by "manually" is that because of the above fact, namely, that existing references to the object don't change because you changed a name, the only way you can actually take advantage of the change later is if you actually execute a command like

sage: A + B
2*B

where you have an explicit reference to the name A.

It's worth rememebering that "assignment" in Python is using a dictionary. Type locals(), for example, to see the locals() dict.

Unlike many languages, Python doesn't really have variables: only objects and names. (And namespaces, I guess.) For example,

sage: a = [1,2]
sage: a
[1, 2]

doesn't declare a variable a and set it to the list [1,2]. We sometimes talk like this, because it's often close enough for government work, but it's not really accurate. What happens is that a list object is created and the name a is defined to refer to it (a process often called 'binding'). We can make other names refer to the same object:

sage: b = a
sage: b
[1, 2]
sage: b[0] = 17
sage: b
[17, 2]
sage: a
[17, 2]
sage: a is b
True

So in the case of a loop like this:

sage: a = [1,2]
sage: for item in a:
....:     print item
....:     item = 4
....:     
1
2
sage: a                                           
[1, 2]

a doesn't change because item = 4 isn't the equivalent of (*item) = 4. item isn't a pointer, it's just a name. item = 4 means "take the name 'item' and bind it to the integer object 4". From Python's perspective, why should the a list care that you've decided to start using "item" to refer to the number 4?

If you want to affect a, you have to grasp one of the elements, say by getting an index:

sage: for i, item in enumerate(a):
....:     print i, item
....:     a[i] = item * 10
....:     
0 1
1 2
sage: a
[10, 20]

Note that you can modify what item refers to directly, if the object referred to by item is mutable. For example:

sage: a = [[1,2], [3,4]]
sage: for item in a:
....:     print item
....:     item += [99]
....:     
[1, 2]
[3, 4]
sage: a
[[1, 2, 99], [3, 4, 99]]

and so on.

UPDATE:

Here's an example of how we would handle things like this in Python via a dictionary, without dynamically creating local variables:

sage: set_random_seed(3)
sage: vv = [var("x%d" % i) for i in [0..5]]
sage: vv
[x0, x1, x2, x3, x4, x5]
sage: vals = [random() for v in vv]
sage: vals
[0.43088005103813976, 0.8358366908518607, 0.8023253357960184, 0.4891524489091327, 0.7822037482240924, 0.7607638369816612]
sage: vdict = dict(zip(vv, vals))
sage: vdict
{x5: 0.7607638369816612, x3: 0.4891524489091327, x2: 0.8023253357960184, x0: 0.43088005103813976, x4: 0.7822037482240924, x1: 0.8358366908518607}
sage: some_expr = sum(random() * v**i for v in vv)
sage: some_expr
0.6925472846314387*x0^5 + 0.19968616753011514*x1^5 + 0.9416651257671081*x2^5 + 0.9556540407131406*x3^5 + 0.7656492351180494*x4^5 + 0.584583199716608*x5^5
sage: some_expr.subs(vdict)
0.804750970712524

Regarding the comments:

I'm afraid I don't understand what is meant by 'manually referring to variable names'. As opposed to what other methods of referring to them?

When the variables (or names) are kept in a dictionary I can do all sorts of nice things to them as a collection. Not so much if I rebind the local names to something else. For example, say I do what you suggest, and type "A=B". I don't think it'll do what you want:

sage: var("A B")
(A, B)
sage: expr = A + B
sage: expr
A + B
sage: A = B
sage: A
B
sage: expr 
A + B

You can give the name "A" to anything you like, but it won't affect the object to which A refers, so I don't really the see the point. What I mean by "manually" is that because of the above fact, fact -- namely, that existing references to the object don't change because you changed a name, name -- the only way you can actually take advantage of the change later is if you actually execute a command like

sage: A + B
2*B

where you have an explicit reference to the name A.. And that means in one way or another you're hardcoding the reference.

It's worth rememebering that "assignment" in Python is using a dictionary. Type locals(), for example, to see the locals() dict.

[Note that one could use exec to achieve your goal, but I didn't even want to mention it until I'd had a run at convincing you this is not the way to go.]