写这篇笔记的缘由,首先想系统地学习一下 python,之前也片段地学了下,每次用起的时候,都不太想得起具体的用法,要搜索很久。同时,个人感觉教程内容有点杂,于是总结了下方便查阅,也加深一下印象。
Python 基础
输入和输出
输出
- print(),加引号输出字符串,不加输出变量或计算结果
遇到,
输出一个空格,print('The quick brown fox','jumps over','the lazy dog')
输入
- input(),可在加上输入提示参数
数据类型和变量,基本运算
数据类型
整数
浮点数
字符串
r''
表示''
内的字符默认不转义'''...'''
表示多行内容,直接换行,不用\n
布尔值: True 和 False
空值:None,不能理解为0
变量
- 必须由大小写字母,数字和下划线组成,且不能以数字开头
基本运算
/
除法,精确的,10 / 3 = 3.333333333//
地板除,两个整数的地板除仍为整数, 10 // 3 = 3
字符串和编码
Python字符串
Python 3 字符串以 Unicode 编码
ord()
获取字符的整数表示,chr()
将编码转换成对应字符网络或磁盘上传输的是字节流类型 bytes
encode()
将字符串转换成指定编码的 bytes'中文'.encode('utf-8')
decode()
将 bytes 转换成指定编码的数据,传入errors='ignore'
忽略无法解码的字节b'\xe4\xb8\xad\xff'.decode('utf-8',errors='ignore')
len()
计算字符数,如果传入 bytes ,计算字节数使 Python 解释器以指定编码读取源代码
1
2
# -*- coding: utf-8 -*-
格式化
%
对应%d, %f, %s, %x(十六进制整数)
'Hi, %s,you have $%d' % ('Michael', 10000)
;输出单个%
用%%
format()
'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.25)
f-strings
list 和 tuple
list 列表
[]
包裹,classmates = ['Michael', 'Bob', 'Tracy']
len()
获取 list 元素个数使用索引访问元素,
-1
获取最后一个元素append()
,将元素将元素追加到末尾insert()
插到索引号为 1 的位置:classmates.insert(1, 'Jack')
pop(i)
删除指定位置的元素直接给元素赋值替换元素
tuple 元组
- 一旦初始化就不能改变
- 使用索引访问元素
- 无
append()
,insert()
方法 - 只有一个元素时添加
,
消除歧义t = (1,)
list 和 tuple 区别
- list 可变,tuple 不可变
条件判断
if
,else
后面都有:
else if
可用elif
替代
循环
for .. in 循环,
for name in names:
range()
生成整数序列while 循环
continue,break
dict 和 set
dict 字典
{}
包裹,names = {'Michael': 95, 'Bob': 70, 'Tracy': 85}
判断 key 存在
1、in
判断是否存在;'Thomas' in names
2、get()
方法,不存在返回None
或者指定的 value ;names.get('Thomas', -1)
pop(key)
删除 key ,对应 value 也删除;names.pop('Bob')
存放顺序和 key 放入的顺序无关,用空间换取时间
作为 key 的对象不可变,如字符串,整数
set
- 和 dict 类似,key 的集合,不存储 value,没有重复的 key
- 创建 set,需提供一个 list 作为输入集合;
s = set([1, 2, 3])
- 重复元素自动被过滤
add(key)
添加元素,重复添加没有效果;s.add(4)
remove(key)
删除元素;s.remove()4
- set 可做交集,并集操作;
s1 & s2
,s1 | s2
不可变对象
- 调用自身任意方法,也不会改变对象自身的内容
函数
调用函数
查看函数的名称和参数
python 官方文档:https://docs.python.org/3/library/functions.html
通过help()
查看;help(abs)
参数数量,类型不对,会报
TypeError
错误
定义函数
def + 函数名 + 参数名 + 冒号;
def my_abs(x):
定义空函数:pass
1
2def nop():
pass
函数参数
位置参数:普通参数,调用函数时按照位置顺序依次赋值
默认参数
在函数中设定默认参数值,调用时可以不写默认参数的值:
1 | def power(x, n=2): |
必选参数在前,默认参数在后,默认参数中变化大的参数在前,变化小的在后
多个默认参数时,改变其中某个参数,指明参数名
1 | def student(name, gender, age=6, city='Beijing'): |
默认参数大坑,须指向不变对象
可变参数:
*param
传入参数,得到 list
函数定义:1
2
3
4
5def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum调用函数:
1
calc(1, 2, 3)
传入一个 list 或 tuple(元组),前加
*
,*nums
表示把nums
这个 list 的所有元素作为可变参数传进去:1
calc(*nums)
关键字参数:
**kw
传入参数,得到 dict
函数定义:1
2def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)调用函数:
1
2>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}传入一个 dict,前加
**
,**extra
表示把extra
这个 dict 的所有 key-value 传进去1
2
3'city': 'Beijing', 'job': 'Engineer'} > extra = {
'Jack', 24, **extra) > person(
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}命名关键字参数
限制关键字参数的名字,添加分隔符*
,*
之后的为命名关键字参数
函数定义:1
2def person(name, age, *, city, job)
print(name, age, city, job)函数调用
1
2>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer已有可变参数,后面命名关键字参数不需要特殊分隔符:
1
2def person(name, age, *args, city, job):
print(name, age, args, city, job)命名关键字参数可以有默认值
递归函数
- 函数里调用函数自身
高级特征
切片
L[0:3]
表示从索引 0 开始,直到索引 3 结束,不包括索引 3索引是 0 可以省略,
L[:3]
'abcdef'[1::2]
从索引 1 开始每隔 2 个取 1 个负索引也生效
迭代
for ... in
迭代 dict ,d 是 dict,
for key in d
迭代的是 key 。若要迭代 value ,for value in d.values()
。同时迭代 key 和 value,for d,v in d.items()
判断是否可迭代对象,通过 collections 模块的 iterable 类型判断
1
2
3
4
5
6
7from collections import Iterable
'abc', Iterable) # str是否可迭代 isinstance(
True
1,2,3], Iterable) # list是否可迭代 isinstance([
True
123, Iterable) # 整数是否可迭代 isinstance(
Falseenumerate()
函数同时迭代索引和元素本身:1
2
3
4
5
6>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2 C
列表生成式
List Conprehensions
生成的列表中的内容 + for 迭代生成[1x1, 2x2, 3x3, …, 10x10]
1
2>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]也可采用循环方式
1
2
3
4
5
6>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]加上判断,筛选出偶数的平方
1
2>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]两层循环,生成全排列
1
2>>> [m + n for m in 'ABC' for n in 'DEF']
['AD', 'AE', 'AF', 'BD', 'BE', 'BF', 'CD', 'CE', 'CF']可调用列表生成内容的方法
把 list 中所有字符串转换成小写1
2
3'Hello', 'World', 'IBM', 'Apple'] > L = [
> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
生成器(generator)
节省空间,一边循环一边计算
第一种方法,将列表生成器中
[]
改成()
1
2
3
4
5
6>>> L = [x * x for x in range(1, 11)]
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> g = (x * x for x in range(1, 11))
>>> g
<generator object <genexpr> at 0x0512BE68>next()
函数获取 generator 的下一个返回值,没有更多元素时,抛出 StopIteration 错误,一般采用迭代的方式获取1
2
3
4> next(g)
1
> next(g)
4geneterator 生成斐波拉契数列
1
2
3
4
5
6
7def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'函数遇到 return 返回,变成 generator 的函数,每次调用
next()
的时候执行,遇到yield
返回,再次执行从上次返回的yield
语句继续执行。
迭代器
nop
函数式编程
nop
模块
一个 .py 文件为一个模块
将函数分组到模块中,提高代码可维护性
通过包名解决模块名冲突的问题
包名.模块名mycompany.abc
使用模块
- 模块示列
1 | #!/usr/bin/env python3 |
第四行为模块文档注释,任何模块第一个字符串都被视为文档注释
第六行用 __author__
变量写入作者名字
if __name__=='__main__'
用于测试模块功能
- 作用域
正常函数和变量名是公开(public)的,如:abc
,x123
__xxx__
为特殊变量,可以被引用,有特殊函数_xxx
和__xxx
为非公开的(private)
安装第三方模块
python -m pip install xxx
面向对象编程
类和实例
1 | class Student(object): |
类名后括号内为继承的类,默认为 object
构造函数
def __init__(self, name, score)
第一个参数为self
操作类的属性self.name
内部函数
def print_score(self)
第一个参数为self
实例化对象直接调用构造函数,不需要 new
访问限制
__
两个下划线开头,私有变量,不能访问,实际名字改变,如__name
改成了_Student__name
,不同 python 版本处理方式不同
_
单下划线开头看做私有变量私有变量采用 get 和 set 方法 可检查传入参数
继承和多态
被继承的 class 称为基类,父类,或超类(Base class,Super class),继承的 class 称为 子类 (subclass)
用
isinstance()
判断变量是否某个类型1
2>>> isinstance(a, list)
True子类计时父类型又是子类型,父类不是子类型
获取对象信息
type()
获取对象类型isinstance()
判断对象是否属于某个类型dir()
获取对象的所有属性和方法,__xxx__
的是特殊的属性和方法getattr()
获取属性或方法,setattr()
设置属性或方法,hasattr()
判断属性或方法是否存在
实例属性和类属性
- 实例属性优先级高于类属性
错误,调试和测试
错误处理
使用返回错误代码的方式,繁琐,调试不方便
try...except...finally
错误处理机制,try 可能出错的代码1
2
3
4
5
6
7
8
9try:
print('try...')
r = 10/0
print('result=', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')执行
r = 10/0
捕获到ZeroDivisionError
,不再执行try
中之后语句
执行except
语句
执行finally
语句
继续执行剩下语句设置多个
except
语句块捕获多种不同类型的语句
错误类型也是 class ,存在子类父类,except 父类错误时也将子类’一网打尽’了
所有错误从BaseException
类派生
常见错误类型和错误关系:https://docs.python.org/3/library/exceptions.html#exception-hierarchy
如果没有捕获到错误可加一个
else
语句,没有错误发生,执行 else 中语句finally
语句不管错误是否发生,最后都会执行调用栈:错误的跟踪信息,异常栈
1
2
3
4
5
6
7
8
9
10
11$ python3 err.py
Traceback (most recent call last):
File "err.py", line 11, in <module>
main()
File "err.py", line 9, in main
bar('0')
File "err.py", line 6, in bar
return foo(s) * 2
File "err.py", line 3, in foo
return 10 / int(s)
ZeroDivisionError: division by zero使用
logging
记录错误信息raise
抛出错误
调试
- 断言:
assert
1 | def foo(s): |
assert 断言失败,抛出 AssertionError
,python 解释器参数 -o
关闭 assert
- logging
控制语句输出到不同的地方,比如 console 和文件
1 | import logging |
pdb
python -m pdb err.py
1
查看代码n
单布执行代码p 变量名
查看变量q
结束调试
程序中pdb.set_trace()
设置断点,命令c
继续执行IDE调试
pycharm
单元测试
nop
文档测试
nop
IO编程
数据的输入(input)输出(output)
分为同步和异步,区别为是否等待IO执行的结果,等待的为同步IO
文件读写
现代操作系统不允许普通的程序直接操作磁盘,读写文件请求操作系统打开一个文件对象
读文件
1.open()
函数传入文件名和标识符 f = open('test.txt', 'r')
2.read()
一次读取文件的全部内容;read(size)
每次最多读取 size 个字节的内容;readline()
每次读取一行内容;readlines()
读取所有内容并返回 list
3.close()
文件使用完后必须关闭
4.使用 try..finally
确保使用完正确关闭文件,使用 with
语句自动调用 close()
方法
1 | with open('test.txt', 'r') as f: |
5.二进制文件采用标志符 rb
打开
6.encoding
设置读取文件的编码方式,errors
设置遇到编码错误后的处理方式f = open('text.txt', 'r', encoding='gbk', errors='ignore')
- 写文件
1.传入标识符 'w'
,'wb'
写文本文件或二进制文件
2.wtite()
写入文件
3.务必使用 colose()
关闭文件,确保数据全部写入磁盘。写文件时,不是立即写入磁盘,而是在内存中缓存起来,空闲的时候再写。
4.'w'
如果文件已存在,会直接覆盖,'a'
以追加的模式写入
标识符含义:https://docs.python.org/3/library/functions.html#open
- fire-like object
有read()
方法
StringIO 和 BytesIO
在内存中读写 str 和 byte
getvalue()
获取写入后的值
StringIO:
1 | > from io import StringIO |
1 | from io import StringIO |
BytesIO:
1 | > from io import BytesIO |
1 | >>> from io import BytesIO |
操作文件和目录
os.name
获取操作系统类型,os.uname()
获取系统详细信息(uname 在 windows 下不支持)posix
: Linux、Unix 或 Mac OS Xnt
: Windowsos.environ
操作系统中的环境变量os.environ.get('path')
获取 path 变量的值操作文件和目录的函数一部分在
os
,一部分在os.path
os.rname('text.txt', 'text.py')
文件重命名os.remove('test.py')
删除文件os.path.abspath('.')
绝对路径os.mkdir('/Users/michael/testdir')
创建目录os.rmdir('/Users/michael/testdir')
删除目录
合成路径使用os.path.join()
能正确处理不同操作系统的分隔符shutil
模块的copyfile()
函数复制文件os.path.listdir('.')
列出该文件夹下的所有子一级文件夹和文件
实现 dir -l
功能:
1 | import os,time |
序列化
pickle
模块实现序列化
1.pick.dumps()
将对象序列化成 bytes 对象,或将对象序列化成 bytes 后写入文件
1 | d = dict(name='Bob', age=20, score=88) |
2.pick.load()
从 bytes 中反序列化出对象,或者直接从 file-like obgect 中反序列
1 | with open('dump.txt', 'rb') as f: |
- JSON 和 python 内置对象的转换
dumps()
将 python 对象变成 JSON ,dump()
直接将 JSON 写入file-like object
loads()
将 JSON 字符串反序列化,load()
从file-like object
中读取并序列化
进程和线程
对于操作系统来说,一个任务就是一个进程(Process)
进程内的‘子任务’称为线程(Thread),线程是最小的执行单元,每个进程至少由一个线程组成。
多进程
nop
- Unix/Linux 下,
fork()
调用多进程 - windows 使用跨平台
multiprocessing
模块实现多进程 Queue
,Pipes
实现进程间通信
正则表达式
\d
一个数字\w
一个数字或者字母.
任意字符\s
一个空格(包含 Tab 等空白符)*
任意个数+
至少一个?
0个或者一个{n}
n 个字符{n,m}
n-m 个字符^
开头,$
结尾A|B
匹配 A 或 B[]
表示范围;[0-9a-zA-Z\_]
特殊字符需用\
转义,比如下划线_
re 模块
直接用match()
方法1
re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
预编译之后再用
match()
1
2
3
4
5
6r'^(\d{3})-(\d{3,8})$') re_telephone = re.compile(
# 使用:
'010-12345').groups() re_telephone.match(
('010', '12345')
'010-8086').groups() re_telephone.match(
('010', '8086')()
包裹的为要返回的分组(Group),group()
返回某一个,或groups()
返回全部group(0)
匹配的原始字符串,group(1)
第一个()
内
常用内建模块
datetime
nop
collections
nop
base64
用 64 个字符表示任意二进制数据的编码
3 个字节一组,划分为 4 个 6 bit,查表替换
少于 3 字节的用
\00
补足,编码末尾加上一个或者两个=
,表示补了多少字节编码后的长度一定是 4 的倍数,补足用
=
补足编码
base64.b64encode(b'abc')
解码
base64.b64decode(b'YWJjZA==')
struct
解决 bytes 和其他二进制数据类型的转换
halib
摘要算法:将任意长度的数据转换成固定长度的数据串
- md5
生成固定 128 bit,用 32 个十六进制数表示
数据块很大,可以分块调用update()
,结果一样hexdigest()
十六进制摘要
使用加盐(salt)的方法加强保护
1 | import hashlib |
- sha1
生成固定 160 bit,用 40 个十六进制数表示
1 | import hashlib |
- sha256,sha512
hmac(Keyed-Hashing for Message Authentication)
hash 加盐
itertools
操作迭代函数
图形界面
支持的图形界面的第三方库
TK,wxWidgets,Qt,GTK
#网络编程
TCP/IP 简介
IP 协议
标识互联网上计算机
按块发送,不保证到达,也不保证按顺序到达
IPv4,32 位整数:192.168.0.1
IPV6,128 位整数:2001:0db8:85a3:0042:1000:8a2e:0370:7334
(8 个 4 位 16进制,:
隔开)TCP
建立在 IP 之上
可靠连接,保证顺序到达
HTTP 协议, SMTP 协议建立在 TCP 之上端口
用于进程间通信
小于 1024 的是 internet 标准服务的端口
常见端口号:80
Web 服务21
FTP25
SMTP
TCP编程
socket 通常表示打开了一个网络连接,打开一个 socket 需要知道目标地址的 ip,端口号,再指定协议类型
客户端
导入 socket 库
import socket
创建基于 TCP 的 socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
AF_INET
IPV4,AF_INET6
IPV6SOCK_STREAM
使用面向流的协议 TCP连接
s.connect(('www.sina.com', 80))
使用 tuple(元组),指明域名和端口号发送数据
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
recv(max)
,接收数据,max
指明最大接收字节
服务端
绑定端口
s.bind('127.0.0.1', 9999)
监听,指定等待连接的最大数量
s.listen(5)
server.py
1 | import socket |
client.py
1 | import socket |
UDP 编程
- 面向无连接的协议,不需要建立连接,只需要知道 IP 和端口号就可直接发送数据包
电子邮件
MUA(Mail User Agent) —— 邮件用户代理
MTA(Mail Transfer Agent) —— 邮件传输代理
MDA(Mail Delivery Agent) —— 邮件投递代理
电子邮件流程
1 | 发件人 -> MUA -> MTA -> 若干MTA -> MDA <- MUA <- 收件人 |
发邮件,MUA 和 MTA 使用 SMTP(Simple Mail Transfer Protocol)
收邮件,MDA 和 MUA 使用 POP:Post Office Protocol,目前版本是3,俗称POP3;IMAP:Internet Message Access Protocol,目前版本是4 两种协议
SMTP 发送邮件
模块 email
构造邮件,smtp
发送邮件
POP3收取邮件
nop
Web开发
nop
异步 IO
nop