2011-06-17 83 views
3

也许一个愚蠢的问题,但我发现我的代码中有许多语句是这样的:更改字符串值

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" 

预先感谢您

+3

以我的经验,最好是避免这样的副作用。而是返回值(如第一个示例中所示)。如果有多个值,它们可能会像Tuple一样包装复合类型(然后由调用者分解)。另外,也许问题是“太多重复任务”?考虑:'print another_func(some_func(“some_string”))' – 2011-06-17 23:36:52

+0

[Python:我如何通过引用传递变量?](http://stackoverflow.com/questions/986006/python-how-do- i-pass-a-by-reference) –

+3

'x = func(x)'看起来比'modify(x,func)'糟糕吗?我完全清楚第一个例子应该做什么,0%清楚第二个应该做什么。 –

回答

0

字符串是Python中不变的,所以你的第二个实例C不工作。在第一个示例中,您将名称var绑定到每行上的全新对象。

通常情况下,多个赋值给像这样的单个名称是代码异味。也许如果你发布了一个更大的代码示例,在这里可以给你更好的方法?

1

别人已经解释了为什么这是不可能的,但你可以:

for modify in some_func, other_func, yet_another_func: 
var = modify(var) 

或PST说:

var = yet_another_func(other_func(some_func(var))) 
2

事实上,一直at least one attemptcompose功能添加到functools。我想我明白他们为什么没有......但是,嘿,这并不意味着我们不能让一个自己:

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' 

试想想它,这可能不是解决您问题的最佳方案。但写起来很有趣。

+0

+1“好玩写”:-) – kindall

+0

哇!我真的过度设计了那个。除了有一个简单得多的递归解决方案之外,甚至还有一个单线程! lambda lst:reduce(lambda x,y:lambda * args,** kwargs:x(y(* args,** kwargs)),lst)'。它不漂亮,但它的工作原理;请参阅[这里](http://www.amk.ca/python/writing/functional#the-functional-module)了解使用'functional'的lambda-free版本。 – senderle

-1

我只是要去把这个权利在这里(因为没有一个答案似乎已经解决了它尚未)

如果你经常重复的功能相同的序列,考虑更高层次的功能,它们包裹:

def metafunc(var): 
    var = somefunc(var) 
    var = otherfunc(var) 
    var = thirdfunc(var) 
    return lastfunc(var) 

然后当你调用该函数metafunc你确切地知道发生了什么你var:没有。所有你从函数调用中得到的是metafunc返回的值。 此外,您可以确定在您忘记的程序的某些部分中没有发生任何事情。这是非常重要的,尤其是在脚本语言中,通常有很多事情在幕后发生,你不知道是不是知道/记住。

这样做有好处和缺点,理论讨论在纯函数式编程的范畴之内。一些真实世界的交互(如I/O操作)需要非纯函数,因为它们需要超出代码执行范围的实际意义。 这背后的原理是指这里简要:

http://en.wikipedia.org/wiki/Functional_programming#Pure_functions

4

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

基本上没有什么可以做的。抱歉。

0

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

​​

另一种方式,甚至更少pythonic,是使用exec格式化指令。它得到的变量名的字符串感谢this solution为:不出所料

def getname(obj, callingLocals=locals()): 
    """ 
    a quick function to print the name of input and value. 
    If not for the default-Valued callingLocals, the function would  always 
    get the name as "obj", which is not what I want. 
    """ 
    return next(k for k, v in callingLocals.items() if v is obj) 

def updatevar2(k, v, callingLocals=locals()): 
    n = getname(k, callingLocals) 
    exec('global {};{}={}'.format(n, n, repr(v))) 

结果:

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