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)add(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

関数を取り除く方法はありません。呼び出し元は、評価される式を渡すことはできず、呼び出される関数のみを渡すことができます。(しかも*2表情じゃなくて、表情の断片に過ぎない…)


しかし、Python には 以外にも関数を作成する方法がたくさんあります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 や、カリー化された関数を使用する他の特定の関数型言語に慣れている場合は、(*) 2or2 *を関数として渡すことができます。partialこれは手動で行う方法であり、 とoperator.mul同等です(*)。)


これで十分でない場合は、「式ツリー ライブラリ」を構築 (または検索してインストール) することにより、「クイック ラムダ」を作成できます。次に、次のようなコードを記述できます。

>>> 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 に答える
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 に答える
0

ラムダまたはクロージャーのいずれかが必要です。基本的に、名前のない関数を渡しますか、それとも状態を関数にバインドし、関数に状態を渡しますか?

于 2013-10-04T01:10:44.177 に答える
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))
于 2013-10-04T01:20:50.373 に答える