web-dev-qa-db-ja.com

Pythonの遅延評価

Pythonの遅延評価とは何ですか?

1つのウェブサイトは言った:

Python 3.x range()関数は、オンデマンドでリストの要素を計算する特別な範囲オブジェクトを返します(遅延評価または遅延評価):

>>> r = range(10)
>>> print(r)
range(0, 10)
>>> print(r[3])
3

これはどういう意味ですか?

42
Vipul

range()(またはPython2.xのxrange())によって返されるオブジェクトは、 generator として知られています。

ジェネレータは、_[0,1,2,..,9]_の範囲全体をメモリに保存する代わりに、_(i=0; i<10; i+=1)_の定義を保存し、必要な場合にのみ次の値を計算します(レイジー評価)。

基本的に、ジェネレーターを使用すると、構造のようなリストを返すことができますが、いくつかの違いがあります。

  1. リストには、作成時にすべての要素が保存されます。ジェネレーターは、必要なときに次の要素を生成します。
  2. リストは必要なだけ繰り返すことができ、ジェネレーターはexactlyを1回だけ繰り返すことができます。
  3. リストはインデックスによって要素を取得できますが、ジェネレータは取得できません-値を最初から最後まで一度だけ生成します。

ジェネレータは次の2つの方法で作成できます:

(1)リスト理解に非常に似ています:

_# this is a list, create all 5000000 x/2 values immediately, uses []
lis = [x/2 for x in range(5000000)]

# this is a generator, creates each x/2 value only when it is needed, uses ()
gen = (x/2 for x in range(5000000)) 
_

(2)関数として、yieldを使用して次の値を返します。

_# this is also a generator, it will run until a yield occurs, and return that result.
# on the next call it picks up where it left off and continues until a yield occurs...
def divby2(n):
    num = 0
    while num < n:
        yield num/2
        num += 1

# same as (x/2 for x in range(5000000))
print divby2(5000000)
_

注:range(5000000)はPython3.xのジェネレータですが、[x/2 for x in range(5000000)]はまだリストです。 range(...)は仕事をしてxを一度に1つずつ生成しますが、このリストが作成されると_x/2_値のリスト全体が計算されます。

62
bcorso

簡単に言えば、遅延評価とは、オブジェクトが作成されたときではなく、必要なときにオブジェクトが評価されることを意味します。

Python 2、範囲はリストを返します-これは、大きな数値を指定すると、範囲を計算して作成時に戻ることを意味します:

>>> i = range(100)
>>> type(i)
<type 'list'>

Python 3、ただし、特別な範囲オブジェクトを取得します:

>>> i = range(100)
>>> type(i)
<class 'range'>

消費した場合のみ、実際に評価されます。つまり、実際に必要な場合にのみ範囲内の数値を返します。

13
Burhan Khalid

python patterns および wikipedia という名前のgithubリポジトリは、遅延評価とは何かを教えてくれます。

値が必要になるまでexprのevalを遅らせ、evalの繰り返しを回避します。

python3のrangeは、評価の繰り返しを回避しないため、完全な遅延評価ではありません。

遅延評価のより典型的な例はcached_property

import functools

class cached_property(object):
    def __init__(self, function):
        self.function = function
        functools.update_wrapper(self, function)

    def __get__(self, obj, type_):
        if obj is None:
            return self
        val = self.function(obj)
        obj.__dict__[self.function.__name__] = val
        return val

Cached_property(a.k.a lazy_property)は、funcを遅延評価プロパティに変換するデコレーターです。プロパティに最初にアクセスすると、関数を呼び出して結果を取得し、次にプロパティにアクセスしたときに値が使用されます。

例えば:

class LogHandler:
    def __init__(self, file_path):
        self.file_path = file_path

    @cached_property
    def load_log_file(self):
        with open(self.file_path) as f:
            # the file is to big that I have to cost 2s to read all file
            return f.read()

log_handler = LogHandler('./sys.log')
# only the first time call will cost 2s.
print(log_handler.load_log_file)
# return value is cached to the log_handler obj.
print(log_handler.load_log_file)

適切なWordを使用するには、pythonrangeのようなジェネレーターオブジェクトはcall_by_needパターンではなく、遅延評価

2
Vi.Ci