如何避免定义变量来保存可能只需要一次的函数结果

时间:2012-12-04 11:00:20

标签: python binding decorator python-decorators

通常我只需要使用函数返回的值,如果这样的值满足条件,就像在这个结构中一样:

tmp = my_func(x)
if tmp == some_value:
    # do something with tmp

我想通过避免使用新变量tmp来使这段代码更简洁和可读,类似于这种方式:

if my_func(x) == some_value:
    # do something with my_func(x) last return

另一个例子可能是:

tmp = initialization_value
while tmp != some_value:
    tmp = my_func(x)
    # do something with tmp
    # change value of x

将更加简洁和可读

while my_func(x) != some_value:
    # do something with my_func(x) last return
    # change value of x

是否有可能获得或实施这种编码风格?

关注

在我看来,获取它的最佳方法是通过装饰器缓存最后返回的vaue,请参阅下面的答案。

5 个答案:

答案 0 :(得分:2)

不,你不能assign in an if statement。你的初始代码很好。

答案 1 :(得分:1)

写下来是有效的:

if my_func(x) == some_value:
    # do something 
    return something

但是,如果您想在my_func(x)语句if语句中使用{{1}}的结果,那么您可以这样做。

答案 2 :(得分:1)

您的解决方案是:

def save_last(f):
    def w(*args, **kwargs): # w is the 'wrapper' function
        w.last=f(*args, **kwargs)
        return w.last
    return w

@save_last
def fync(x): # just an example function
    if 1<x<100: return (x%15 + x//6)*(x%2)
    else: return (x%10)*10 + (x%7)
print 'fync.__dict__ :',fync.__dict__

for i in xrange(1,114):
    if fync(i)%7==3:
        print 'fync(%3d)==%2d   %2d-3==%2d==7*%d' \
              % (i,fync.last,fync.last,
                 fync.last-3,(fync.last-3)//7)
print 'fync.__dict__ :',fync.__dict__

结果

fync.__dict__ : {}
fync(  3)== 3    3-3== 0==7*0
fync(  9)==10   10-3== 7==7*1
fync( 35)==10   10-3== 7==7*1
fync( 41)==17   17-3==14==7*2
fync( 79)==17   17-3==14==7*2
fync( 85)==24   24-3==21==7*3
fync(102)==24   24-3==21==7*3
fync(109)==94   94-3==91==7*13
fync(113)==31   31-3==28==7*4
fync.__dict__ : {'last': 31}

我发现装饰器的使用方式很重,而且可以这样做:

def finc(x):
    if 1<x<100: finc.last = (x%15 + x//6)*(x%2)
    else: finc.last = (x%10)*10 + (x%7)
    return finc.last
print 'finc.__dict__ :',finc.__dict__

for i in xrange(1,114):
    if finc(i)%7==3:
        print 'finc(%3d)==%2d   %2d-3==%2d==7*%d' \
              % (i,finc.last, finc.last,
                 finc.last-3,(finc.last-3)//7) 
print 'finc.__dict__ :',finc.__dict__ 

结果完全一样。

顺便说一下,我想象了以下解决方案:

def func(x=None,li=[None]):
    if x is None: return li[0]
    elif x>0:
        if 1<x<100:  li[0] = (x%15 + x//6)*(x%2)
        else: li[0] = (x%10)*10 + (x%7)
        return li[0]

for i in xrange(1,114):
    if func(i)%7==3:
        print 'func(%3d)==%2d   %2d-3==%2d==7*%d' \
              % (i,func(),func(),
                 func()-3,(func()-3)/7)

结果显然是一样的 但我更喜欢上面的解决方案,使用一个不使用装饰器的属性。

Nota Bene

所有三种解决方案的原理是相同的:在返回函数之前,将结果存储在属性或默认参数列表中的函数中。

将名称的创建从函数外部移动到函数内部:
无论如何,有一个对象存储结果somwhere,属性或列表,因此还有一个专用名称来保持对存储对象的访问。
这只是解决问题。

修改

顺便说一句,我的最后一个解决方案,包含该函数的内部列表,并不是以下另一个解决方案:

L = []

def fonc(x,li=L):
    if 1<x<100:  li[:] = [(x%15 + x//6)*(x%2)]
    else: li[:] = [(x%10)*10 + (x%7)]
    return li[0]

for i in xrange(1,114):
    if fonc(i)%7==3:
        print 'func(%3d)==%2d   %2d-3==%2d==7*%d' \
              % (i,L[0],L[0],
                 L[0]-3,(L[0]-3)/7)

但是这个解决方案几乎等同于你在问题中所写的内容:由于绑定到tmp标识符或将结果保持为列表元素而保留函数的结果不会产生很多不同。

所以我仍然是第一个看法,你的问题是一个错误的问题:

  • 要么你需要做一些函数的结果,你必须把它作为一个名称引用的对象,在函数内部或外部

  • 或者您不必对函数的结果执行某些操作,然后您只需编写:

if my_func(x) == some_value:
    # do nothing with my_func(x)
    return some_value

答案 3 :(得分:0)

如果您经常使用此构造,则可以执行

def cmp_iter(a, b):
    if a == b:
        yield a
# general case:
def if_iter(a, b, testfunc):
    if testfunc(a, b):
        yield a

为了做到

for tmp in cmp_iter(my_func(x), some_value):
    frobnicate(tmp)
    return tmp

如果条件未满足,则此for循环不会运行,如果满足条件,则仅运行一次。

然而,这很不寻常,可能会使您的代码的潜在读者感到困惑,所以要么不要这样做,要么做一个很好的文档。

答案 4 :(得分:-1)

我找到了一个简洁的解决方案(欢迎更好的解决方案)使用装饰器,它保存装饰函数在last属性中返回的最后一个值。我的构造变成:

if my_func(x) == some_value:
    # do anything with the value returned by my_func, saved in my_func.last
    # such as
    print my_func.last
    return my_func.last

简洁明了。该函数仅评估一次,您不需要引入恼人的临时变量。

当然,您必须记住使用(假设装饰器名称为last)来装饰您想要“启用save_last属性的函数:

@save_last
def my_func(...):
    # function definition

装饰器定义为:

# last value returned by decorated function is accessible as 'last' attribute
def save_last(f):
    def w(*args, **kwargs): # w is the 'wrapper' function
        w.last=f(*args, **kwargs)
        return w.last
    return w