Vip*_*pul 43 python lazy-evaluation python-3.x
什么是Python中的懒惰评估?
一个网站说:
在Python 3.x中,range()函数返回一个特殊的范围对象,它根据需要计算列表的元素(延迟或延迟评估):
>>> r = range(10)
>>> print(r)
range(0, 10)
>>> print(r[3])
3
Run Code Online (Sandbox Code Playgroud)
这是什么意思?
bco*_*rso 65
range()(或xrange()在Python2.x中)返回的对象称为生成器.
生成器不是在整个[0,1,2,..,9]存储器中存储整个范围,而是(i=0; i<10; i+=1)仅在需要时存储定义并计算下一个值(AKA惰性评估).
从本质上讲,生成器允许您返回类似结构的列表,但这里有一些差异:
可以通过两种方式创建生成器:
(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))
Run Code Online (Sandbox Code Playgroud)
(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)
Run Code Online (Sandbox Code Playgroud)
注意:即使range(5000000)是Python3.x中的生成器,[x/2 for x in range(5000000)]仍然是一个列表.range(...)做它的工作并一次生成x一个,但是在x/2创建此列表时将计算整个值列表.
Bur*_*lid 14
简而言之,延迟评估意味着在需要时评估对象,而不是在创建对象时评估对象.
在Python 2中,range将返回一个列表 - 这意味着如果你给它一个大数字,它将计算范围并在创建时返回:
>>> i = range(100)
>>> type(i)
<type 'list'>
Run Code Online (Sandbox Code Playgroud)
但是在Python 3中,您将获得一个特殊的范围对象:
>>> i = range(100)
>>> type(i)
<class 'range'>
Run Code Online (Sandbox Code Playgroud)
只有当你消费它时,它才会被实际评估 - 换句话说,它只会在你真正需要它时返回范围内的数字.
小智 8
一个名为python 模式和维基百科的github仓库告诉我们什么是惰性求值。
延迟 expr 的 eval 直到需要它的值并避免重复 evals。
range 在 python3 中不是一个完整的惰性求值,因为它不能避免重复求值。
惰性求值的一个更经典的例子是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
Run Code Online (Sandbox Code Playgroud)
cached_property(又名 lazy_property)是一个装饰器,它将 func 转换为惰性求值属性。第一次访问属性时,调用 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)
Run Code Online (Sandbox Code Playgroud)
用一个恰当的词来说,像range这样的 python 生成器对象更像是通过call_by_need模式设计的,而不是惰性求值
| 归档时间: |
|
| 查看次数: |
36331 次 |
| 最近记录: |