Python 中的惰性求值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20535342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Lazy evaluation in Python
提问by Vipul
What is lazy evaluation in Python?
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):
在 Python 3.x 中,该range()函数返回一个特殊的范围对象,该对象根据需要计算列表的元素(延迟或延迟评估):
>>> r = range(10)
>>> print(r)
range(0, 10)
>>> print(r[3])
3
What is meant by this?
这是什么意思?
采纳答案by bcorso
The object returned by range()(or xrange()in Python2.x) is known as a lazy iterable.
由range()(或xrange()在 Python2.x 中)返回的对象被称为惰性可迭代对象。
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).
生成器不是将整个范围存储[0,1,2,..,9]在内存中,而是存储定义(i=0; i<10; i+=1)并仅在需要时计算下一个值(也称为延迟评估)。
Essentially, a generator allows you to return a list like structure, but here are some differences:
本质上,生成器允许您返回类似结构的列表,但这里有一些区别:
- A list stores all elements when it is created. A generator generates the next element when it is needed.
- A list can be iterated over as much as you need, a generator can only be iterated over exactlyonce.
- 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:
(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) As a function, using yieldto return the next value:
(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)
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 xone at a time, but the entire list of x/2values will be computed when this list is create.
注意:尽管range(5000000)是 Python3.x 中的生成器,但[x/2 for x in range(5000000)]仍然是一个列表。range(...)完成它的工作并一次生成x一个,但是在x/2创建此列表时将计算整个值列表。
回答by Burhan Khalid
In a nutshell, lazy evaluation means that the object is evaluated when it is needed, not when it is created.
简而言之,惰性求值意味着对象在需要时进行求值,而不是在创建时求值。
In Python 2, range will return a list - this means that if you give it a large number, it will calculate the range and return at the time of creation:
在 Python 2 中,range 将返回一个列表——这意味着如果你给它一个很大的数字,它会计算范围并在创建时返回:
>>> i = range(100)
>>> type(i)
<type 'list'>
In Python 3, however you get a special range object:
但是,在 Python 3 中,您会得到一个特殊的范围对象:
>>> i = range(100)
>>> type(i)
<class 'range'>
Only when you consume it, will it actually be evaluated - in other words, it will only return the numbers in the range when you actually need them.
只有当你使用它时,它才会真正被评估——换句话说,它只会在你真正需要它们时返回范围内的数字。
回答by Vi.Ci
A github repo named python patternsand wikipediatell us what lazy evaluation is.
一个名为python 模式和维基百科的github仓库告诉我们什么是惰性求值。
Delays the eval of an expr until its value is needed and avoids repeated evals.
延迟 expr 的 eval 直到需要它的值并避免重复 evals。
rangein python3 is not a complete lazy evaluation, because it doesn't avoid repeated eval.
range在 python3 中不是一个完整的惰性求值,因为它不能避免重复求值。
A more classic example for lazy evaluation is cached_property:
惰性求值的一个更经典的例子是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
The cached_property(a.k.a lazy_property) is a decorator which convert a func into a lazy evaluation property. The first time property accessed, the func is called to get result and then the value is used the next time you access the property.
cached_property(又名 lazy_property)是一个装饰器,它将 func 转换为惰性求值属性。第一次访问属性时,调用 func 以获取结果,然后在下次访问该属性时使用该值。
eg:
例如:
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)
To use a proper word, a python generator object like rangeare more like designed through call_by_needpattern, rather than lazy evaluation
用一个恰当的词来说,像range这样的 python 生成器对象更像是通过call_by_need模式设计的,而不是惰性求值

