变量不是盒子
Python变量就像Java的引用变量。Python变量应该当成是对象的标签
定义,相等,别名
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | charles = {'name': 'Charles L. Dodgson', 'born': 1832}
  lewis = charles print(lewis is charles)
  print(id(charles), id(lewis))
  lewis['balance'] = 950 print(charles)
  alex = {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950} print(alex == charles) print(alex is charles)
 
  | 
 
charles和lewis引用的是相同的对象 
alex对象的内容与charles相同,但不是引用相同的对象,Python的==,比较的是对象的属相。is操作符比较的是对象的id,对象的id是创建时就确定了,永远不会改变了。 
==和is
==操作符比较对象的值
判断对象是否为None,更合理的方式是
is操作符速度比==快,因为它不能被重载,因此Python不用寻找特殊的方法来计算它。只需要简单的比较它们的id就可以了。对于a==b,其实背后使用的是a.__eq__(b),__eq__是从Object继承用于比较对象的id,因此效果和is一样.但是很多内置的类型重载了__eq__,做了更多的操作比较对象属性的值。因此==可能会产生额外的计算。
Tuple相对不可修改
元组跟大多数的Python的集合–lists,dicts,sets一样,都是持有对象们的引用。如果引用类型和修改,那么元组自身不可修改,而内部条目可以修改。
1 2 3 4 5 6 7
   | t1 = (1, 2, [30, 40]) t2 = (1, 2, [30, 40]) print(t1 == t2) print(id(t1[-1])) t1[-1].append(99) print(t1) print(t1 == t2)
   | 
 
t1是不可修改的,t[-1]可修改 
t1和t2的内容一样。修改t2的条目的内容,这个时候t1和t2不相同了 
默认浅拷贝
1 2 3 4 5 6 7
   | l1 = [3, [55, 44], (7, 8, 9)] l2 = list(l1) print(l2) print(l1 == l2) print(l1 is l2)
  l3 = l1[:]
   | 
 
l2由l1拷贝,值相等,但对象不相同 
l3由l1拷贝 
- 两种方式的拷贝都属于浅拷贝。
 
1 2 3 4 5 6 7 8 9 10
   | l1 = [3, [66, 55, 44], (7, 8, 9)] l2 = list(l1) l1.append(100) l1[1].remove(55) print('l1:', l1) print('l2:', l2) l2[1] += [33, 22] l2[2] += (10, 11) print('l1:', l1) print('l2:', l2)
   | 
 
l2是l1的浅拷贝。l1[1]移除55。这也会影响到l2 
任意对象的深浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   |  class Bus:     def __init__(self, passengers=None):         if passengers is None:             self.passengers = []         else:             self.passengers = list(passengers)
      def pick(self, name):         self.passengers.append(name)
      def drop(self, name):         self.passengers.remove(name)
 
  import copy
  bus1 = Bus(['Alice', 'Bill', 'Claire', 'David']) bus2 = copy.copy(bus1) bus3 = copy.deepcopy(bus1)
  print(id(bus1), id(bus2), id(bus3))
  bus1.drop('Bill') print(bus1.passengers) print(bus2.passengers) print(id(bus1.passengers), id(bus2.passengers), id(bus3.passengers)) print(bus3.passengers)
 
 
  | 
 
bus2是bus1的浅拷贝,bus3是bus1的深拷贝 
删除和垃圾回收
del表达式仅删除名字,不会删除对象。执行del表达式之后,对象可能会被回收。但只有在删除了最后一个引用对象的变量,才会被回收掉。CPython垃圾回收的基本算法是引用计数。CPython2.0,引入了新的垃圾回收算法,可以删除循环引用的对象组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | s1 = {1, 2, 3} s2 = s1
 
  def bye():     print('Gone with the wind')
 
  ender = weakref.finalize(s1, bye) print(ender.alive) del s1 print(ender.alive) s2 = 'spam' print(ender.alive)
 
  | 
 
s1,s2指向相同的对象 
- 使用
weakref来监控s1的状态 
- 执行
del s1,对象还被s2引用没有被回收 
- 改变
s2的引用,这个时候对象被回收 
弱引用
弱引用不增加引用计数。弱引用不阻止垃圾回收
1 2 3 4 5 6 7 8 9 10
   | a_set = {0, 1} wref = weakref.ref(a_set) print(wref) print(wref())
  a_set = {2, 3, 4} print(wref()) print(wref() is None) print(wref() is None)
 
  | 
 
WeakValueDictionary
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   |  class Cheese:     def __init__(self, kind):         self.kind = kind
      def __repr__(self):         return 'Cheese(%r)' % self.kind
 
  import weakref
  stock = weakref.WeakKeyDictionary() catalog = [Cheese('Red Leicester'), Cheese('Tilsit'), Cheese('Brie'), Cheese('Parmesan')]
  for cheese in catalog:     stock[cheese.kind] = cheese
  print(sorted(stock.keys()))
  del catalog print(stock.keys()) del cheese print(sorted(stock.keys()))
 
 
  | 
 
弱引用的限制
不是所有的Python对象都能使用弱引用。基本list和dict都不能被引用。但它们的纯净子类可以。Set也可以