how to deepcopy a slice object?

Simon Forman rogue_pedro at yahoo.com
Tue Aug 15 17:37:42 EDT 2006


Alexandre Guimond wrote:
> Here is my reason:
>
> I have an object that contrains a 2D regular grid (matrix). In this
> regular grid, I place points at regular intervals. In essence, i have
> something like (my code is obviously more complex, this is just to show
> what I want to do)
>
> obj.grid = numpy.zeros( ( 100, 100 ) )
> obj.grid[ obj.y1: obj.y2 : obj.ys, obj.x1 : obj.x2 : obj.xs ] =
> embedded_parameters
> result = somefunc( obj.grid )
>
> My goal was to reduce the number of elements in my obj object by
> replacing y1, y2, ys, and x1, x2, xs by 2 slice objects, and then do:
>
> obj.grid[ obj.slicey, obj.slicex ] = embedded_parameters
>
> But when I do this and then try to deepcopy my object, it doesn't work,
> as in the example below.
>
> Its not a big thing. I just liked the idea of having less elements in
> my obj class and actually modeling my slice concept by a slice object,
> specially since i'm going to 3D and 4D grid, and its somewhat annoying
> to carry so many indices in my class definition.
>
> Simon Forman wrote:
> > Alexandre Guimond wrote:
> > > Hi all,
> > >
> > > i'm trying to deepcopy a slice object but i get the following error.
> > > Does anyone know a workaround?
> > >
> > > ActivePython 2.4.3 Build 12 (ActiveState Software Inc.) based on
> > > Python 2.4.3 (#69, Apr 11 2006, 15:32:42) [MSC v.1310 32 bit (Intel)]
> > > on win32
> > > Type "help", "copyright", "credits" or "license" for more information.
> > > >>> import copy
> > > >>> copy.deepcopy( slice( 1, 10, 2 ) )
> > > Traceback (most recent call last):
> > >   File "<stdin>", line 1, in ?
> > >   File "C:\Program Files\Python\lib\copy.py", line 204, in deepcopy
> > >     y = _reconstruct(x, rv, 1, memo)
> > >   File "C:\Program Files\Python\lib\copy.py", line 336, in _reconstruct
> > >     y = callable(*args)
> > >   File "C:\Program Files\Python\lib\copy_reg.py", line 92, in
> > > __newobj__
> > >     return cls.__new__(cls, *args)
> > > TypeError: slice expected at least 1 arguments, got 0
> > >
> > > thx for any help.
> >
> > Why would you want to [deep]copy a slice object?
> >
> > Anyway,  I don't know much about them, other than that they are
> > slightly unusual objects that play a very restricted role in python,
> > rather like the Ellipsis.
> >
> > Workarounds are possible, I think, but really you almost certainly
> > don't need to do this.
> >
> > Peace,
> > ~Simon

Ah, so you *do* want to deepcopy slice objects..  Neat. :-)

I can't do that, but I can show you a couple of ways to deepcopy
objects that have slices as attributes.

First, if the __init__() method and its args are sufficient to recreate
your objects then you could do something like this:

class DeepCopyable0:

    def __init__(self, x, y, z, a, b, c):
        self.slicex = slice(x, y, z)
        self.slicey = slice(a, b, c)

    def __deepcopy__(self, memo):

        # Create local vars for brevity.
        sx, sy = self.slicex, self.slicey

        # Create a new DeepCopyable0 instance.
        return DeepCopyable0(
            sx.start, sx.stop, sx.step,
            sy.start, sy.stop, sy.step
            )

|>> d0 = DeepCopyable0(1, 2, 3, 4, 5, 6)
|>> d0.slicex, d0.slicey
(slice(1, 2, 3), slice(4, 5, 6))
|>> d1 = deepcopy(d0)
|>> d1.slicex, d1.slicey
(slice(1, 2, 3), slice(4, 5, 6))

Otherwise, another way to do it would be to provide the pickling
protocol:

class DeepCopyable1:

    def __init__(self, x, y, z, a, b, c):
        # Pretend this was something more complicated.
        self.slicex = slice(x, y, z)
        self.slicey = slice(a, b, c)

    def __getstate__(self):

        state = self.__dict__.copy()

        # Create local vars for brevity.
        sx, sy = self.slicex, self.slicey

        # Save the indices rather than the slices.
        state['slicex'] = sx.start, sx.stop, sx.step
        state['slicey'] = sy.start, sy.stop, sy.step

        return state

    def __setstate__(self, state):

        # Recreate the slice objects.
        state['slicex'] = slice(*state['slicex'])
        state['slicey'] = slice(*state['slicey'])

        self.__dict__.update(state)


|>> d0 = DeepCopyable1(1, 2, 3, 4, 5, 6)
|>> d0.slicex, d0.slicey
(slice(1, 2, 3), slice(4, 5, 6))
|>> d1 = deepcopy(d0)
|>> d1.slicex, d1.slicey
(slice(1, 2, 3), slice(4, 5, 6))

Circular references seem work fine here too.  Observe:

|>> d0 = DeepCopyable1(1, 2, 3, 4, 5, 6)
|>> d0.rec = d0
|>> d0
<delme.DeepCopyable instance at 0xb7d5cb2c>
|>> d0.rec.rec  #etc...
<delme.DeepCopyable instance at 0xb7d5cb2c>
|>> d1 = deepcopy(d0)
|>> d1
<delme.DeepCopyable instance at 0xb7d7878c>
|>> d1.rec
<delme.DeepCopyable instance at 0xb7d7878c>

Since you're going to be using more dimensions, you could make python
do the work for you rather than cutting and pasting:

class DeepCopyable2:

    # __init__() omitted...

    def __getstate__(self):
        state = self.__dict__.copy()

        # Keep track of the slice attributes
        slices = state['slices'] = []

        # Convert slices to indices.
        for attr, s in state.items():
            if isinstance(s, slice):
                state[attr] = s.start, s.stop, s.step
                slices.append(attr)

        return state

    def __setstate__(self, state):

        slices = state.pop('slices')

        # Recreate the slice objects.
        for attr in slices:
            state[attr] = slice(*state[attr])

        self.__dict__.update(state)


(I copied over the __init__() method from DeepCopyable for this
example.)
|>> from delme import *
|>> d0 = DeepCopyable2(1, 2, 3, 4, 5, 6)
|>> d1 = deepcopy(d0)
|>> d1.slicex, d1.slicey
(slice(1, 2, 3), slice(4, 5, 6))

HTH. :)

I haven't used numpy (yet) and I've never explicitly used slice
objects, so the idea of storing and copying them struck me funny.  I
find it very interesting and amusing that someone somewhere has a use
for them like this.

Peace,
~Simon




More information about the Python-list mailing list