Python 按函数更改字符串值

Python 按函数更改字符串值,python,Python,也许这是个愚蠢的问题,但我注意到我的代码中有很多这样的语句: var = "some_string" var = some_func(var) var = another_func(var) print var # outputs "modified_string" var = "some_string" modify(var, some_func) modify(var, another_func) print var # outputs "modified_string" 这真让我恼火,

也许这是个愚蠢的问题,但我注意到我的代码中有很多这样的语句:

var = "some_string"
var = some_func(var)
var = another_func(var)
print var # outputs "modified_string"
var = "some_string"
modify(var, some_func)
modify(var, another_func)
print var # outputs "modified_string"
这真让我恼火,只是看起来很糟糕(与整个python相反) 如何避免使用,并以如下方式开始使用:

var = "some_string"
var = some_func(var)
var = another_func(var)
print var # outputs "modified_string"
var = "some_string"
modify(var, some_func)
modify(var, another_func)
print var # outputs "modified_string"

提前感谢您

字符串在python中是不可变的,因此您的第二个示例无法工作。在第一个示例中,您将名称
var
绑定到每行的一个全新对象


通常,对单个名称的多个赋值都是一种代码气味。如果您发布了一个更大的代码示例,可能有人会在这里向您展示一个更好的方法?

其他人已经解释了为什么这是不可能的,但是您可以:

for modify in some_func, other_func, yet_another_func:
 var = modify(var)
或者正如pst所说:

var = yet_another_func(other_func(some_func(var)))
事实上,在
functools
中添加了一个
compose
函数。我想我明白他们为什么不。。。但是,嘿,这并不意味着我们不能自己做一个:

def compose(f1, f2):
    def composition(*args, **kwargs):
        return f1(f2(*args, **kwargs))
    return composition

def compose_many(*funcs):
    if len(funcs) == 1:
        return funcs[0]
    if len(funcs) == 2:
        return compose(funcs[0], funcs[1])
    else:
        return compose(funcs[0], compose_many(*funcs[1:]))
测试:

>>> def append_foo(s):
...     return s + ' foo'
... 
>>> def append_bar(s):
...     return s + ' bar'
... 
>>> append_bar(append_foo('my'))
'my foo bar'
>>> compose(append_bar, append_foo)('my')
'my foo bar'
>>> def append_baz(s):
...     return s + ' baz'
... 
>>> compose_many(append_baz, append_bar, append_foo)('my')
'my foo bar baz'

想想看,这可能不是解决你问题的最好办法。但是写起来很有趣。

我只想把这个放在这里(因为似乎没有一个答案能解决这个问题)

如果你通常重复相同的函数序列,考虑把它们封装在一个更高级的函数中:

def metafunc(var):
    var = somefunc(var)
    var = otherfunc(var)
    var = thirdfunc(var)
    return lastfunc(var)
然后,当您调用函数
metafunc
时,您确切地知道您的
var
发生了什么:什么都没有。从函数调用中得到的只是
metafunc
返回的内容。 此外,您可以确定在您忘记的程序部分中没有发生任何事情。这一点非常重要,尤其是在脚本语言中,通常有很多你不知道/不记得的幕后活动

这有优点也有缺点,理论上的讨论属于纯函数式编程的范畴。一些真实世界的交互(如i/o操作)需要非纯函数,因为它们需要超出代码执行范围的真实世界含义。 这里简要地定义了这背后的原则:


问题是
str
int
float
long
,如果您在Py2.x中(True和False实际上是
int
s,所以它们也是))在Python中被称为“不可变类型”。这意味着您不能修改它们的内部状态:
str
(或
int
float
)的所有操作都将导致
str
(或其他)的“新”实例,而旧值将保留在Python的缓存中,直到下一个垃圾回收周期


基本上,你无能为力。抱歉。

有一种方法可以通过在本地符号表中重写来修改不可变变量,但是,我认为这不是很好,应该尽量避免

def updatevar(obj, value, callingLocals=locals()):
    callingLocals[next(k for k, o in callingLocals.items() if o is obj)] = value
另一种方法,甚至不那么pythonic,是将exec与格式化指令一起使用。由于以下原因,它将变量名作为字符串获取:

结果如预期:

var = "some_string"
updatevar(var, "modified_string")
print(var) # outputs "modified_string"
updatevar2(var, var + '2')
print(var) # outputs "modified_string2"

我不认为这是最“pythonic”的做法,但您可以将字符串“包装”到列表中,因为列表在python中是可变的。 例如:

var = "string"
var_wrapper = [var]
现在,您可以将列表传递给函数并访问其唯一的元素,当更改后,它将在外部可见

def change_str(lst):
    lst[0] = lst[0] + " changed!"
您将得到:

>>> change_str(var_wrapper)
>>> var_wrapper[0]
"string changed!"
编辑:

为了使内容更具可读性,您可以进一步创建一个“包装器类”:

现在让我们运行相同的示例:

>>> var = my_str("string")
>>> var.change_str("new string!")
>>> print(var)
new string!

感谢@Error syntacticalreform在我的经验中提到的上课

,最好避免这样的副作用。相反,返回值(如第一个示例中所示)。如果有多个值,它们可能是像元组一样包装的复合类型(然后由调用方分解)。或者,问题可能是“重复作业太多”?考虑:
打印另一个函数(some func(“some字符串”)
x=func(x)看起来比
修改(x,func)
更糟糕吗?我100%清楚第一个例子应该做什么,0%清楚第二个例子应该做什么。@Chris Lutz,我不确定这是重复的。字面上的问题是“如何通过引用传递变量”,但真正的问题是“如何避免重复为同一个变量名分配新值”。这实际上是一个有趣而有价值的问题。@senderle-我想类似
x=chain_funcs(func1,func2,…,x)
的问题会比较好。不过这会让调用的顺序有点模棱两可。我完全同意pst——一般来说,最好坚持只做一件事的函数,并把它们做好。如果你想经常重复相同的函数序列,而不希望有重复的代码,考虑把你常用的函数序列封装在它们自己的高级函数中,其唯一的目的是调用这些低级函数。我保证,从长远来看,这种做法会对你有所帮助。哇!我真的设计过度了。除了有一个简单得多的递归解决方案外,甚至还有一个单行程序<代码>lambda lst:reduce(lambda x,y:lambda*args,**kwargs:x(y(*args,**kwargs)),lst)。它不漂亮,但很管用;有关使用
functional
的lambda免费版本,请参阅。这还不错,但这也可能暗示您可能希望实现一个类。(仅供未来阅读此问答的人使用)。@错误语法自责你完全正确!我想知道是否要在编辑中添加它。现在我想我会的…一个完整的实现并不是真的需要,但最后的一个小提示(或简短的例子)可能是有用的。