From this link: How do I pass a variable by reference?, we know, Python will copy a string (an immutable type variable) when it is passed to a function as a parameter, but I think it will waste memory if the string is huge. In many cases, we need to use functions to wrap some operations for strings, so I want to know how to do it more effective?
-
I'm not sure what you're asking here ... do you have some code that demonstrates a problem that you're encountering? – g.d.d.c Nov 28 '12 at 15:46
-
1> we know, Python will copy a string (an immutable type variable) when it is passed to a function as a parameter You most certainly do not know this! Python never implicitly copies anything. – Mike Graham Nov 28 '12 at 16:02
7 Answers
Python does not make copies of objects (this includes strings) passed to functions:
>>> def foo(s):
... return id(s)
...
>>> x = 'blah'
>>> id(x) == foo(x)
True
If you need to "modify" a string in a function, return the new string and assign it back to the original name:
>>> def bar(s):
... return s + '!'
...
>>> x = 'blah'
>>> x = bar(x)
>>> x
'blah!'
Unfortunately, this can be very inefficient when making small changes to large strings because the large string gets copied. The pythonic way of dealing with this is to hold strings in an list and join them together once you have all the pieces.

- 44,786
- 9
- 89
- 119
-
1Python never passes by reference. It passes references, but "pass by reference" is already taken for another argument passing style (one which permits, for example, the function `swap(a, b)`). – Nov 28 '12 at 15:48
-
1@delnan: Point taken. Whatever you call it, Python does not make copies of the object referred to by names when they are assigned to arguments. – Steven Rumbalski Nov 28 '12 at 15:52
-
1Absolutely. It's just the terminology which is problematic. Same goes for other cases of assignment, and for other objects, so you might want to generalize your answer. – Nov 28 '12 at 15:56
-
1@delnan -- Perhaps I'm not a per CS type guy, but you'll often see people in C write a function `swap(&a, &b)` and refer to that as pass by reference. However, that's very similar to what you're actually doing in python. You can pass an object in and change the object in the function, but you can't change where the "pointer" points. The only difference is that python has immutable objects, so you're not allowed to change the object that the "pointer" references for immutable objects. Anyway, I'm never clear on what to call it (for python or for C). – mgilson Nov 28 '12 at 15:59
-
Sorry, I take back my former comment. I didn't read OP's post very clearly. I should get more sleep. Great answer (+1) – mgilson Nov 28 '12 at 16:02
-
1@mgilson I agree that that's pass by reference, in that it achieves the same thing (I'm only concerned with semantics here). The difference is, C has pointers to everything, so you can pass a pointer to (for example) a local variable or a struct member. In Python, there's no such thing - every variable, member, collection item, etc. is a "reference" and you can't have a "reference to a reference", so you effectively can't do what pass-by-reference (be it built into the language, or emulated by C-style pointers) can do. – Nov 28 '12 at 16:02
Python does pass a string by reference. Notice that two strings with the same content are considered identical:
a = 'hello'
b = 'hello'
a is b # True
Since when b is assigned by a value, and the value already exists in memory, it uses the same reference of the string. Notice another fact, that if the string was dynamically created, meaning being created with string operations (i.e concatenation), the new variable will reference a new instance of the same string:
c = 'hello'
d = 'he'
d += 'llo'
c is d # False
That being said, creating a new string will allocate a new string in memory and returning a reference for the new string, but using a currently created string will reuse the same string instance. Therefore, passing a string as a function parameter will pass it by reference, or in other words, will pass the address in memory of the string.
And now to the point you were looking for- if you change the string inside the function, the string outside of the function will remain the same, and that stems from string immutability. Changing a string means allocating a new string in memory.
a = 'a'
b = a # b will hold a reference to string a
a += 'a'
a is b # False
Bottom line:
You cannot really change a string. The same as for maybe every other programming language (but don't quote me). When you pass the string as an argument, you pass a reference. When you change it's value, you change the variable to point to another place in memory. But when you change a variable's reference, other variables that points to the same address will naturally keep the old value (reference) they held. Wish the explanation was clear enough

- 975
- 2
- 13
- 31
In [7]: strs="abcd"
In [8]: id(strs)
Out[8]: 164698208
In [9]: def func(x):
print id(x)
x=x.lower() #perform some operation on string object, it returns a new object
print id(x)
...:
In [10]: func(strs)
164698208 # same as strs, i.e it actually passes the same object
164679776 # new object is returned if we perform an operation
# That's why they are called immutable
But operations on strings always return a new string object.

- 244,495
- 58
- 464
- 504
If you want to potentially change the value of something passed in, wrap it in a dict or a list:
This doesn't change s
def x(s):
s += 1
This does change s:
def x(s):
s[0] += 1
This is the only way to "pass by reference".

- 11,620
- 5
- 64
- 44
def modify_string( t ):
the_string = t[0]
# do stuff
modify_string( ["my very long string"] )

- 32,471
- 48
- 110
- 179
wrapping the string into a class will make it pass by reference:
class refstr:
"wrap string in object, so it is passed by reference rather than by value"
def __init__(self,s=""):
self.s=s
def __add__(self,s):
self.s+=s
return self
def __str__(self):
return self.s
def fn(s):
s+=" world"
s=refstr("hello")
fn(s) # s gets modified because objects are passed by reference
print(s) #returns 'hello world'

- 49
- 1
Just pass it in as you would any other parameter. The contents won't get copied, only the reference will.

- 486,780
- 108
- 951
- 1,012