When python divides two integers the results is truncated to an integer:
>>> a = 1/2
0
>>> a = 1 / 16
0
>>> a = 15 / 16
0
>>> a = 1.0 / 2
0.5
If you slice a list beyond its bounds, it will not raise an error:
>>> a = [1, 2, 3, 4]
[1,2,3,4]
>>> a[0:3]
[1,2,3]
>>> a[2:4]
[3,4]
>>> a[2:5]
[3,4]
>>> a[2:500]
[3,4]
>>> a[5:6]
[]
You can use this to check if an index exists:
>>> isinstance(a, list)
True
>>> len(a)
4
>>> n = 5
>>> not a[n:(n+1)] == []
False
>>> n = 2
>>> not a[n:(n+1)] == []
True
All python objects are pointers. Unless you make a copy of an object, when you assign one objet the value of another you are only pointing to it so any changes to one object affect the other:
>>> dict1 = {'a': 'apple', 'b':'bear'}
>>> dict2 = dict1
>>> print repr(dict1)
{'a': 'apple', 'b':'bear'}
>>> print repr(dict2)
{'a': 'apple', 'b':'bear'}
>>> dict2['a'] = 'antelope'
>>> print dict1['a']
'antelope'
# Expected 'apple'
>>> dict2 = copy.copy(dict1)
>>> dict2['a'] = 'aardvark'
>>> print repr(dict1)
{'a': 'antelope', 'b':'bear'}
>>> print repr(dict2)
{'a': 'aardvark', 'b':'bear'}
But copy only makes copies of the first level of objects. i.e in a dictionary of dictionaries only the first level of the dictionary is copied. To make a copy of all the objects you must make a deep copy. This should only be used when needed since there are some disadvantages which are explained on the python website:
>>> dict1 =
{ 'a': {'fruit':'apple', 'animal':'aardvark'},
'b': {'fruit':'banana', 'animal':'bear'},}
>>> dict2 = copy.copy(dict1)
>>> dict2['a']['anaimal'] = 'antelope'
>>> print dict1['a']['animal']
'antelope'
# Expected aardvark
>>> dict2 = copy.deepcopy(dict1)
>>> dict2['b']['fruit'] = 'blueberry'
>>> print repr(dict1)
{ 'a': {'fruit':'apple', 'animal':'antelope'},
'b': {'fruit':'banana', 'animal':'bear'},}
>>> print repr(dict2)
{ 'a': {'fruit':'apple', 'animal':'antelope'},
'b': {'fruit':'blueberry', 'animal':'bear'},}