2
a = 'hello'
b = None
c = None
for x in [a, b, c]:
    if isinstance(x, (basestring, dict, int, float)) or x is None:
        x = [x]
a

returns 'hello', but expected ['hello']. However, this works:

a = 'hello'
a = [a]
a

returns ['hello'].

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • 3
    You are updating the value of `x` but not `a`. – Chris Lam Jun 28 '17 at 03:09
  • I have no idea about python, but many languages disallow assigning to the loop variable. It is under the control of the compiler; how do you expect the program to loop properly if you modify its loop variable? That being said, maybe python allows that. Just a possible reason. – Aganju Jun 28 '17 at 03:10
  • In the first code the result is in ```x``` not in ```a``` – Pablo Cesar Cordova Morales Jun 28 '17 at 03:11
  • Doh! Coding too late! Thanks for the help –  Jun 28 '17 at 03:22
  • Python's variables are just labels to values. You are not changing the value you are just pointing the label to a different value. Changing which value `x` points to does not change which value `a` points to. @Aganju python has no issues with changing the loop variable, as it is just reassigned on every loop to the `next()` value in the iteration. – AChampion Jun 28 '17 at 03:26
  • Does this answer your question? [Can't modify list elements in a loop](https://stackoverflow.com/questions/19290762/cant-modify-list-elements-in-a-loop) – mkrieger1 Jan 23 '22 at 19:52

3 Answers3

3

To achieve that, first you have to understand that you have two diferent refecerences, a and x (for each element), and the reference for the list [a,b,c], used only in the for loop, and never more.

To achieve your goal, you could do this:

a = 'hello'
b = None
c = None
lst = [a, b, c] #here I create a reference for a list containing the three references above
for i,x in enumerate(lst):
    if isinstance(x, (str,dict, int, float)) or x is None: #here I used str instead basestring
        lst[i] = [x]

print(lst[0]) #here I print the reference inside the list, that's why the value is now showed modified

['hello']

but as I said, if you do print(a) it will show again:

'hello' #here i printed the value of the variable a, wich has no modification

because you never did anything with it.

Take a look at this question to understand a little more about references How do I pass a variable by reference?

developer_hatch
  • 15,898
  • 3
  • 42
  • 75
2

Lets work through this one line at a time;

a = 'hello'  # assigns 'hello' to a.
b = None  # etc...
c = None
for x in [a, b, c]:  # Creates list from the values in 'a' 'b' and 'c', then iterates over them.
    # This if statement is always True. x is always either a string, or None.
    if isinstance(x, (basestring, dict, int, float)) or x is None:
        x = [x]  # On the first iteration, sets variable to the expected ['hello']
        # After that though - it replaces it with [None]
a  # = 'hello' - you have not assigned anything to the variable except on the first line.

The only variable that is ever set to ['hello'] is x, which is quickly overwritten with None. If you changed your if check to exclude or x is None and assigned to a instead of x you would get your desired result.

It's also worth noting that the list [a, b, c] is created when you start the for loop. Changing a b or c during the for loop will have no effect - the list has already been created.

Shadow
  • 8,749
  • 4
  • 47
  • 57
0

Other answers are great. I think, to generalize, the list element is immutable/hashable so the for loop returns a copy, not a reference to the original object. I should've spotted this, but teaches me for coding too long without sleep!

I ended up using this:

def lst(x):
    if isinstance(x, (basestring, dict, int, float)) or x is None:
        x = [x]
    return x
[a, b, c] = map(lst, [a, b, c])