class Gizmo: def __init__(self): print('Gizmo id: %d' % id(self)) x = Gizmo() print(x) y = Gizmo() * 10 print(y) print(dir())
❶ 输出的 Gizmo id: ... 是建立 Gizmo 实例的反作用。
❷ 在乘法运算中使用 Gizmo 实例会抛出异常。
❸ 这里代表,在尝试求积以前其实会建立一个新的 Gizmo 实例。
❹ 可是,确定不会建立变量 y,由于在对赋值语句的右边进行求值时抛出了异常。
longe = {'name': 'longe', 'born': 1993} liang = longe print(liang is longe) print(id(liang), id(longe)) longe['balance'] = 950 print(liang) ## 冒充的longe信息 other = {'name': 'longe', 'born': 1993, 'balance': 950} print(other) print(other is longe)
❶ liang 是 longe 的别名。
❷ is 运算符和 id 函数确认了这一点。
❸ 向 liang 中添加一个元素至关于向 longe 中添加一个元素。html
在那段代码中,liang 和 longe 是别名,即两个变量绑定同一个对象。
而 other 不是 longe 的别名,由于两者绑定的是不一样的对象。pythonother 和longe 绑定的对象具备相同的值(== 比较的就是值),可是它们的标识不一样。
== 运算符比较两个对象的值(对象中保存的数据),而 is 比较对象的标识。算法
元组的不可变性实际上是指 tuple 数据结构的物理内容(即保存的引用)不可变,与引用的对象无关编程
>>> t1 = (1, 2, [30, 40]) ➊ >>> t2 = (1, 2, [30, 40]) ➋ >>> t1 == t2 ➌ True >>> id(t1[-1]) ➍ 4302515784 >>> t1[-1].append(99) ➎ >>> t1 (1, 2, [30, 40, 99]) >>> id(t1[-1]) ➏ 4302515784 >>> t1 == t2 ➐ False
基础理解!!!仍是能够的
>>> l1 = [3, [55, 44], (7, 8, 9)] >>> l2 = list(l1) ➊ >>> l2 [3, [55, 44], (7, 8, 9)] >>> l2 == l1 ➋ True >>> l2 is l1 ➌ False
然而,构造方法或 [:] 作的是浅复制(即复制了最外层容器,副本中的元素是源容器中
元素的引用)。若是全部元素都是不可变的,那么这样没有问题,还能节省内存。缓存
import copy 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) 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(bus2.passengers) print(id(bus1.passengers), id(bus2.passengers), id(bus3.passengers)) print(bus3.passengers)
❸ 审查 passengers 属性后发现,bus1 和 bus2 共享同一个列表对象,由于 bus2 是
bus1 的浅复制副本。
❹ bus3 是 bus1 的深复制副本,所以它的 passengers 属性指代另外一个列表。数据结构
注意,通常来讲,深复制不是件简单的事。若是对象有循环引用,那么这个朴素的算法会进入无限循环
>>> a = [10, 20] >>> b = [a, 30] >>> a.append(b) >>> a [10, 20, [[...], 30]] >>> from copy import deepcopy >>> c = deepcopy(a) >>> c [10, 20, [[...], 30]]
深复制有时可能太深了。例如,对象可能会引用不应复制的外部资源或单例值。咱们能够实现特殊方法 __copy__() 和 __deepcopy__(),控制 copy 和 deepcopy 的行为
共享传参指函数的各个形式参数得到实参中各个引用的副本。也就是说,函数内部的形参
是实参的别名。app
def f(a, b): a += b return a a = [1, 2] b = [3, 4] print(f(a, b)) print(a, b)
这里变量全都是引用,不管局部变量仍是全局.
因此上面案例中,a会变化函数
class HauntedBus: """备受幽灵乘客折磨的校车""" def __init__(self, passengers=[]): #别使用这种可变类型 做为默认参数 self.passengers = passengers
class TwilightBus: """正常的校车""" 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) bus1 = TwilightBus(("sfs", 'sdf')) bus2 = TwilightBus(["sdfsdfsfd111"]) bus1.pick("ppxia") bus1.drop("sfs") print(bus1.passengers) bus2.drop("sdfsdfsfd111") print(bus2.passengers)
尽可能别用可变类型作默认参数值, 实在要用,必须使其产生副本
>>> import weakref >>> s1 = {1, 2, 3} >>> s2 = s1 ➊ >>> def bye(): ➋ ... print('Gone with the wind...') ... >>> ender = weakref.finalize(s1, bye) ➌ >>> ender.alive ➍ True >>> del s1 >>> ender.alive ➎ True >>> s2 = 'spam' ➏ Gone with the wind... >>> ender.alive False
❺ 如前所述,del 不删除对象,而是删除对象的引用。
❻ 从新绑定最后一个引用 s2,让 {1, 2, 3} 没法获取。对象被销毁了,调用了 bye 回
调,ender.alive 的值变成了 False。测试
>>> import weakref >>> a_set = {0, 1} >>> wref = weakref.ref(a_set) ➊ >>> wref <weakref at 0x100637598; to 'set' at 0x100636748> >>> wref() ➋ {0, 1} >>> a_set = {2, 3, 4} ➌ >>> wref() ➍ {0, 1} >>> wref() is None ➎ False >>> wref() is None ➏ True
❷ 调用 wref() 返回的是被引用的对象,{0, 1}。由于这是控制台会话,因此 {0, 1}
会绑定给 _ 变量。
❸ a_set 再也不指代 {0, 1} 集合,所以集合的引用数量减小了。可是 _ 变量仍然指代
它。
❹ 调用 wref() 依旧返回 {0, 1}。
❺ 计算这个表达式时,{0, 1} 存在,所以 wref() 不是 None。可是,随后 _ 绑定到结
果值 False。如今 {0, 1} 没有强引用了。
❻ 由于 {0, 1} 对象不存在了,因此 wref() 返回 None。spa