【问题标题】:copy/deepcopy and variable scope复制/深复制和变量范围
【发布时间】:2012-04-21 03:02:11
【问题描述】:

我在使用 copy.copy() 和 copy.deepcopy() 以及 Python 的范围时遇到问题。我调用一个函数,一个字典作为参数传递。字典复制本地字典,但字典不保留复制的值。

def foo (A, B):
    localDict = {}
    localDict['name'] = "Simon"
    localDict['age'] = 55
    localDict['timestamp'] = "2011-05-13 15:13:22"
    localDict['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}

    A = copy.deepcopy(localDict)

    B['me'] = 'John Doe'
    return



def qua (A, B):
    print "qua(A): ", A
    print "qua(B): ", B

    return


# *** MAIN ***
# 
# Test
#
A = {}
B = {}

print "initial A: ", A
print "initial B: ", B

foo (A, B)

print "after foo(A): ", A
print "after foo(B): ", B

qua (A, B)

copy.deepcopy 有效,并且在函数“foo”中,dict A 具有 localDict 的内容。但是在“foo”的范围之外,dict A 是空的。同时,在分配了键和值后,dict B 保留了从函数 'foo' 出来后的值。

如何维护 copy.deepcopy() 在函数“foo”之外复制的值?

【问题讨论】:

  • 为什么不在您的代码中使用fooreturn localDict, B 并使用A, B = foo(A, B)?这样它工作,您根本不需要使用copy 模块。另外,阅读一下 Python 的对象引用:stackoverflow.com/questions/575196/…
  • @Blender,是的,我知道我可以这样做,但我想知道当字典通过引用传递时,为什么 deepcopy() 会导致 Python 中的字典出现范围问题。
  • 它根本不是deepcopycopy(你真的应该使用dict(otherdict) 来复制,但这不是重点)。当您将对象传递给函数并且只能修改某些对象时,Python 不像 PHP 那样工作。阅读我链接到的问题的答案。

标签: python


【解决方案1】:

想一想:

>>> def foo(d):
...   d = {1: 2}
... 
>>> d = {3: 4}
>>> d
{3: 4}
>>> foo(d)
>>> d
{3: 4}
>>> 

foo 内部,d = {1: 2} 将一些对象绑定到名称d。这个名字是本地的,它不会修改 d 用来指向的对象。另一方面:

>>> def bar(d):
...   d[1] = 2
... 
>>> bar(d)
>>> d
{1: 2, 3: 4}
>>> 

所以这与您使用(深度)复制无关,它只是 Python 中“变量”的工作方式。

【讨论】:

    【解决方案2】:

    发生的情况是,在 foo() 中,您创建了 B 的副本并将其分配给 A,通过将新对象重新分配给相同的名称来隐藏您作为参数发送的空 dict。现在在函数内部你有一个名为 A 的新字典,在全局范围内与外部的 A 完全无关,当函数结束时它会被垃圾收集,所以实际上什么都没有发生,只有添加到 B 的“me”键。

    如果不是:

    A = copy.deepcopy(localDict)

    你做这样的事情,它会像你期望的那样工作:

    C = copy.deepcopy(localDict)
    
    A.update(C)
    

    但您真正想要的似乎与复制模块无关,是这样的:

    def foo (A, B):
        A['name'] = "Simon"
        A['age'] = 55
        A['timestamp'] = "2011-05-13 15:13:22"
        A['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
    
        B['me'] = 'John Doe'
    

    【讨论】:

      【解决方案3】:

      您看到的行为与deepcopy() 无关,您正在将名称A 重新分配给一个新值,除非您使用global 关键字,否则该分配不会继续。对B 的更改之所以持久,是因为您正在修改一个可变变量,这里有两个选项可以让您获得所需的行为:

      • 不用localDict,直接修改A即可:

        def foo(A, B):
            A['name'] = "Simon"
            A['age'] = 55
            A['timestamp'] = "2011-05-13 15:13:22"
            A['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
        
            B['me'] = 'John Doe'
            return
        
      • 使用A.update(copy.deepcopy(localDict)) 代替A = copy.deepcopy(localDict)

        def foo(A, B):
            localDict = {}
            localDict['name'] = "Simon"
            localDict['age'] = 55
            localDict['timestamp'] = "2011-05-13 15:13:22"
            localDict['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
        
            A.update(copy.deepcopy(localDict))
        
            B['me'] = 'John Doe'
            return
        

      【讨论】:

        猜你喜欢
        • 2013-12-28
        • 1970-01-01
        • 2015-08-21
        • 2014-10-27
        • 2014-05-02
        • 1970-01-01
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多