1 python 拷贝
深拷贝, 浅拷贝 与引用三者的区别
- import copy
- a = [1, 2, 3, 4, ['a', 'b']] #原始对象
- b = a #赋值, 传对象的引用
- c = copy.copy(a) #对象拷贝, 浅拷贝
- d = copy.deepcopy(a) #对象拷贝, 深拷贝
- a.append(5) #修改对象 a
- a[4].append('c') #修改对象 a 中的 ['a', 'b'] 数组对象
- print('a =', a)
- print( 'b =', b)
- print( 'c =', c)
- print('d =', d)
输出结果:
- a = [1, 2, 3, 4, ['a', 'b', 'c'], 5] #a 执行两次值追加操作
- b = [1, 2, 3, 4, ['a', 'b', 'c'], 5] #赋值是对象的引用, b 指向仍然是 a, 因此与 a 内容保持一致
- c = [1, 2, 3, 4, ['a', 'b', 'c']] #对象的浅拷贝外部 list 重新生成新的空间, 但是嵌套数组的内存地址不变
- d = [1, 2, 3, 4, ['a', 'b']] #深拷贝是所有的数组都新生成一个内存空间, 与原来的脱离关系
2 python 的垃圾回收机制
Python GC 主要使用引用计数 (reference counting) 来跟踪和回收垃圾. 在引用计数的基础上, 通过 "标记 - 清除"(mark and sweep)解决容器对象可能产生的循环引用问题, 通过 "分代回收"(generation collection)以空间换时间的方法提高垃圾回收效率.
1 引用计数
PyObject 是每个对象必有的内容, 其中 ob_refcnt 就是做为引用计数. 当一个对象有新的引用时, 它的 ob_refcnt 就会增加, 当引用它的对象被删除, 它的 ob_refcnt 就会减少. 引用计数为 0 时, 该对象生命就结束了.
优点:
简单
实时性
缺点:
维护引用计数消耗资源
循环引用
2 标记 - 清除机制
基本思路是先按需分配, 等到没有空闲内存的时候从寄存器和程序栈上的引用出发, 遍历以对象为节点, 以引用为边构成的图, 把所有可以访问到的对象打上标记, 然后清扫一遍内存空间, 把所有没标记的对象释放.
3 分代技术
分代回收的整体思想是: 将系统中的所有内存块根据其存活时间划分为不同的集合, 每个集合就成为一个 "代", 垃圾收集频率随着 "代" 的存活时间的增大而减小, 存活时间通常利用经过几次垃圾回收来度量.
Python 默认定义了三代对象集合, 索引数越大, 对象存活时间越长.
举例:
当某些内存块 M 经过了 3 次垃圾收集的清洗之后还存活时, 我们就将内存块 M 划到一个集合 A 中去, 而新分配的内存都划分到集合 B 中去. 当垃圾收集开始工作时, 大多数情况都只对集合 B 进行垃圾回收, 而对集合 A 进行垃圾回收要隔相当长一段时间后才进行, 这就使得垃圾收集机制需要处理的内存少了, 效率自然就提高了. 在这个过程中, 集合 B 中的某些内存块由于存活时间长而会被转移到集合 A 中, 当然, 集合 A 中实际上也存在一些垃圾, 这些垃圾的回收会因为这种分代的机制而被延迟.
3 python 中 is 与 == var 与 let
is 比较的是两者的内存地址 == 基本比较的是两者的数值
is 判定
判定值相等, 内存地址也相等
- a = 10
- b = 10
- a is b
Ture 常用的 1-256 计算机共用一个内存地址
- a = 9999999
- b = 9999999
- a is b
False 数值较大的数类似长整型, 计算机会生成新的内存地址
var 与 let
var 定义的变量可以重新被定义
let 定义的变量不能重新被定义
4 Python 中 read readline readlines
read() 每次读取整个文件, 它通常用于将文件内容放到一个字符串变量中
readline 读取下一行, 使用生成器方法, 返回字符串的对象
readlines 读取整个文件到一个迭代器以供我们遍历
- #read
- f = open("a.txt")
- lines = f.read()
- print(lines)
- print(type(lines))
- f.close()
- # 输出
- # hello
- # python!
- <type 'str'> #字符串类型
- #readline
- f = open("a.txt")
- line = f.readline()
- print(type(line))
- while line:
- print line,
- line = f.readline()
- f.close()
- # 输出
- #<type 'str'>
- <type 'str'> #字符串类型
- # hello
- # python!
- #readlines
- f = open("a.txt")
- lines = f.readlines()
- print(type(lines))
- for line in lines:
- print(line)
- f.close()
# 输出
- <type 'list'>
- # hello
- # python!
5 python2 与 python3 的区别
contents | python3 说明 |
---|---|
print 函数 | python3 打印带括号 |
整除 | / 可以得到浮点数 |
Unicode | Unicode (utf-8) 字符串 |
xrange 模块 | 统一使用 range, 并新增__contains__ |
Raising exceptions/Handling exceptions | raise 与 as 关键字 |
next() 函数 | 只保留 next(), .next() 抛出属性异常 |
for 循环 | for 循环变量不会再导致命名空间泄漏 |
比较不可排序类型 | python 不支持不同类型的比较 |
输入 input | 只允许 input, 取消了 raw_input |
6 Python 必须学会的 super
(1) super() 继承方法
在类的继承中, 如果重定义某个方法, 该方法会覆盖父类的同名方法, 但有时, 我们希望能同时实现父类的功能, 这时, 我们就需要调用父类的方法了, 可通过使用 super 来实现
- class Animal(object): #Animal 为父类
- def __init__(self, name):
- self.name = name
- def greet(self):
- print 'Hello, I am %s.' % self.name
- class Dog(Animal): #Dog 为子类
- def greet(self): #Dog 重定义了 greet 方法并继承了父类的方法
- super(Dog, self).greet() # Python3 可使用 super().greet()
- print 'WangWang...'
- >>> dog = Dog('dog') #实例化
- >>> dog.greet() #调用 greet 方法
Hello, I am dog.
WangWang..
(2) super 初始化
super 的一个最常见用法可以说是在子类中调用父类的初始化方法
- class Base(object):
- def __init__(self, a, b):
- self.a = a
- self.b = b
- class A(Base):
- def __init__(self, a, b, c):
- super(A, self).__init__(a, b) # 初始化子类继承父类 super(子类名, self).__init__(父类参数)
- self.c = c
Python3 可使用
super().__init__(a, b)
, 这样子类继承父类的属性的同时, 有保持了自身独有的属性.
(3) 深入 super
super 其实与父类没有实质的关联
- class Base(object):
- def __init__(self):
- print "enter Base"
- print "leave Base"
- class A(Base): #继承 base
- def __init__(self):
- print "enter A"
- super(A, self).__init__()
- print "leave A"
- class B(Base): #继承 base
- def __init__(self):
- print "enter B"
- super(B, self).__init__()
- print "leave B"
- class C(A, B): #多重继承自 A,B
- def __init__(self):
- print "enter C"
- super(C, self).__init__() #super 第一个参数可以是继承链中任意类名字
- print "leave C"
- # 输出
- >>> c = C()
- enter C
- enter A
- enter B
- enter Base
- leave Base
- leave B
- leave A
- leave C
按我们的理解, enter A 下面输出应该是基类 base 中 enter base, 为什么是 enter B ?? 原因是 super 跟父类没有什么关联, 因此执行的顺序是 A-->B-->Base
执行过程是:
初始化 C()时, 先会去调用 A 的构造方法中的
super(A, self).__init__()
, super(A, self)返回当前类的继承顺序中 A 后的一个类 B; 然后再执行
super(B,self).__init()__
, 这样顺序执行下去.
super 方法可以看出: super()的第一个参数可以是继承链中任意一个类的名字,
1 如果是本身就会依次继承下一个类;
2 如果是继承链里之前的类便会无限递归下去;
3 如果是继承链里之后的类便会忽略继承链汇总本身和传入类之间的类;
来源: https://www.cnblogs.com/why957/p/9207016.html