【问题标题】:How do I "freeze" an object, I.E. compute it once and then reference it later without computing it again?我如何“冻结”一个对象,即计算一次然后在以后引用它而不再次计算它?
【发布时间】:2014-01-04 14:31:04
【问题描述】:

很抱歉描述不佳,问题的根源是我不确定术语。

这不是 GIS 问题,而是一般问题的一个示例:在 python 2.7 中,我如何“冻结”一个计算时间过长的变量,就像我对 frozen_list_copy = original_list[:] 所做的那样?

这里有一些代码,简化后专注于我的问题。 maketransformer() 运行时间太长,它会输出 transformer,这是一个 GDAL(GIS 东西)坐标系统转换对象,它在每次循环迭代时都工作相同。我只需要创建一次transformer 对象,然后从中重复调用一个方法。每次循环引用 transformer 变量赋值时,它都会运行 maketransformer() 来创建一个新变量。

def maketransformer(file): #contains arbitrary stuff that takes too long

    data = gdal.Open(file)
    output_wkt = data.GetProjection()
    srs_out = osr.SpatialReference()
    srs_out.ImportFromWkt(output_wkt)

    transformer = osr.CoordinateTransformation(srs_out)
    return transformer

transformer = maketransformer('data/w001001.adf')

for tuple in shapefilepoints:
    getelevation(transformer.Transform(tuple))

我怎样才能只运行一次maketransformer(),然后“冻结”它生成的对象,将其与其分配“断开”,这样我就可以使用该对象,而无需在整个 0.1 秒的创建过程中运行 15,000 次?

我正在尝试做的类似于:

>>> x = ['one', 'two', 'three']
>>> y = x
>>> z = x[:]     # I want to do this, but with a non-list object
>>> x[2] = 'purple'
>>> x
['one', 'two', 'purple']
>>> y
['one', 'two', 'purple']
>>> z     # So that the following happens when I use z
['one', 'two', 'three']

简而言之,我在谷歌上用什么词来形容这个!非常感谢,为无用的具体初学者问题道歉。

编辑:我发现了一个有用的工具来发现什么是滞留:

>>>import profile
profile.run("maketransformer('data/w001001.adf')")

Profile 将函数分解为各个部分,返回它所做的一切的调用次数和时间,表明它在 0.001 秒内运行。问题出在其他地方。谢谢大家教我这些有用的东西。

【问题讨论】:

  • 你用的是什么版本的python? 3.2 及以上版本有@functools.lru_cache 可以为你缓存运行函数的结果。
  • 我使用的是 2.7,但这正是我想要的!谢谢你。编辑问题
  • @CeganDodge 由于您提到 2.7,您需要选择一个记忆库:请参阅 this post 了解一些信息
  • @JonClements 好信息,谢谢
  • 这个问题现在实际上毫无意义,因为问题本身包含答案并且是基于对代码的一些误解。

标签: python scope variable-assignment


【解决方案1】:
def maketransformer(file): #contains arbitrary stuff that takes too long

    data = gdal.Open(file)
    output_wkt = data.GetProjection()
    srs_out = osr.SpatialReference()
    srs_out.ImportFromWkt(output_wkt)

    transformer = osr.CoordinateTransformation(srs_out)
    return transformer

transformer = maketransformer('data/w001001.adf')

for tuple in shapefilepoints:
    getelevation(transformer.Transform(tuple))

正如您所写,这段代码不会每次都重新运行maketransformermaketransformer 只运行一次,然后每个 Transform 调用都使用同一个对象。这可能就是您所需要的。

【讨论】:

  • 非常感谢!好吧,我不应该相信我的看法。现在要找出整个事情的哪一部分实际上花了这么长时间。
【解决方案2】:

pythonpickle 模块将根据对象的数据足迹(来自磁盘或内存字符串)“重构”一个对象,而无需执行初始化代码。

import pickle

...
transstr = dumps(maketransformer(...))

for ....
    getelevation(pickle.reads(transstr).Transform(tuple))

...

或类似的东西我相信会做你想做的。

【讨论】:

  • 完美。我认为泡菜是为了其他目的,我会更深入地研究它。谢谢!
  • @CeganDodge: pickle 不是答案。序列化和反序列化数据结构以制作副本效率不高。
  • @user2357112 我同意它效率不高,在更高级别修复代码可能是更好的解决方案 - 我只是提出它作为上述问题的解决方案。
  • @norlesh:在得知我误解了我的问题之前,我在测试中使用了 pickle,它完美地解决了我认为的问题,并且在以后的这个项目中实际上会派上用场。发现!无论如何,谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-10-04
  • 2021-05-05
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多