2

I'm trying to use deepcopy on an ndarray, and the line looks like this:

foo = myArray.__deepcopy__()

I'm getting:

TypeError: function takes exactly 1 argument (0 given)

I need a deep copy, and I can't import copy.

2
  • 2
    "I can't import copy" - why not? Commented Mar 16, 2017 at 23:49
  • 2
    Unless you're using an object array (which you shouldn't), myArray.copy() should work fine. Commented Mar 17, 2017 at 0:17

3 Answers 3

2

The special __deepcopy__ method takes a memo arg. You can pass an empty dict for this:

foo = myArray.__deepcopy__({})
Sign up to request clarification or add additional context in comments.

7 Comments

Weird, I didn't see that in the documentation, but it works. Thanks!
Since when could the memo be a tuple? The docs say it's a dict.
@user2357112 I would have naturally said dict too, but the numpy doc used a tuple as sample: docs.scipy.org/doc/numpy/reference/…
@MosesKoledoye: That looks like a formatting problem to me, not a sample input. It wouldn't be the only formatting problem; a few lines down, we have ndarray.__new__((S, ...), with mismatched parentheses.
@user2357112 You are right, but I am particularly surprised as to why it works with almost any container type
|
2

The relevant code in copy is:

def deepcopy(x, memo=None, _nil=[]):
    """Deep copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.
    """

    if memo is None:
        memo = {}
        ....
           copier = getattr(x, "__deepcopy__", None)
            if copier:
                y = copier(memo)
...
# If is its own copy, don't memoize.
if y is not x:
    memo[d] = y
    _keep_alive(x, memo) # Make sure x lives at least as long as d
return y

So memo is a memoize dictionary, at least when used 'properly'

So if I pass a dictionary as memo, it changes that:

In [160]: dd={}
In [161]: A2=copy.deepcopy(A,memo=dd)
In [162]: dd
Out[162]: 
{2814755008: array([[[0, 1, 0, 0, 0, 0],
         [0, 0, 1, 0, 0, 1],
         [0, 0, 0, 1, 0, 1],
         [1, 0, 0, 0, 1, 0]],

        [[0, 0, 1, 0, 0, 0],
         [0, 0, 1, 1, 0, 0],
         [0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0]]]), 2814808588: [array([[[0, 1, 0, 0, 0, 0],
          [0, 0, 1, 0, 0, 1],
          [0, 0, 0, 1, 0, 1],
          [1, 0, 0, 0, 1, 0]],

         [[0, 0, 1, 0, 0, 0],
          [0, 0, 1, 1, 0, 0],
          [0, 0, 0, 0, 0, 0],
          [0, 0, 0, 0, 0, 0]]])]}
In [163]: id(A)
Out[163]: 2814755008
In [167]: id(dd[id(A)])
Out[167]: 2814568472
In [168]: id(A2)
Out[168]: 2814568472

The memo keeps a record of the copy. I don't know what the 2nd item is.

And if I ask for another deep copy with the same memo, it gives the memoized array rather than a new copy.

In [173]: A3=copy.deepcopy(A,memo=dd)
In [174]: id(A2)
Out[174]: 2814568472
In [175]: id(A3)
Out[175]: 2814568472

If an array is object dtype, the deepcopy might make a difference. The memo certainly looks different.

Comments

1

The copy module contains the documentation for __deepcopy__, and it is quite clear what the argument should be:

In order for a class to define its own copy implementation, it can define special methods __copy__() and __deepcopy__(). The former is called to implement the shallow copy operation; no additional arguments are passed. The latter is called to implement the deep copy operation; it is passed one argument, the memo dictionary.

But if you're not implementing a customized deep-copyable class you generally don't need to bother about this, simply use copy.deepcopy:

from copy import deepcopy
import numpy as np
arr = np.random.random((100, 100))
deepcopy(arr)

It will take care of the memo-dict without your intervention. Note: Most of the __*__ are designed that way, you generally don't and shouldn't call them directly. So like you use x in y instead of y.__contains__(x) you normally use copy.deepcopy(x) instead of x.__deepcopy__(dict()).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.