14

純粋な 関数、数学関数に似た関数であり、「実世界」との相互作用も副作用もありません。より実用的な観点からは、純粋な関数では次のことができないことを意味します。

  • メッセージを印刷または表示する
  • ランダムにする
  • システム時刻に依存
  • グローバル変数を変更する
  • その他

このすべての制限により、非純粋関数よりも純粋関数について推論する方が簡単になります。プログラムのバグが少なくなるように、大部分の関数を純粋にする必要があります。

Haskell のような巨大な型システムを持つ言語では、読者は関数が純粋かどうかを最初からすぐに知ることができるため、後続の読み取りが容易になります。

@purePython では、この情報は、関数の上に置かれたデコレーターによってエミュレートされる場合があります。また、そのデコレーターが実際に検証作業を行うことも望んでいます。私の問題は、そのようなデコレータの実装にあります。

今のところ、関数のソース コードを調べて、または、または、およびそれらのいずれかが見つかった場合に不平を言うなどの流行語をglobal探しrandomますprint

import inspect

def pure(function):
    source = inspect.getsource(function)
    for non_pure_indicator in ('random', 'time', 'input', 'print', 'global'):
        if non_pure_indicator in source:
            raise ValueError("The function {} is not pure as it uses `{}`".format(
                function.__name__, non_pure_indicator))
    return function

しかし、あなたの運次第でうまくいくかもしれないし、うまくいかないかもしれない奇妙なハックのように感じます。より良いデコレータを書くのを手伝ってくれませんか?

4

2 に答える 2

12

どこから来たのかはわかりますが、これはうまくいかないと思います。簡単な例を見てみましょう:

def add(a,b):
    return a + b

したがって、これはおそらく「純粋」に見えます。しかし、Python では、+here は、呼び出されたときに有効なバインディングに応じて、何でもできる任意の関数です。そのため、a + b任意の副作用が発生する可能性があります。

しかし、それはさらに悪いことです。これが標準の整数+を処理しているだけだとしても、さらに「不純な」処理が行われています。

+が新しいオブジェクトを作成しています。呼び出し元だけがその新しいオブジェクトへの参照を持っていると確信している場合は、これを純粋な関数と考えることができます。しかし、そのオブジェクトの作成プロセス中に、そのオブジェクトへの参照が漏れていないことを確認することはできません。

例えば:

class RegisteredNumber(int):

    numbers = []

    def __new__(cls,*args,**kwargs):
        self = int.__new__(cls,*args,**kwargs)
        self.numbers.append(self)
        return self

    def __add__(self,other):
        return RegisteredNumber(super().__add__(other))

c = RegisteredNumber(1) + 2

print(RegisteredNumber.numbers)

これは、おそらく純粋な add 関数が実際にRegisteredNumberクラスの状態を変更したことを示しています。これはばかげて考案された例ではありません: 私の製品コード ベースには、作成された各インスタンスを追跡するクラスがあります。たとえば、キーを介したアクセスを許可します。

純度の概念は、Python ではあまり意味がありません。

于 2015-07-27T22:02:48.837 に答える
1

(答えではありませんが、コメントするには長すぎます)

関数が同じ引数のセットに対して異なる値を返すことができる場合、それは純粋ではありませんか?

Python の関数はオブジェクトであるため、オブジェクトの純度を確認する必要があることを思い出してください...

次の例を見てください。

def foo(x):
    ret, foo.x = x*x+foo.x, foo.x+1
    return ret
foo.x=0

繰り返し呼び出すとfoo(3)、次のようになります。

>>> foo(3)
9

>>> foo(3)
10

>>> foo(3)
11

...

globalさらに、グローバルを読み取るために、ステートメントやglobal()関数内の組み込みを使用する必要はありません。グローバル変数は別の場所で変更される可能性があり、関数の純度に影響を与えます。

上記のすべての状況は、実行時に検出するのが難しい場合があります。

于 2015-07-22T17:13:28.170 に答える