Python_audition笔记
with的用法,上下文管理器。一般打开文件用,打开文件在进行读写时可能会出现异常状况,如果不用with自己要
try,except,finally。with实现了finally中的f.close
用来处理可变参数
*args被打包成tuple
**kwargs被打包成dict
def print_all(a,*args,**kwargs):
print(a)
if args:
print(args)
if kwargs:
print(kwargs)
print_all("hello", "world", "amber", name="amberli")
控制台输出结果:
hello
('world', 'amber')
{'name': 'amberli'}
print_all(*["a",'b','c'],**{"name":"amberli","age":30})
控制台输出结果:
a
('b', 'c')
{'name': 'amberli', 'age': 30}
不可变对象:bool/int/float/tuple/str/frozenset
可变对象:list/set/dict
frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素
set(可变集合)与frozenset(不可变集合)的区别:
set无序排序且不重复,是可变的,有add(),remove()等方法,既然是可变的,所以不存在哈希值
frozenset是冻结的集合,是不可变的,存在哈希值,好处是可以作为字典的key,也可以作为其他集合的元素
缺点是一旦创建便不能更改,没有add,remove方法
set()和frozenset()工厂函数分别用来生成可变和不可变的集合,如果不提供任何参数默认会生成空集合。
如果提供一个参数,则参数必须是可迭代的,即,一个序列,或迭代器,或支持迭代的一个对象,例如一个列表或一个字典。
enumerate()函数用于将一个可遍历的数据对象(如列表、元祖或字符串)组合为一个索引序列,同时列出数据和数据下标,
一般用在for循环当中。
>>> e = enumerate("amberli")
>>> for i, v in e:
... print(i,v)
...
0 a
1 m
2 b
3 e
4 r
5 l
6 i
>>>
如何自定义自己的异常?为什么需要定义自己的异常?
* 继承Exception实现自定义异常
* 给异常加上一些附加信息
* 处理一些业务相关的特定异常(raise MyException)
class MyException(Exception):
pass
try:
...
raise MyException("my exception")
except MyException as e:
print(e)
GIL: Global Interpreter Lock
Cpython解释器的内存管理并不是线程安全的
保护多线程情况下对python对象的访问
Cpython使用简单的锁机制避免多个线程同时执行字节码
GIL的影响:
限制了程序的多核执行
同一个时间只能有一个线程执行字节码
CPU密集程序难以利用多核优势
IO期间会释放GIL,对IO密集程序影响不大
如何避免GIL影响:
区分CPU和IO密集程序
CPU密集可以使用多进程+进程池
IO密集使用多线程/协程
cpython扩展
为何有了GIL还要关注线程安全
python中什么操作才是原子的?一步到位执行完
一个操作如果是一个字节码指令可以完成就是原子的
原子的是可以保证线程安全的
使用dis操作来分析字节码
以加锁的方式确保线程安全:
不加锁后:
import threading
n = [0]
def foo():
n[0] = n[0] + 1
n[0] = n[0] + 1
threads = []
for i in range(5000):
t = threading.Thread(target=foo)
threads.append(t)
for t in threads:
t.start()
print(n) # 不一定为10000
加锁:
import threading
lock = threading.Lock() # 以加锁的方式确保线程安全
n = [0]
def foo