0

通常,只有当函数返回的值满足条件时,我才需要使用该值,如以下构造:

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

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

跟进

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

终极和确定的解决方案

尽管这个问题没有投票,但似乎我并不是唯一一个要求这种语言特性的人,事实上最后 Python 3.8 引入了海象运算符,它正好解决了这个需求。使用 Python 3.8+,上面的代码可以很方便地编写为:

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

5 回答 5

2

不,您不能在 if 语句中赋值。您的初始代码很好。

于 2012-12-04T11:01:33.523 回答
1

有效的写法:

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

但是,如果您想使用语句my_func(x)内部的结果,则必须重新计算它,因此您的做法很好。if

于 2012-12-04T11:07:42.010 回答
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)

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

.

诺塔贝内

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

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

.

编辑

顺便说一句,我的最后一个解决方案(带有函数内部的列表)与以下另一个解决方案相距不远:

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
于 2014-02-05T04:47:33.457 回答
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 循环不会运行,如果条件满足,则只运行一次。

然而,这是非常不寻常的,并且可能会使您的代码的潜在读者感到困惑,因此要么避免这样做,要么做好文档。

于 2012-12-04T11:13:45.307 回答
-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

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

当然,您必须记住使用(假设装饰器名称为)来装饰您想要“启用”属性的功能:lastsave_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
于 2012-12-06T15:04:56.800 回答