我有一个名为Video的python类,它代表YouTube视频。给定 YouTube 视频的 ID,视频会返回一个表示该视频的对象。但是,首次创建视频对象时,不会查询 YouTube。只有当要求输入需要来自 YouTube 信息的属性时,才会查询 YouTube。以下是它的工作原理:
>>> from video import Video
>>> video = Video('B11msns6wPU')
# 'B11msns6wPU' is the ID of a video
>>> video
Video(youtube_id="B11msns6wPU")
### As of now, no call to YouTube's API has been made
### Next, I ask for the title attribute. The object queries YouTube's API to get
### this information. In doing so, the object is completely initialized
>>> video.title
u'Badly Drawn Boy - Disillusion (directed by Garth Jennings)'
>>> video.duration
u'275'
# no query was made to the API because the object has been already been initialized
我不确定这在技术上是否是"懒惰评估",但它的味道相似。在首次调用属性之前,不会初始化视频对象。我想知道这种技术是否值得实施。显然,它使我的代码更加复杂。你有什么想法?
这是一种笼统的判断,而不是一个硬性的决定。
如果惰性对象(Video
类实例)是应用程序的核心,那么在执行其他任何操作之前完全初始化它可能是有意义的;如果您的应用程序没有数据就毫无用处,请先获取数据。
但是,如果你的应用可能有成百上千个这样的Video
实例,并且其中大多数不会被使用,那么让用户在你初始化所有实例时等待是没有意义的。 在这种情况下,将初始化推迟到真正需要时才有意义。 例如,如果要显示"缩略图墙"显示,则可能需要每个视频和标题的缩略图,但除非用户单击缩略图,否则可能不需要任何其他内容。
我喜欢一般的方法,即使用该对象的代码不需要知道或关心对象是否预先初始化。
lazy loading
。如果并不总是需要这些属性,那么值得实施,并且从 api 中无偿查询它们将是一种浪费。例如,我创建了一个Video
类,但我不需要这些属性。
当类属性需要很长时间来获取/加载时,延迟加载是一个好主意。因此,在您的情况下,API 调用是否昂贵,您的Video
类是否真的需要它?有关视频类的更多信息将有助于了解它是否值得实现。延迟加载只是为了延迟加载而无缘无故地增加了代码的复杂性,所以是的,查看是否需要延迟加载很重要。
归根结底,这一切都取决于您如何处理应用程序中的 Video 对象。
当后续操作需要对后端进行更多查询时,或者当请求如此之大以至于以块为单位进行请求时,或者当您很有可能不会使用请求的每个部分时,惰性计算(或延迟加载或延迟初始化)很有用......一般来说,这是在渴望行为(例如 range()
在Python 2.x中)和懒惰(在Python 3.x中range()
)。
在这种情况下,似乎无论如何使用视频对象,最终发生的只是对该单个对象的 Youtube API 的调用。
如果您的库支持更复杂的查询或用法,则延迟计算可能非常有用。大致如下:
>>> video_list = ['B11msns6wPU', 'GuaCaMole', 'OvER9000']
>>> videos = Video.fetch(video_list)
# No API call, yet
>>> videos.filter_by('duration', lambda dur: int(dur) > 200)
# Filter by duration - still no API call
>>> for v in videos.all:
... # Now the API call is made, and the filtering is done all at once
当然,我知道我的例子是人为的(它看起来很奇怪地像一个数据库库......),但这就是它的要点。
是的,您正在实现惰性评估,并且作为"是否值得"问题的其他答案,这取决于数据的使用模式以及何时要让用户等待。 要记住的另一件事是,如果视频数据的拉取可能需要一段时间,但您相当确定您将需要数据,则可以在另一个执行线程中提取数据以预取它。
实现您使用的惰性计算类型并避免代码复杂性的一种方法是使用金字塔库中的装饰器(如@reify)。 看看这个博客文章中金字塔库中的@reify装饰器,其中包含一个链接,用于在底部实现源代码
这可能不是您想要实现它的方式,但值得研究惰性计算的"pythonic"解决方案。