1

I have a look at python code where string variable assignments looks like:

var1 = var2[:]

I am just wondering what is the difference between:

var1 = var2

Here is my experiments:

>>> original = "some text"
>>> copy1 = original
>>> copy2 = original[:]
>>> original = "another text"
>>> copy1
'some text'
>>> copy2
'some text'

Updated:

Here is a full code. This code search a key for substitution cipher. If I remove '[:]' this code will works very slowly.

ceth
  • 44,198
  • 62
  • 180
  • 289

5 Answers5

5

Due to interning, there is often no difference (in the resulting object) between the two. We may check whether two variables point to the same object by using the is operator, which in contrast to the == operator checks wheter the actual memory address of the objects are the same:

>>> a = "foo"
>>> b = a
>>> a is b
True
>>> c = a[:]
>>> a is c
True

Interning is a mechanism for saving memory and speeding up comparisons of immutable objects, and it works like this: before creating a new immutable, python checks to see if an identical immutable already exists. If so, it just uses a reference to the existing object. It can do that without harm because there's no way to change an immutable. This is why even two independently created strings may point to the same object:

>>> a = "foo"
>>> b = "foo"
>>> a is b
True

But if var2 was some mutable sequential object, like a list, then var2[:] would be a shallow copy of var2, so that making changes to one would not affect the other.

>>> a = list("foo")
>>> a
['f', 'o', 'o']
>>> b = a
>>> b is a
True
>>> c = a[:]
>>> c is a
False
>>> b.pop()
'o'
>>> a
['f', 'o']
>>> b
['f', 'o']
>>> c
['f', 'o', 'o']

For the full picture, also read Ashwini Chaudharys answer.

Community
  • 1
  • 1
Lauritz V. Thaulow
  • 49,139
  • 12
  • 73
  • 92
2

[:] notation is used for slicing,

a[m:n] will return characters starting from index m upto n-1, if nothing is passed it returns the whole string back.

In [1]: a="foobar"

In [2]: a[:]          #this is equal to a only as nothing to passed to slicing
Out[2]: 'foobar'

In [3]: a[1:]         #return everything after index 1
Out[3]: 'oobar'

In [4]: a[:1]         #return everything before 1st index
Out[4]: 'f'

In [5]: a[:-1]        #return everything before the last character
Out[5]: 'fooba'

DIFFERENCE between b=a[:] and b=a is that b=a takes less number of steps internally:

In [7]: def func1():
   ...:     a="foo"
   ...:     b=a
   ...:     

In [8]: def func2():
   ...:     a="foo"
   ...:     b=a[:]
   ...:     

In [9]: dis.dis(func1)
  2           0 LOAD_CONST               1 ('foo')
              3 STORE_FAST               0 (a)

  3           6 LOAD_FAST                0 (a)
              9 STORE_FAST               1 (b)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE        

In [10]: dis.dis(func2)
  2           0 LOAD_CONST               1 ('foo')
              3 STORE_FAST               0 (a)

  3           6 LOAD_FAST                0 (a)
              9 SLICE+0             
             10 STORE_FAST               1 (b)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE 

timeit:

In [11]: %timeit func1()
1000000 loops, best of 3: 336 ns per loop

In [12]: %timeit func2()
1000000 loops, best of 3: 397 ns per loop
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
1

In the full code you link to, there is a possibility of original being a list, not a str:

parentkey,parentscore = startkey or list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),-99e99

and then

child = parentkey[:]
# swap two characters in the child
child[a],child[b] = child[b],child[a]

As mentioned by lazyr, creating a copy will make a difference in this case.

Lev Levitsky
  • 63,701
  • 20
  • 147
  • 175
1

Note that in your code, the variable can be a list rather than a string.

See the following example:

>>> a = [1,2,3]
>>> b = a
>>> b[0] = 'foo'
>>> a
['foo', 2, 3]

But:

>>> a = [1,2,3]
>>> b = a[:]
>>> b[0] = 'foo'
>>> a
[1, 2, 3]

In other words, in the first example, the reference to a is preserved in b and changing b changes a. Using the slice notation [:] makes a deep (1 level) copy instead.

Hamish
  • 22,860
  • 8
  • 53
  • 67
  • You just got the last sentence the wrong way round: `[:]` makes a **deep** copy (well, one extra layer deep). It is a really handy way to copy, say, a list of strings. – D Read Nov 06 '12 at 10:30
0

a[:] is the same as just a, id(a) == id(a[:]), so there is no difference)

a = 'Convert an integer number to a binary string Convert an integer number to a binary'
id(a) == id(a[:])
>>> True

For list [:] returns a copy of it.

a = [1, 2, 3]
id(a) == id(a[:])
>>> False
alexvassel
  • 10,600
  • 2
  • 29
  • 31