1

我创建了一个 python 脚本,它可以根据指定的阶跃函数循环一系列值。

#!/usr/bin/python

def mul(value, step): return value * step
def inc(value, step): return value + step
def step_range(start, end, step, func):
    while start <= end:
        yield start
        start = func(start, step)

def main():
    for x in step_range(1, 64, 2, mul): 
        print '%d, '%(x),
    print
    for x in step_range(0, 64, 8, inc): 
        print '%d, '%(x),

if __name__ == '__main__':
    main()

输出:

$ python test.py
1,  2,  4,  8,  16,  32,  64,
0,  8,  16,  24,  32,  40,  48,  56,  64,

无论如何我可以摆脱辅助功能,以便用户可以做这样的事情吗?

for x in step_range(1, 64, *2): 
    ...

def step_range(start, end, step):
    while start <= end:
        yield start
        start = start ?step?

我被难住的?标记......我查看了operator模块,但我必须知道mul(a, b)andadd(a, b)函数的两个参数。

4

5 回答 5

4

一个更清晰的方法可能是

def step_range(start, end, func):
    while start <= end:
        yield start
        start = func(start)

然后例如,你可以做

[a for a in step_range(1, 10, lambda x: x * 2)] # [1, 2, 4, 8]

这样,您就不仅限于乘法或加法。当您阅读它时,它也更加 Pythonic 和清晰。

于 2013-10-04T01:04:52.077 回答
1

我进口operator了,我相信我想出了一个很好的解决方案:

我保持原来step_range()的功能完好无损,我摆脱了帮手。我还添加了在递减值的情况下修改条件的功能。

#!/usr/bin/python

import operator

def step_range(start, end, step, step_func, compare_func):
    while compare_func(start, end):
        yield start
        start = step_func(start, step)

def main():
    print [x for x in step_range(1, 64, 2, operator.mul, operator.le)]
    print [x for x in step_range(64, 0, 2, operator.div, operator.gt)]
    print [x for x in step_range(0, 64, 8, operator.add, operator.le)]
    print [x for x in step_range(64, 0, 8, operator.sub, operator.ge)]

if __name__ == '__main__':
    main()

输出:

$ python test.py
[1, 2, 4, 8, 16, 32, 64]
[64, 32, 16, 8, 4, 2, 1]
[0, 8, 16, 24, 32, 40, 48, 56, 64]
[64, 56, 48, 40, 32, 24, 16, 8, 0]

谢谢你们的帮助!

于 2013-10-04T01:33:28.337 回答
1

没有办法摆脱这个功能。调用者不能传递要评估的表达式,只能传递要调用的函数。(另外,*2它甚至不是一个表达式,它只是一个表达式的片段……)


但是除了def. 例如,有lambda, 和高阶函数,例如partial

>>> for x in step_range(1, 64, lambda x: x*2):
...     pass
>>> from functools import partial
>>> from operator import mul
>>> for x in step_range(1, 64, partial(mul, 2): 
...     pass

但这取决于调用者,而不是被调用者。

(如果您习惯于 Haskell 和某些其他使用 curried 函数的函数式语言,那么您可以只传递(*) 22 *作为函数,partial这是您手动执行的方式,operator.mul相当于(*).)


如果这还不够好,您可以通过构建(或搜索和安装)“表达式树库”来创建“快速 lambdas”。然后你可以写这样的代码:

>>> for x in step_range(1, 64, _1 * 2):
...     pass

或者您可以使用宏处理器,例如MacroPy.


如果你真的,真的想要(你真的,真的不想,只是为了完整性……),你可以用一个表达式片段的字符串表示,完成它,然后eval在正确的上下文中完成它:

>>> for x in step_range(1, 64, "*2"):
...     pass

但我不会在里面展示如何做到这一点step_range,因为你真的,真的不想。

于 2013-10-04T01:16:02.060 回答
0

一个 hackish 的方法是构造一个尴尬的字符串,如下所示:

import operator

functions = {"*": operator.mul,
             "+": operator.add}

def step_range(start, end, step_string):
    """The function generates all the elements from start to end by
    successively applying the step_string.

    start and end are integers
    step_string is a string formatted like this:
    - the first character is either "+" or "*"
    - the rest of the string forms a number

    Some doctests:

    >>> [x for x in step_range(1, 64, "*2")]
    [1, 2, 4, 8, 16, 32, 64]

    >>> [x for x in step_range(0, 64, "+8")]
    [0, 8, 16, 24, 32, 40, 48, 56, 64]

    """
    func_sign, param = step_string[0], step_string[1:]

    func = functions[func_sign]


    while start <= end:
        yield start
        start = func(start, int(param))
于 2013-10-04T01:20:50.373 回答
0

你要么想要一个 lambda,要么想要一个闭包。基本上,您是想传递一个未命名的函数,还是将状态绑定到一个函数并传递带有状态的函数?

于 2013-10-04T01:10:44.177 回答