4

Let's say I have a function f() that takes a list and returns a mutation of that list. If I want to apply that function to five member variables in my class instance (i), I can do this:

for x in [i.a, i.b, i.c, i.d, i.e]:
    x[:] = f(x)

1) Is there a more elegant way? I don't want f() to modify the passed list.

2) If my variables hold a simple integer (which won't work with the slice notation), is there also a way? (f() would also take & return an integer in this case)

2
  • It seems like f is intended to take a list, but you're iterating over the list as well. Commented Jan 26, 2011 at 6:37
  • The lists that f takes are stored in i.a, i.b, etc. The iteration in the example is over the variables which are storing (referencing, for purists) the lists. OK, not actually over the variables, but that's the effect I'm looking for. Commented Jan 26, 2011 at 7:28

3 Answers 3

4

Another solution, though it's probably not elegant:

for x in ['a', 'b', 'c', 'd', 'e']:
    setattr(i, x, f(getattr(i, x)))
Sign up to request clarification or add additional context in comments.

2 Comments

This won't have the same effect as slice assignment in the case that the attributes are lists. It's still as close to what's desired as possible though so +1.
That's the exact functionality I'm looking for, though I was hoping it would be more readable.
2

Python doesn't have pass by reference. The best you can do is write a function which constructs a new list and assign the result of the function to the original list. Example:

def double_list(x):
    return [item * 2 for item in x]

nums = [1, 2, 3, 4]
nums = double_list(nums) # now [2, 4, 6, 8]

Or better yet:

nums = map(lambda x: x * 2, nums)

Super simple example, but you get the idea. If you want to change a list from a function you'll have to return the altered list and assign that to the original.

You might be able to hack up a solution, but it's best just to do it the normal way.

EDIT

It occurs to me that I don't actually know what you're trying to do, specifically. Perhaps if you were to clarify your specific task we could come up with a solution that Python will permit?

3 Comments

This won't change the actual list object, just the one reference.
@aaronasterling that's right, you'd have to create a new list (or assign to an existing one).
@aaronasterling then he's out of luck I suppose. I want a helicopter too :D
2

Ultimately, what you want to do is incompatible with the way that Python is structured. You have the most elegant way to do it already in the case that your variables are lists but this is not possible with numbers.

This is because variables do not exist in Python. References do. So i.x is not a list, it is a reference to a list. Likewise, if it references a number. So if i.x references y, then i.x = z doesn't actually change the value y, it changes the location in memory that i.x points to.

Most of the time, variables are viewed as boxes that hold a value. The name is on the box. In python, values are fundamental and "variables" are just tags that get hung on a particular value. It's very nice once you get used to it.

In the case of a list, you can use use slice assignment, as you are already doing. This will allow all references to the list to see the changes because you are changing the list object itself. In the case of a number, there is no way to do that because numbers are immutable objects in Python. This makes sense. Five is five and there's not much that you can do to change it. If you know or can determine the name of the attribute, then you can use setattr to modify it but this will not change other references that might already exist.

As Rafe Kettler says, if you can be more specific about what you actually want to do, then we can come up with a simple elegant way to do it.

4 Comments

In my case, I'd actually prefer that any other references to the lists aren't affected. So the setattr method would do the right thing (like Antoine's suggestion), but doesn't have the elegance I'm looking for.
@David Well then setattr is the only way. As you are doing it now with slice assignment, other references will reference the modified list. I agree, it's ugly though. More details about what you're trying to do get's a better answer ;)
My particular application is this: I have a bunch of member variables, each with a list of file paths that might need glob expansion and some other string manipulation. My f() takes just such a list and returns the globbed version. I want this whole set of member variables to go through this process. I suppose I could put them all in their own dict for easy iteration, but this is existing code.
@David, Keeping them in a dictionary would definitely be the correct way to do it. Any other alternative would require you to specifically enumerate which attributes you want changed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.