Ask Your Question

Variable assignment in list

This is a very basic question because I am a new user of SAGE with a background mostly in Java and C++. But in the following session:

sage: var('A')
A
sage: var('B')
B
sage: for item in alist:
item = B
print item
....:
B
sage: for item in alist:
print item
....:
A


I am not sure why the value of the item in the list is printed as 'A' instead of 'B'. During the previous loop it seems like it assigned the value 'B' and printed out that the item was 'B. This may be an issue of the line 'item = B' returning a transient copy of the item, instead of a reference to the item. Can someone explain what is going on in programming language terms and tell me how to fix this so that the last line would print 'B'?

EDIT: I should explain that what I want to do is not just change the items in the list, so I don't want to just make alist conatin the variable 'B'. I actually want to assign the value 'B' to the variable 'A', so that when I type 'A' into SAGE, the output is 'B'. This can be accomplished in this example with the one command:

sage: A = B


but the point is that if I have two lists

1. listVariables, e.g. [Y_1,...Y_n]
2. listExpressions, e.g. [X^2, X^3, Z^4, ..., XZ]

of unknown length and contents, except that the two lists have the same number of elements, I want to assign the value contained in listExpressions[i] to the variable in listVariables[i] by looping over the lists.

edit retag close merge delete

1 answer

Sort by » oldest newest most voted

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 ...

more

Comments

Thanks for your very clear and detailed answer. But I realized I wasn't unambiguous about what I wanted to do. I actually wanted to assign the value 'B' to every variable in the list, not change the contents of the list, which I am just using as a vehicle for doing the assignment. I have added a clarification in the original question above.

( 2012-06-12 17:27:25 -0500 )edit

@heatkernel: _why_ do you want to do that? Attempts to manually refer to variable names in this way are almost always a sign that someone is trying to import a non-Pythonic way of solving a problem into Python. In this case, probably a dictionary is the right answer, but I'd need to know your use case to be sure.

( 2012-06-12 17:31:35 -0500 )edit

If the program/function has n (the length of the list) as an integer parameter, so that there are n variables o have values assigned to them, and the expressions you want to assign also depend on n (so a previous part of the program produces both the list of assignee variables and assignment expressions), you can't hard code in the assignment. 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? Not trying to be tendentious, I am just too new to SAGE to understand what you mean here. A dictionary might work as a substitute for assignment, but I still prefer the variable to be assigned the values.

( 2012-06-12 17:38:15 -0500 )edit

@heatkernel: you don't have to. I'll give an example of how we do this.

( 2012-06-12 17:40:22 -0500 )edit

Thanks, DSM, I think the point you are making, if I may try to rephrase it, is that in SAGE, if you want to implement something close to (or the same as(?)) mathematical equality of a variable "A" with a more complicated expression "f(x)", you had better do it through a dictionary (which is the same as hashtable, right?). If you make the definition of "A" as "f(x)" with "=" instead of a dictionary, this just binds the local name "A" to "f(x)" and this this definition of "A" won't pass through to other expressions defined in terms of "A", such as the "expr" in your example. Anyway, I will try to work with dictionaries instead of "="'s for assignment and post other questions as they arise.

( 2012-06-13 18:35:10 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Stats

Asked: 2012-06-12 15:17:33 -0500

Seen: 1,023 times

Last updated: Jun 12 '12