Monday, January 6, 2014

Python Trivia

Any command you can run in the terminal window can be run inside IPython when you start the command with !

Shallow copy means copying references and deep copy implies copying the complete contents of an object (roughly speaking). The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):
  • shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

 A trailing comma would turn an expression into a one-tuple and "()" would represent a zero-tuple.  it is the commas, not the parentheses, that define the tuple

Like Jave, Python uses automatic garbage collection, releasing objects whose reference count is zero.


Lists and References:

Creating Lists

Python creates a single new list every time you execute the [] expression. No more, no less. And Python never creates a new list if you assign a list to a variable.
A = B = [] # both names will point to the same list

A = []
B = A # both names will point to the same list

A = []; B = [] # independent lists
Note that the for-in statement maintains an internal index, which is incremented for each loop iteration. This means that if you modify the list you’re looping over, the indexes will get out of sync, and you may end up skipping over items, or process the same item multiple times. To work around this, you can loop over a copy of the list:
    for object in L[:]:
        if not condition:
            del L[index]
Alternatively, you can use create a new list, and append to it:
    out = []
    for object in L:
        if condition:
            out.append(object)
>>> l1=range(3)
>>> l2=range(20,23)
>>> l3=range(30,33)
>>> l1[len(l1):]=[l2]    # equivalent to 'append' for subscriptable sequences 
>>> l1[len(l1):]=l3      # same as 'extend'
>>> l1
[0, 1, 2, [20, 21, 22], 30, 31, 32]
By putting the list constructor around l2 in l1[len(l1):]=[l2], or calling l.append(l2), you create a reference that is bound to l2. If you change l2, the references will show the change as well. The length of that in the list is a single element -- the reference to the appended sequence.

With no constructor shortcut as in l1[len(l1):]=l3you are making a true (shallow) copy of the elements in l3.

So here, changing the element of l2 will change corresponding "list" element of l1, and vice versa. Changing the element of l3 will not changing the corresponding element in l1, and changing corresponding element in l1 will not change the element in l3, because "extend" works using a shallow copy and the elements in l3 is immutable.

>>> l1=range(3)
>>> l2=range(20,23)
>>> l3=[l2]
>>> l1[len(l1):]=l3      # same as 'extend'
>>> l1
In this case, however, changing the element in each of the lists will change the corresponding element in the others, because even for a shallow copy, references are stored because the corresponding elements are mutable (a list).

The list object consists of two internal parts; one object header, and one separately allocated array of object references. The latter is reallocated as necessary.
The list has the following performance characteristics:
  • The list object stores pointers to objects, not the actual objects themselves. The size of a list in memory depends on the number of objects in the list, not the size of the objects.
  • The time needed to get or set an individual item is constant, no matter what the size of the list is (also known as “O(1)” behaviour).
  • The time needed to append an item to the list is “amortized constant”; whenever the list needs to allocate more memory, it allocates room for a few items more than it actually needs, to avoid having to reallocate on each call (this assumes that the memory allocator is fast; for huge lists, the allocation overhead may push the behaviour towards O(n*n)).
  • The time needed to insert an item depends on the size of the list, or more exactly, how many items that are to the right of the inserted item (O(n)). In other words, inserting items at the end is fast, but inserting items at the beginning can be relatively slow, if the list is large.
  • The time needed to remove an item is about the same as the time needed to insert an item at the same location; removing items at the end is fast, removing items at the beginning is slow.
  • The time needed to reverse a list is proportional to the list size (O(n)).
  • The time needed to sort a list varies; the worst case is O(n log n), but typical cases are often a lot better than that.


No comments:

Post a Comment