识别Python中的引用

识别Python中的引用,python,memory,reference,web.py,Python,Memory,Reference,Web.py,我刚刚花了很长时间使用web.py框架在python中调试了一个问题,这让我想知道将来如何检查这类问题 简言之,web.py的数据库类的方法之一是返回一个存储对象,我只能猜测它是对内存中某个值的引用,而不是副本。结果是,无论我尝试做什么,我都无法将一个查询的多个结果附加到一个列表中,因为该列表只包含同一行数据的副本 为了解决这个问题,我必须创建另一个字典,并将web.py存储对象中的所有值显式转换为另一个数据类型(我只是使用字符串使其工作),以便强制它创建一个新对象 在代码中,发生了以下情况:

我刚刚花了很长时间使用web.py框架在python中调试了一个问题,这让我想知道将来如何检查这类问题

简言之,web.py的数据库类的方法之一是返回一个存储对象,我只能猜测它是对内存中某个值的引用,而不是副本。结果是,无论我尝试做什么,我都无法将一个查询的多个结果附加到一个列表中,因为该列表只包含同一行数据的副本

为了解决这个问题,我必须创建另一个字典,并将web.py存储对象中的所有值显式转换为另一个数据类型(我只是使用字符串使其工作),以便强制它创建一个新对象

在代码中,发生了以下情况:

>>> result = db.query(query_params)
>>> for row in result:
>>>     print row
...     result_list.append(row)
{"result" : "from", "row" : "one"}
{"result" : "from", "row" : "two"}
>>> print result_list
[{"result":"from", "row" : "two"}, {"result" : "from", "row" : "two}]
这让我意识到这是一个参考问题。列表存储的是“行”的位置,而不是它的副本

我尝试的第一件事是:

 copy = {}
 for row in result:
    for value in row:
        copy[value] = row[value]
    result_list.append(copy)
但这也导致了同样的问题。 我只是通过调整上述内容找到了一个解决方案:

            copy[value] = str(row[value])
所以,我的问题是双重的,真的:

  • 有没有一种简单的方法可以告诉我们什么东西是如何被储存和/或传递的
  • 有没有一种方法可以显式地请求副本而不是引用
  • 使用。它允许在python中对对象进行简单的浅层和深层复制:

    import copy    
    result_list.append(copy.copy(row))
    

    我对web.py一无所知,但最有可能的结果集是append(dict(row))


    另请参见:

    欢迎了解Python的工作原理。在Python中很容易识别哪些对象是通过引用传递的:所有对象都是。只是很多对象(整数、字符串、元组)是不可变的,所以当有多个名称指向它们时,您不会真正注意到,因为您无法更改它们

    如果需要副本,请显式复制。通常,这可以使用类型的构造函数完成:

    newlist = list(oldlist)
    newdict = dict(olddict)
    
    列表也可以使用一个片段来完成,您经常会看到:

    newlist = oldlist[:]
    
    字典有一个
    copy()
    方法:

    newdict = olddict.copy()
    

    这些是“浅”副本:制作了一个新容器,但其中的项目仍然是原始参考。举例来说,这会让你心痛不已。存在一个名为
    copy
    的模块,该模块包含用于复制几乎任何对象的函数,以及一个
    deepcopy
    函数,该函数还将复制包含的对象到任何深度。

    如果您对身份感兴趣,您可以始终使用
    is
    操作符进行检查:

    >>> help('is')
    
    您的尝试不起作用的原因是因为您在循环之外创建字典,所以您当然会遇到问题:

    >>> mydict = {}
    >>> for x in xrange(3):
    ...     d = mydict
    ...     print d is mydict
    ...
    ...
    True
    True
    True
    
    无论您向
    d
    mydict
    添加多少次内容,
    mydict
    始终是同一个对象

    其他人评论说您应该使用copy,但他们没有解决您的根本问题—您似乎不理解引用类型

    在Python中,一切都是对象。有两种基本类型-可变和不可变。不可变对象是字符串、数字和元组等。不允许您更改内存中的这些对象:

    >>> x = 3
    >>> y = x
    >>> x is y
    True
    
    现在
    x
    y
    指的是同一个对象(不仅仅是具有相同的值)

    因为3是一个整数且不可变,所以此操作不会修改存储在
    x
    中的值,它实际做的是将3和4相加,并发现其结果是值7,因此现在
    x
    将“指向”7

    对于可变对象,可以在位修改它们:

    >>> mylist = [1,2,3]
    >>> mylist[0] = 3
    >>> mylist
    [3, 2, 3]
    
    如果您不再将Python中的变量看作是在变量中存储值,而将它们看作是名称标记,那么您将有更轻松的时间—您知道说“Hello,我的名字是”的那些吗

    因此,代码中发生的本质是,通过循环返回的对象每次都是相同的

    下面是一个例子:

    >>> def spam_ref():
    ...     thing = []
    ...     count = 0
    ...     while count < 10:
    ...         count += 1
    ...         thing.append(count)
    ...         yield thing
    ...
    >>> for a in spam_ref():
    ...  print a
    ...
    [1]
    [1, 2]
    [1, 2, 3]
    [1, 2, 3, 4]
    [1, 2, 3, 4, 5]
    [1, 2, 3, 4, 5, 6]
    [1, 2, 3, 4, 5, 6, 7]
    [1, 2, 3, 4, 5, 6, 7, 8]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> spam = []
    >>> for a in spam_ref():
    ...      spam.append(a)
    ...
    
    但事实并非如此:

    >>> for a in spam:
    ...  print a
    ...
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    因为列表是可变的,所以生成器函数能够就地修改它。在您的情况下,您有一本正在返回的词典,因此正如其他人所提到的,您需要使用一些复制词典的方法


    如需进一步阅读,请查看effbot。两种方法中的任何一种都可以:

    result = db.query(query_params).list()
    result = list(db.query(query_params))
    

    db.query
    db.select
    returniterator,需要将其转换为list

    我不知道有这样一个模块。非常感谢。谢谢你的赘言。我不知道python中的所有内容都是通过引用传递的。这显然是一件非常有益的事情!
    [1]
    [1, 2]
    [1, 2, 3]
    [1, 2, 3, 4]
    [1, 2, 3, 4, 5]
    [1, 2, 3, 4, 5, 6]
    [1, 2, 3, 4, 5, 6, 7]
    [1, 2, 3, 4, 5, 6, 7, 8]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    >>> for a in spam:
    ...  print a
    ...
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    result = db.query(query_params).list()
    result = list(db.query(query_params))