Every Python object has a type, identity, and value.
The builtin function type()
returns a type
object.
The builtin function id()
returns the object's identity (an integer).
Value is kind of vague, though.
print 1, type(1), id(1)
foo = range(10)
print foo, type(foo), id(foo)
import sys
print sys, type(sys), id(sys)
def bar():
pass
print bar, type(bar), id(bar)
1 <type 'int'> 4299197592 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <type 'list'> 4415085312 <module 'sys' (built-in)> <type 'module'> 4297509808 <function bar at 0x10728b320> <type 'function'> 4415075104
Think of an object's value as any and all of its attributes. For example, anything you'd type self.
to get at from inside if you wrote the class yourself.
Most custom classes are mutable. To create a simple immutable class, try using a namedtuple
. Otherwise you can raise a TypeError
from __setattr__
to make your own immutable type.
You can't change their values.
The value of x
is the same before and after foo
is called.
x = some_immutable
foo(x)
print x
This is kind of like pass-by-value.
Immutable objects include numbers, strings, tuples.
def add_one(bar):
bar += 1
b = 5
print b, id(b)
add_one(b)
print b, id(b)
5 4299197496 5 4299197496
You can change their values.
The value of y
may be different after foo
is called.
y = some_mutable
foo(y)
print y
This is kind of like pass-by-reference.
Mutable objects include lists, dictionaries, etc.
def reverse_list(foo):
foo.reverse()
a = range(10)
print a, id(a)
reverse_list(a)
print a, id(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 4415096664 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 4415096664
It's pretty easy to change the value of a number variable...
foo = 42
print foo
foo += 1
print foo
foo = 42
print foo
42 43 42
The assignment operator doesn't change the value of an object, it changes its identity.
foo = 42
print foo, id(foo)
foo += 1
print foo, id(foo)
foo = "bar"
print foo, id(foo)
42 4299198584 43 4299198560 bar 4381029040
If you have an immutable container (e.g. a tuple) that holds mutable objects (e.g. lists), you can still mutate the contained objects without mutating the container.
A = ([],[],[])
print A, id(A[0]), id(A)
A[0].append(5)
print A, id(A[0]), id(A)
A[1] = [5]
([], [], []) 4414903504 4414893984 ([5], [], []) 4414903504 4414893984
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-171-868c79a8f9fc> in <module>() 3 A[0].append(5) 4 print A, id(A[0]), id(A) ----> 5 A[1] = [5] TypeError: 'tuple' object does not support item assignment
Mostly you don't have to think about this stuff, but sometimes you do.
def my_appending_function(element, initial_list=[]):
# do some stuff
initial_list.append(element)
return initial_list
print my_appending_function((1,2,3,5), range(2))
print my_appending_function(10)
print my_appending_function(5)
[0, 1, (1, 2, 3, 5)] [10] [10, 5]
These are defined once when the function is defined. This is a result of def
being an executable statement that binds the name of the function to the function object. All this has something to do with Python functions being "first class" objects.
So...instead of this:
def my_appending_function(element, initial_list=[]):
# do some stuff
initial_list.append(element)
return initial_list
Do this:
def my_appending_function(element, initial_list=None):
if initial_list is None:
initial_list = []
# do some stuff
initial_list.append(element)
return initial_list
Now it does what you (may have) expected:
def my_appending_function(number, initial_list=None):
if initial_list is None:
initial_list = []
# do some stuff
initial_list.append(number)
return initial_list
print my_appending_function(10)
print my_appending_function(5)
print my_appending_function(10)
print my_appending_function(5)
[10] [5] [10] [5]