Disappointment over a Spoonerism

This is a spoonerism: butterflyflutterby.

See the link at the end of this post.

I had hoped to use list slicing and tuple assignment to transpose the 'b' with the 'fl', using the code below. Then 'butterfly' would become 'flutterby'. The following was written in hopes that the contents of the list would be buffered as the exchange was in progress, enabling a clean exchange of slices:

spoonerism = 'butterfly'
spoonerism = list(spoonerism)
spoonerism[0:1], spoonerism[6:8] = spoonerism[6:8], spoonerism[0:1]
spoonerism = ''.join(spoonerism)
print(spoonerism)

Disappointingly, the output was:

fluttebly

It’s just not as poetic as flutterby. … :frowning:

So, then I decided to verify what would have happened if, instead of the buffering that I had hoped for, the two slice assignments had been performed in succession, as follows,

spoonerism = 'butterfly'
spoonerism = list(spoonerism)
spoonerism[0:1] = spoonerism[6:8]
print(''.join(spoonerism)) # intermediate result
spoonerism[6:8] = spoonerism[0:1]
spoonerism = ''.join(spoonerism)
print(spoonerism) # final result

Output:

flutterfly
fluttefly

The output makes sense, though it is, of course, not what was originally desired. However, it also differs from the original disappointing output, proving, quite bluntly, that the original attempted tuple-powered slice assignment was not simply decomposed into two successive slice assignments.

The following produces the desired result, but why?:

spoonerism = 'butterfly'
spoonerism = list(spoonerism)
spoonerism[0:1], spoonerism[7:9] = spoonerism[6:8], spoonerism[0:1] # works, but huh?
spoonerism = ''.join(spoonerism)
print(spoonerism)

Output:

flutterby

Let’s decompose the previous into two successive slice assignments for comparison:

spoonerism = 'butterfly'
spoonerism = list(spoonerism)
spoonerism[0:1] = spoonerism[6:8]
spoonerism[7:9] = spoonerism[0:1]
spoonerism = ''.join(spoonerism)
print(spoonerism)

Output:

flutterfy

Hmmm … not the same result as from the previous hack, but now that is no longer surprising.

OK, I’ve weathered the initial disappointment, :slight_smile: but just what is going on when this is executed as in the original attempt?:

spoonerism[0:1], spoonerism[6:8] = spoonerism[6:8], spoonerism[0:1]

Just for interest:

The above was EDITED on November 20, 2021 to add a little commentary.

You’re extending (inserting into?) a list in the first assignment, before updating a later part of the list. Try assigning the original parts into temporary variables and printing or at each step to confirm this.

A solution would be to swap the order: it’s always easier to change a list in the later elements so as not to affect the indices of the earlier elements (for example, I always reverse iterate when I conditionally pop list elements).

sp[6:8], sp[0:1] = sp[0:1], sp[6:8]
1 Like

Thanks, this suggestion works:

So, now I have this:

spoonerism[6:8], spoonerism[0:1] = spoonerism[0:1], spoonerism[6:8]

It does the job perfectly. :smiley:

The fact that the above works, while the original attempt did not, does suggest that the two slice assignments are performed in succession. It would follow then, that when in the original post the first of the two modified the earlier part of the list, it affected the indices of the list, thereby affecting the result of the second of the two assignments.

However, if the two slice assignments implemented with tuples are executed in succession, why do the two below not produce the same results as each other?

spoonerism[0:1], spoonerism[6:8] = spoonerism[6:8], spoonerism[0:1]

The output from that one in the original post was:

fluttebly

spoonerism[0:1] = spoonerism[6:8]
spoonerism[6:8] = spoonerism[0:1]

The output from that one in the original post was:

fluttefly

Yes, they both differ, in results, from what was wanted, presumably due to the effect of the first slice assignment on the indices of the list. But why are the two code snippets above not equivalent to each other?

EDIT (2x on November 20, 2021):

Aha! The operations in the first of the two snippets above must be performed in the following order:

  • The first slice to the right of the = operator is buffered, prior to the change in indices.
  • The second slice to the right of the = operator is buffered, prior to the change in indices.
  • The first slice to the left of the = operator is replaced, affecting the indices.
  • The second slice to the left of the = operator is replaced, and so is affected by the change in indices.

That differs from the order of operations in the second snippet. In the first snippet, both slices to the right of the = operator are buffered prior to either of the assignments being completed. So buffering of both of those slices occurs prior to the index change. In the second snippet, for obvious reasons, the first assignment is completed in its entirety, prior to the second.

Thanks for your help!