Others have explained the problem and suggested using l=None
and an explicit test for it. I'd like to suggest a different approach:
class Bar(object):
def __init__(self, l=[]):
self.l = list(l)
# and so on...
This guarantees a new blank list each time by default, and also assures that if a caller passes in a list of their own, you get a copy of that list rather than a reference to the caller's list. As an added benefit, callers can pass in anything that the list constructor can consume, such as a tuple or a string, and your code doesn't have to worry about that; it can just deal with a list.
If you just save a reference to the list the caller gives you, and later change the list named self.l
, you may be inadvertently changing the list that was passed in, too (since both your class and the caller now have a reference to the same object). Similarly, if they change the list after calling your constructor, your "copy" will be changed too (since it's not actually a copy). Of course, it could be that this is behavior you want, but probably not in this case.
Although if you never manipulate the list (i.e. add, replace, or delete items), but only refer to it or replace it wholesale, copying it is usually a waste of time and memory.
The copy made using the list()
constructor is shallow. That is, the list itself is a new object, but if the original list contains references to mutable objects (such as other lists or dictionaries, or instances of most other classes), the same problem can arise if you change those objects, because they are still shared between the lists. This is an issue less frequently than you might think, but if it is, you can perform a deep copy using the deepcopy()
function in the copy
module.