人生苦短,我用Python
缺点
- 运行速度慢
- 代码不能加密(解释型语言)
入门
变量
py变量本身类型不固定,是一门动态语言,一个变量可以被赋值成不同类型。
比如之前为int,后来为string
判断常量类型可以使用isinstance(x, (int, float))
命名规则
- 常量
- 全大写
tips
1 | # output |
变量不需要预先声明类型,在赋值的那一刻被初始化。
字符编码
- UNICODE
- 把所有语言都统一到一套编码里
- 通常2个字节
- 计算机内存中统一使用UNICODE编码,按需进行转换
- ASCII
- 1个字节,通常用来保存英文
- UTF-8
- 英文字符1个字节,中文字符3个字节
- 有一个额外的好处,ASCII编码可以看成是UTF8编码的一部分
list
方括号
有序的集合,可以随时添加和删除其中的元素。 元素可以是任意元素
1 | aList = [1,2,3,4] |
扩展:generator
1 | #列表生成的[]改为() |
Tuple
圆括号,不可更改
1 | # 元组不可以被更改(内容可以) |
字典dict(Map)
大括号
注意key是不可变的(字符串、整数)
1 | aDict = {'host':'earth'} |
set
是一组key的集合,且key不能重复
需要提供一个list作为输入集合,会自动过滤重复项
1 | s = set([1,2,3]) |
Class
1 | class ClassName(base_class[es]): |
slots
可以动态给对象或类绑定属性和方法
slots表示限制对象的属性
1 | class Student(object): |
Enum
1 | # 1 |
metaclass
控制类的创建行为
1 | class ListMetaclass(type): |
标识符
1 | _xxx_ 系统定义、特殊变量,可以被直接饮用 |
build-in func
Func | |
---|---|
operator.eq() | Compare |
str(obj) | get description |
type(obj) | getType |
repr(obj) or. ‘obj’ | 字符串表示 |
ord(char) | 字符的证书表示 |
chr(int) | 整数对应的char |
isinstance(x, str) | 判断前者是不是后者的类型 |
map(func,list) | 将list中的元素通过func进行转换 |
reduce(func,list) | 将list中的元素通过func进行减少 |
filter(func,list) | 根据func指示的布尔值进行过滤,返回Iterator,一般需要list() |
sorted(list,key=func,reverse = bool) | 排序,根据key的大小排序 |
dir() | 一个对象所有的方法 |
函数
1 | # annotation & func |
需要注意,默认参数必须指向不变对象,否则会出现默认参数更改后,之后再次调用函数的默认参数为之前更改过的对象。
懒加载函数
比如不需要立即求和,而是在后面的代码中根据需要再进行计算
注意返回的函数不要引用循环变量,或者后续会发生变化的变量
1 | def lazy_sum(*args): |
匿名函数
1 | lambda x:x*x |
wrapper
函数也有对象,可以拿到属性.
若想在代码运行期间增加功能,称为装饰器。
1 | def log(func): |
偏函数
把一个函数的某个参数固定住
1 | import functools |
编码
- ASCII 英语和数字,一个字节表示一个字符
- Unicode 通常两个字节表示一个字符,特殊符号可能需要四个(Python3)
- UTF-8 把字符编码成1-6个字节,汉字通常3个字节,英文字母1个字节
1 | #!/usr/bin/env python3 |
文件读取
1 | f = open('//','r',encoding='gbk') |
进程
Linux操作系统提供了一个fork()系统调用,调用一次,返回两次,因为操作系统把当前进程赋值了一份,即创建了一个子进程,故而分别在父进程和子进程内返回了。
其中子进程返回0,而父进程返回子进程的id。因为父进程可以fork出很多子进程,所以父进程要记下每个子进程的id,而子进程只需要调用getppid()就可以拿到父进程的ID
1 | import os |
multiprocessing
因为windows没有fork,故而需要一个跨平台的多进程支持库
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动。
join() 方法用于进程间的同步,表示等待子进程结束后再继续往下运行。
1 | from multiprocessing import Process |
pool
大量启动子进程,可以用进程池的方式批量创建子进程
1 | from multiprocessing import Pool |
线程
任何进程默认就会启动一个线程,我们把它称为主线程。
使用threading开启新线程,threading.Thread(target=loop,name=’’)
Lock
多进程中,同一个变量,各自有一份拷贝存在每个进程中,互不影响。而多线程中,所有变量都由线程共享,故而任何一个变量都可以被任何一个线程修改。
1 | lock = threading.Lock() |
Python线程虽然是真正意义上的线程,但是解释器执行代码时,都会有一个GIL锁,
任何Python线程执行前,必须先获得GIL锁,然后执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个全局锁实际上把所有线程的执行代码都给上了锁,所以,即使跑在100核的CPU上,也只能用到1个核
GIL Global Interpreter Lock
Threadlocal
同java中的threadlocal
1 | local_school = threading.local() |
进程和线程比较
多进程稳定性高,一个子进程崩溃了不会影响其他进程。但是创建进程的代价大
多线程速度快一些,但是任何一个线程挂掉都可能直接造成整个代码崩溃,因为所有线程共享进程的内存。比如Windows上的“该程序执行了非法操作,即将关闭”,往往是某个线程出了问题,但是操作系统会强制结束整个进程。
切换是有代价的,多任务一旦多到一个限度,就会消耗掉系统所有的资源,结果效率急剧下降。
- 保存现场(CPU寄存器状态,内存页等)
- 准备新环境(恢复上次的寄存器状态,内存页等)
正则表达式
表达 | 含义 | |
---|---|---|
\d | num | |
\w | 数字 | |
. | 任意一个字符 | |
* | 任意个字符(包括0个) | |
+ | 至少一个字符 | |
? | 0或1个字符 | |
{n} | n个字符 | |
{n,m} | n-m个字符 | |
\s | 空格 | |
[] | 表示范围,比如[0-9a-zA-Z_] | |
\ | 特殊符号需要在前面加\进行转义 | |
A\ | B | A或B |
^ | 行的开头,^\d表示以数字开头 | |
$ | 结尾,\d$表示以数字结尾 |
1 | s = 'ABC\\-001' |
python中的正则匹配采用的是贪婪算法,若需要采用非贪婪算法,需要在后面加一个?
比如\d+?
网络编程
TCP
客户端
1 | import socket |
服务器端
1 | def tcplink(sock, addr): |
UDP
无连接协议,只需要知道对方的IP和端口号,就可以发送数据包,但是无法确认是否到达。
速度快,但传输数据不可靠。
1 | # Server |
数据库
SQLite
轻量级,可嵌入,但是不能承受高并发访问
1 | # 导入SQLite驱动: |
MySQL
为服务器端设计的数据库,能承受高并发访问,占用内存页高
内部有多种数据库引擎,最常用的是支持数据库事务的InnoDB
异步IO
当代码需要执行一个耗时的IO操作时,并不等待IO结果,然后就去执行其他代码了。一段时间后,当IO返回结果时,再通知CPU进行处理
一般采用一个消息循环,主线程不断的重复“读取消息-处理消息”这一过程
1 | loop = get_event_loop() |
Coroutine 协程
Coroutine看上去也是函数,但在执行过程中,可以中断,然后执行别的函数,在适当的时候再回来接着执行。
看起来像多线程,但实际上在同一个线程中运行,运行效率极高,且不需要多线程的锁机制。
Python对coroutine的支持是通过generator实现的。Python的yield不但可以返回一个值,还可以接收调用者发出的参数。
1 | def consumer(): |
asyncio(async await)
asyncio就是一个消息循环,从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
同一个线程并发执行两个coroutine
1 | import threading |