Python: modify strings stored in various objects inplace in a loop
I have strings stored in various objects, for example a, b, c[2:7] (ie 5 different strings c[2],...c[6]), d.s, e.s[:] (ie all strings stored in the e.s list). I need to loop over all these strings on various places in the code and mo开发者_运维技巧dify these variables in the loops. (Assigning the modified strings to new variables would not work as there are other functions expecting the modified strings in the original variables.) How can I do that efficiently in Python?
If I could create a list of references to the strings then I could just always iterate over it:
str_ref_lst=[reference(a), reference(b), reference(d.s)]
str_ref_lst.extend[reference(c[2:7])]
str_ref_lst.extend[reference(e.s[:])]
...
for ref_strng in str_ref_lst:
do_string_modifications1(dereference(ref_strng))
...
function_using_the_modified_variables1()
...
for ref_strng in str_ref_lst:
do_string_modifications2(dereference(ref_strng))
...
function_using_the_modified_variables2()
etc
However, I am not aware of reference()/dereference() analogues in Python (and I guess it would not be the right way in Python anyway)
The recommended answer should be "use a dictionary", but if you have to do it that way:
class cls(object):
pass
a = "<a>"
b = "<b>"
c = ["", "", "<c>"]
d = cls()
d.s = "<d.s>"
e = cls()
e.s = "<e.s>"
var_list = "a b c[2:7] d.s e.s".split()
for var in var_list:
exec "%s+='Mod'" % var # Modify the variables
print a,b,c,d.s,e.s
# >>> <a>Mod <b>Mod ['', '', '<c>', 'M', 'o', 'd'] <d.s>Mod <e.s>Mod
IIRC this way doesn't work in Python 3.0 because of internal optimizations
With slices, it should be somewhat like
import re
class cls(object):
pass
def fn(var): # function to apply to the strings
return "[%s mod]" % var
a = "<a>"
b = "<b>"
c = "01234567890"
d = cls()
d.s = "<d.s>"
e = cls()
e.s = "<e.s>"
var_list = "a b c[2:7] d.s e.s".split()
for var in var_list:
# Modify the variables
try:
# exec "%s='Hi there'" % var # Modify the variables
exec "%(var)s=fn(%(var)s)" % { "var": var }
except TypeError:
# Assume Slice...
slice_ = re.findall("\[(\d+)\:(\d+)\]", var)[0] # Get slice
var_with_slice = var
var = var.split("[")[0] # Remove slice
# Look ma, I can code in Perl too! :)
line = \
"%(var)s=%(var)s[:%(slice1)s]+fn(%(var_with_slice)s)+%(var)s[%(slice2)s+1:]" % \
{ "var": var, "var_with_slice": var_with_slice, "slice1": slice_[0], "slice2": slice_[1] }
# somewhat like c = c[:2] + fn(c[2:7]) + c[7+1:]
exec line
print a,b,c,d.s,e.s
# >>> [<a> mod] [<b> mod] 01[23456 mod]890 [<d.s> mod] [<e.s> mod]
Your do_string_modifications
functions need to be changed so that they return the new string value instead of attempting to modify it in place (since that is not possible). Use your new functions to modify the list, and reassign the original string references to the new values in the list after the modification (if necessary):
str_lst = [a, b, d.s, c[2:7], e.s]
str_lst = [do_string_modifications1(x) for x in str_lst]
str_lst = [do_string_modifications2(x) for x in str_lst]
a, b, d.s, c[2:7], e.s = str_lst
You could do something like this.
def stringMod(inStr):
return inStr.replace('f', 'g')
str_list = map(stringMod, str_list)
It is not possible in the generality that you want. The biggest hurdle are the slice operations you gave, c[2:7]
and e.s[:]
. These expressions are no lvalues, you cannot assign to them. They just produce new string values, which you have to capture or they are gone.
If you just had lvalues (a, b, d.s), expressions you can assign to, you could think of something, but with c[2:7] and e.s[:], it is not possible.
精彩评论