Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy evaluation in Python

What is lazy evaluation in Python?

One website said :

In Python 3.x the range() function returns a special range object which computes elements of the list on demand (lazy or deferred evaluation):

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

What is meant by this?

like image 902
Vipul Avatar asked Dec 12 '13 04:12

Vipul


People also ask

What is lazy evaluation example?

Lazy evaluation is an evaluation strategy which holds the evaluation of an expression until its value is needed. It avoids repeated evaluation. Haskell is a good example of such a functional programming language whose fundamentals are based on Lazy Evaluation.

Does Python support lazy evaluation?

Yes, Python evaluates boolean conditions lazily. The docs say, The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.

What is lazy property in Python?

It is a property decorator that gets out of the way after the first call. It allows you to auto-cache a computed value. The standard library @property decorator is a data descriptor object and is always called, even if there is an attribute on the instance of the same name.

How do you make a lazy function in Python?

Solution 2: Use the '__getattr__' Special Method In Python, functions that have double underscores before and after their names are called special or magic methods. Some people also call them dunder (i.e., double underscores) methods. One particular special method — __getattr__ — can help us implement lazy attributes.


1 Answers

The object returned by range() (or xrange() in Python2.x) is known as a lazy iterable.

Instead of storing the entire range, [0,1,2,..,9], in memory, the generator stores a definition for (i=0; i<10; i+=1) and computes the next value only when needed (AKA lazy-evaluation).

Essentially, a generator allows you to return a list like structure, but here are some differences:

  1. A list stores all elements when it is created. A generator generates the next element when it is needed.
  2. A list can be iterated over as much as you need, a generator can only be iterated over exactly once.
  3. A list can get elements by index, a generator cannot -- it only generates values once, from start to end.

A generator can be created in two ways:

(1) Very similar to a list comprehension:

# 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) As a function, using yield to return the next value:

# 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) 

Note: Even though range(5000000) is a generator in Python3.x, [x/2 for x in range(5000000)] is still a list. range(...) does it's job and generates x one at a time, but the entire list of x/2 values will be computed when this list is create.

like image 90
bcorso Avatar answered Sep 17 '22 14:09

bcorso