1. 对象是在内存中实实在在的,在内存中有一个地址存放他的内容的。
  2. 引用可以理解成对这个对象的地址,或者这个对象的名字

python中有一句话是“python中一切都是对象”,整数在python中是一个整数对象。整数相当于java中的Integer类,而不是int。
a = 1 // 1是对象,a是这个对象的引用

在python中有两个运算符 == 和 is,前者用于比较对象的值,后者用于比较两个对象是不是同一个

例子:

““

a=1000 
 b=1000 
 a == b 
 True 
 a is b 
 Falseid(a) 
 140524223738936 
 id(b) 
 140524223738984 
 id(1000) 
 140524223738864
点评: 
a指向一个对象1000 ,b指向另外一个对象1000
a 和 b 值相等,但是两者不是同一个对象的引用
创建了两个对象1000,
通过id()可以获取一个对象在内存中地址

““

例子:

““

a=1000 
 b=a 
 a == b 
 True 
 a is b 
 True 
 id(a) 
 140524223738864 
 id(b) 
 140524223738864 
 id(1000) 
 140524223738960
点评:
第二步将a赋值给b,实际效果相当于b和a同时指向同一个对象1000,因此id(a)和id(b)相等,a is b 返回True

““

例子:

““

a=2 
 b=2 
 a == b 
 True 
 a is b 
 True 
 id(a) 
 140524220614464 
 id(b) 
 140524220614464 
 id(2) 
 140524220614464a=”a” 
 b=”a” 
 id(a) 
 4471174648 
 id(b) 
 4471174648 
 id(“a”) 
 4471174648
点评:
    对于[-5,255]内的整数和单字符的字符串在python启动的时候就会创建好对象,因此a=2和b=2实际都只有一个对象2(节省了内存申请和释放的开销)
    对于大整数都是实时创建和销毁的,如果要长期保存大整数会有内存问题,事实上python中整数对象池是只增不减的。如果代码运行到某一时刻同时存在成千上万的整数对象,那么之后即使不用了,内存也会居高不下,这点在数值计算时需要特别注意
    上面一个例子中id(1000)和id(a)不同,代表a=1000创建了2个对象,分配了2块内存,一个是1000,另一个是指向对象1000的引用a。
    而本例中从id(a)和id(2)相同,why???

““

例子:容器里的对象
python中存放的一切对象都是引用。

((1111,2222,3333),(4444,5555,6666)) 
这个元祖在内存中布局是:
    1. 整体上这是一个元祖,里面的两个元素也都是元祖,因此内存中会有2个内存块存放这两个元祖的地址
    2. 每一个元祖元素又包含3个整数对象,因此会有3个内存块存放三个整数对象的引用,另外还会有3个内存块存放整数对象本身

例子:extend和+=的区别

- 区别1:
>>> import dis
>>> def f1():
...     l1+=[2]
...
>>> dis.dis(f1)
  2           0 LOAD_FAST                0 (l1)
          3 LOAD_CONST               1 (2)
          6 BUILD_LIST               1
          9 INPLACE_ADD
         10 STORE_FAST               0 (l1)
         13 LOAD_CONST               0 (None)
         16 RETURN_VALUE
>>>

>>> def f2():
...     l1.extend([2])
...
>>> dis.dis(f2)
2           0 LOAD_GLOBAL              0 (l1)
          3 LOAD_ATTR                1 (extend)
          6 LOAD_CONST               1 (2)
          9 BUILD_LIST               1
         12 CALL_FUNCTION            1
         15 POP_TOP
         16 LOAD_CONST               0 (None)
         19 RETURN_VALUE
>>>

- 共同点:
>>> l1=[]
>>> l1+=t1
>>> l1
[1, 2, 3]
>>> l1.extend(t1)
>>> l1
[1, 2, 3, 1, 2, 3]

说明:
1. dis模块可以将python代码反编译出来,写成类似汇编指令的形式。
2. += 是个内置的运算操作,extend是个函数,涉及到函数查找,入栈出栈,前者效率更高些
3. +=和extend达到的效果一样,都是对list的本地延伸,后面被+=的对象或者extend的参数只要可以遍历即可,不一定是list,可以是tuple等

例子:不可变对象

>>> t=(1,2)
>>> id(t)
4553455016
>>> t2=(3,)
>>> t+=t2
>>> t
(1, 2, 3)
>>> id(t)
4553522144
>>>


1. python中不可变对象只有: int ,float,str,tuple,complex。
2. 要想改变这些对象只有新建一个新的对象,将引用指向新的对象,实际原来的对象本身并没有改变。因此当使用tuple来做需要经常改变内容的数组,会造成很大的效率问题
3. 不能对不可变对象的元素进行赋值,如下:
>>> t[0]=5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>>
4. 字典的key值是必须是不可变对象,
>>> l=[]
>>> t=(1,)
>>> d={t:"123"}
>>> d={l:"123"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

例子:

>>> t=(1)
>>> type(t)
<type 'int'>
>>> t=(1,)
>>> type(t)
<type 'tuple'>

说明:
    只有一个元素的tuple,该元素后要加一个逗号,否则就是个整数类型,而不是tuple

例子:

>>> l=[[]]*9
>>> l
[[], [], [], [], [], [], [], [], []]
>>> l=[[]]*9
>>> l
[[], [], [], [], [], [], [], [], []]
>>> l[0].append(1)
>>> l
[[1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> l[1].append(2)
>>> l
[[1, 2], [1, 2], [1, 2], [1, 2], [1, 2], [1, 2], [1, 2], [1, 2], [1, 2]]
>>>

说明:
1、 l中的每个元素都是list,因此都是引用,*9实际是将第一个元素的引用复制了9次。因此改变了l[0],大家都变了
2. python中对象的赋值,传递都是引用的传递赋值。除非使用copy库中的接口,可以强制指定复制
3. [[]]*9 等价于 :
    l=[]
    t=[]
    for i in xrange(9):
        l.append(t)
    要想实现9个不同的空列表,可以这样:
    l=[]
    for i in xrange(9):
        l.append([])   //每次都会创建一个新的[]
    简写成:[[] for i in xrange(9)]


4. 
>>> l=[[]]
>>> id(l)
4553610736
>>> l=l*10   //赋值操作意味着两件事儿,new一个对象,
>>> id(l)
4553611312
>>> l=[[]]
>>> id(l)
4553610088
>>> l *= 10
>>> id(l)
4553610088
>>>

*= 操作 id不变,

例子:

>>> def f(a,L=[]):
...     L.append(a)
...     print L
...
>>> f(1)
[1]
>>> f(2)
[1, 2]
>>>

说明:
L的默认值是和f绑定在一起的,每次调用f的时候都用L来引用,这个列表是在建立f的时候创建的。
python在碰到def时,会将下面的“代码对象”关联到函数名的引用。
每次执行的时候只是将L引用到这个对象,并不会重新建立一个新的列表然后将引用赋给L

例子:

def f(g): 
 … g() 
 … 
 def h(): 
 … print “I am h” 
 … 
 f(h) 
 I am h
说明:
函数def和变量赋值本质上没有任何区别。函数f就是对一个函数对象的引用,跟a=1是表示a对对象1的引用一样。
因此可以执行g=f,通过g()来调用f(),另外函数对象也可以像其他对象一样作为参数传递