How to copy a dictionary and only edit the copy

前端 未结 20 2010
说谎
说谎 2020-11-21 06:59

Can someone please explain this to me? This doesn\'t make any sense to me.

I copy a dictionary into another and edit the second and both are changed. Why is this hap

相关标签:
20条回答
  • 2020-11-21 07:40

    Python never implicitly copies objects. When you set dict2 = dict1, you are making them refer to the same exact dict object, so when you mutate it, all references to it keep referring to the object in its current state.

    If you want to copy the dict (which is rare), you have to do so explicitly with

    dict2 = dict(dict1)
    

    or

    dict2 = dict1.copy()
    
    0 讨论(0)
  • 2020-11-21 07:40

    You can also just make a new dictionary with a dictionary comprehension. This avoids importing copy.

    dout = dict((k,v) for k,v in mydict.items())
    

    Of course in python >= 2.7 you can do:

    dout = {k:v for k,v in mydict.items()}
    

    But for backwards compat., the top method is better.

    0 讨论(0)
  • 2020-11-21 07:41

    As others have explained, the built-in dict does not do what you want. But in Python2 (and probably 3 too) you can easily create a ValueDict class that copies with = so you can be sure that the original will not change.

    class ValueDict(dict):
    
        def __ilshift__(self, args):
            result = ValueDict(self)
            if isinstance(args, dict):
                dict.update(result, args)
            else:
                dict.__setitem__(result, *args)
            return result # Pythonic LVALUE modification
    
        def __irshift__(self, args):
            result = ValueDict(self)
            dict.__delitem__(result, args)
            return result # Pythonic LVALUE modification
    
        def __setitem__(self, k, v):
            raise AttributeError, \
                "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)
    
        def __delitem__(self, k):
            raise AttributeError, \
                "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)
    
        def update(self, d2):
            raise AttributeError, \
                "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""
    
    
    # test
    d = ValueDict()
    
    d <<='apples', 5
    d <<='pears', 8
    print "d =", d
    
    e = d
    e <<='bananas', 1
    print "e =", e
    print "d =", d
    
    d >>='pears'
    print "d =", d
    d <<={'blueberries': 2, 'watermelons': 315}
    print "d =", d
    print "e =", e
    print "e['bananas'] =", e['bananas']
    
    
    # result
    d = {'apples': 5, 'pears': 8}
    e = {'apples': 5, 'pears': 8, 'bananas': 1}
    d = {'apples': 5, 'pears': 8}
    d = {'apples': 5}
    d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
    e = {'apples': 5, 'pears': 8, 'bananas': 1}
    e['bananas'] = 1
    
    # e[0]=3
    # would give:
    # AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."
    

    Please refer to the lvalue modification pattern discussed here: Python 2.7 - clean syntax for lvalue modification. The key observation is that str and int behave as values in Python (even though they're actually immutable objects under the hood). While you're observing that, please also observe that nothing is magically special about str or int. dict can be used in much the same ways, and I can think of many cases where ValueDict makes sense.

    0 讨论(0)
  • 2020-11-21 07:43

    Every variable in python (stuff like dict1 or str or __builtins__ is a pointer to some hidden platonic "object" inside the machine.

    If you set dict1 = dict2,you just point dict1 to the same object (or memory location, or whatever analogy you like) as dict2. Now, the object referenced by dict1 is the same object referenced by dict2.

    You can check: dict1 is dict2 should be True. Also, id(dict1) should be the same as id(dict2).

    You want dict1 = copy(dict2), or dict1 = deepcopy(dict2).

    The difference between copy and deepcopy? deepcopy will make sure that the elements of dict2 (did you point it at a list?) are also copies.

    I don't use deepcopy much - it's usually poor practice to write code that needs it (in my opinion).

    0 讨论(0)
  • 2020-11-21 07:44

    Assignment statements in Python do not copy objects, they create bindings between a target and an object.

    so, dict2 = dict1, it results another binding between dict2and the object that dict1 refer to.

    if you want to copy a dict, you can use the copy module. The copy module has two interface:

    copy.copy(x)
    Return a shallow copy of x.
    
    copy.deepcopy(x)
    Return a deep copy of x.
    

    The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

    A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

    A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

    For example, in python 2.7.9:

    >>> import copy
    >>> a = [1,2,3,4,['a', 'b']]
    >>> b = a
    >>> c = copy.copy(a)
    >>> d = copy.deepcopy(a)
    >>> a.append(5)
    >>> a[4].append('c')
    

    and the result is:

    >>> a
    [1, 2, 3, 4, ['a', 'b', 'c'], 5]
    >>> b
    [1, 2, 3, 4, ['a', 'b', 'c'], 5]
    >>> c
    [1, 2, 3, 4, ['a', 'b', 'c']]
    >>> d
    [1, 2, 3, 4, ['a', 'b']]
    
    0 讨论(0)
  • 2020-11-21 07:45

    The best and the easiest ways to create a copy of a dict in both Python 2.7 and 3 are...

    To create a copy of simple(single-level) dictionary:

    1. Using dict() method, instead of generating a reference that points to the existing dict.

    my_dict1 = dict()
    my_dict1["message"] = "Hello Python"
    print(my_dict1)  # {'message':'Hello Python'}
    
    my_dict2 = dict(my_dict1)
    print(my_dict2)  # {'message':'Hello Python'}
    
    # Made changes in my_dict1 
    my_dict1["name"] = "Emrit"
    print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
    print(my_dict2)  # {'message':'Hello Python'}
    

    2. Using the built-in update() method of python dictionary.

    my_dict2 = dict()
    my_dict2.update(my_dict1)
    print(my_dict2)  # {'message':'Hello Python'}
    
    # Made changes in my_dict1 
    my_dict1["name"] = "Emrit"
    print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
    print(my_dict2)  # {'message':'Hello Python'}
    

    To create a copy of nested or complex dictionary:

    Use the built-in copy module, which provides a generic shallow and deep copy operations. This module is present in both Python 2.7 and 3.*

    import copy
    
    my_dict2 = copy.deepcopy(my_dict1)
    
    0 讨论(0)
提交回复
热议问题