我创建了一个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)
和add(a, b)
函数的两个参数。
答案 0 :(得分: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和清晰。
答案 1 :(得分:1)
没有办法摆脱这个功能。调用者不能传递要计算的表达式,只能传递要调用的函数。 (另外,*2
甚至不是表达式,它只是表达式的一个片段......)
但是除了def
之外,Python还有很多方法可以构建函数。例如,有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函数的函数式语言,那么您可以将(*) 2
或2 *
作为函数传递,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
内展示如何做到这一点,因为你真的,真的不想这样做。
答案 2 :(得分: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]
感谢帮助人员!
答案 3 :(得分:0)
你想要一个lambda或一个闭包。基本上,您是要传递未命名的函数,还是将状态绑定到函数并将函数传递给状态?
答案 4 :(得分:0)
这样做的一种破坏方法是构造一个笨拙的字符串,如下所示:
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))