Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
deepcopy和python-避免使用它的提示?_Python_Deep Copy - Fatal编程技术网

deepcopy和python-避免使用它的提示?

deepcopy和python-避免使用它的提示?,python,deep-copy,Python,Deep Copy,我有一个非常简单的python例程,它涉及循环遍历大约20000个纬度和经度坐标的列表,并计算每个点到参考点的距离 def compute_nearest_points( lat, lon, nPoints=5 ): """Find the nearest N points, given the input coordinates.""" points = session.query(PointIndex).all() oldNearest = [] newNe

我有一个非常简单的python例程,它涉及循环遍历大约20000个纬度和经度坐标的列表,并计算每个点到参考点的距离

def compute_nearest_points( lat, lon, nPoints=5 ):
    """Find the nearest N points, given the input coordinates."""

    points = session.query(PointIndex).all()
    oldNearest = []
    newNearest = []
    for n in xrange(nPoints):
        oldNearest.append(PointDistance(None,None,None,99999.0,99999.0))
        newNearest.append(obj2)

    #This is almost certainly an inappropriate use of deepcopy
    #  but how SHOULD I be doing this?!?!
    for point in points:
        distance = compute_spherical_law_of_cosines( lat, lon, point.avg_lat, point.avg_lon )
        k = 0
        for p in oldNearest:
            if distance < p.distance:
                newNearest[k] = PointDistance(
                    point.point, point.kana, point.english, point.avg_lat, point.avg_lon, distance=distance
                    )
                break
            else:
                newNearest[k] = deepcopy(oldNearest[k])
            k += 1
        for j in range(k,nPoints-1):
            newNearest[j+1] = deepcopy(oldNearest[j])
        oldNearest = deepcopy(newNearest)

    #We're done, now print the result
    for point in oldNearest:
        print point.station, point.english, point.distance

    return
所以基本上我只是制作一个输入的完整副本,并附加一个新的值-到参考点的距离。然后我将“sorted”应用于结果列表,指定排序键应该是PointDistance对象的distance属性


这比使用deepcopy快得多,尽管我承认我真的不明白为什么。我想这取决于高效的C实现python的“排序”?

好的,首先是最简单的事情:

  • deepcopy
    通常速度很慢,因为它必须做大量的内部簿记,才能以一种正常的方式复制病理病例,比如包含自身的对象。例如,请参阅或查看Python路径中的
    copy.py
    中的
    deepcopy
    的源代码

  • sorted
    很快,因为它是用C实现的。比Python中的等效排序快得多

  • 现在,我们来了解一下Python的引用计数行为,正如您在评论中所问的。在Python中,变量是引用。当你说
    a=1
    时,想想它有
    1
    作为一个单独存在的对象,而
    a
    只是一个附加到它的标签。在其他一些语言(如C)中,变量是容器(而不是标记),当您执行
    a=1
    时,实际上将1放入
    a
    。对于Python,变量是引用,这一点不适用。这有一些有趣的结果,您可能也会偶然发现:

    >>> a = []      # construct a new list, attach a tag named "a" to it
    >>> b = a       # attach a tag named "b" to the object which is tagged by "a"
    >>> a.append(1) # append 1 to the list tagged by "a"
    >>> print b     # print the list tagged by "b"
    [1]
    
    之所以会看到这种行为,是因为列表是可变对象:您可以在创建列表后对其进行修改,并且在通过引用列表的任何变量访问列表时会看到修改。列表的不变等价物是元组:

    >>> a = ()      # construct a new tuple, attach a tag named "a" to it
    >>> b = a       # now "b" refers to the same empty tuple as "a"
    >>> a += (1, 2) # appending some elements to the tuple
    >>> print b
    ()
    
    这里,
    a+=(1,2)
    a
    引用的现有元组中创建一个新元组,再加上另一个动态构造的元组
    (1,2)
    ,并且
    a
    被调整为指向新元组,当然
    b
    仍然引用旧元组。类似于
    a=a+2
    这样的简单数字加法也会发生同样的情况:在这种情况下,
    a
    最初指向的数字不会以任何方式发生变异,Python“构造”一个新数字并移动
    a
    指向新数字。简言之,数字、字符串和元组是不可变的;列表、目录和集合是可变的。用户定义的类通常是可变的,除非您明确地确保内部状态不能被改变。还有一个
    frozenset
    ,它是一个不可变的集合。当然还有很多其他的:)

    我不知道您的原始代码为什么不起作用,但您可能遇到了与我在列表中显示的代码片段相关的行为,因为默认情况下,
    PointDistance
    类也是可变的。另一种选择是
    collections
    中的
    namedtuple
    类,它构造了一个类似元组的对象,其字段也可以通过名称访问。例如,您可以这样做:

    from collections import namedtuple
    PointDistance = namedtuple("PointDistance", "point distance")
    
    这将为您创建一个
    PointDistance
    类,该类有两个命名字段:
    point
    distance
    。在主
    for
    循环中,可以适当地分配这些参数。由于在
    for
    循环过程中,
    字段指向的点对象不会被修改,并且
    距离
    是一个数字(根据定义,它是不可变的),因此这样做应该是安全的。但是是的,一般来说,简单地使用
    sorted
    似乎更快,因为
    sorted
    是用C实现的。您还可以使用
    heapq
    模块,它实现了一个由普通Python列表支持的堆数据结构,因此,它可以让您轻松地找到顶部的
    k
    元素,而无需对其他元素进行排序。然而,由于
    heapq
    也是在Python中实现的,除非你有很多要点,否则
    sorted
    的效果会更好


    最后,我想补充一点,到目前为止,我从未使用过
    deepcopy
    ,所以我想在大多数情况下都有办法避免它。

    我知道这并不能直接解决您的问题(我知道这是一个老问题),但是,由于有一些关于性能的讨论,因此有必要研究一下
    append
    操作。您可能需要考虑“预分配”数组。例如:

    array = [None] * num_elements
    for i in range(num_elements):
        array[i] = True
    
    与:

    array = []
    for i in range(num_elements):
        array.append(True)
    

    这两种方法的一个简单的
    timeit
    运行表明,如果您为
    num\u元素的中等值预先分配数组,那么
    PointDistance
    类的效果如何?如果将
    PointDistance
    类设置为一个简单类,只引用原始点及其距离(即它实际上是一个包含两个元素的元组),您不需要使用
    deepcopy
    ,因为点在算法过程中不会改变,距离是一个简单的数字。@Tamás是的,它基本上只是一个字典。但是,在第一个示例中,如果没有deepcopy,这肯定不起作用。如果我干脆把这门课全部取消,改用字典的话,也许会有用吧?老实说,我只是对参考模型没有足够清晰的理解,不知道在这些情况下会发生什么。也许你可以详细说明一下,或者给我指一下关于这个主题的其他资源或帖子?非常感谢你花时间写下如此详细、清晰和简洁的解释。因此,我觉得我对事物的“为什么”有了更好的理解。
    array = []
    for i in range(num_elements):
        array.append(True)