Python基础

Python基础学习搬运

很乱 !!! 复习时整理

一、关于Python

Python 简介

百度百科:Python

Python的创始人为荷兰人吉多·范罗苏姆 (Guido van Rossum)。1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,作为ABC 语言的一种继承。之所以选中Python(大蟒蛇的意思)作为该编程语言的名字,是取自英国20世纪70年代首播的电视喜剧《蒙提.派森的飞行马戏团》(Monty Python’s Flying Circus)。
ABC是由Guido参加设计的一种教学语言。就Guido本人看来,ABC 这种语言非常优美和强大,是专门为非专业程序员设计的。但是ABC语言并没有成功,究其原因,Guido 认为是其非开放造成的。Guido 决心在Python 中避免这一错误。同时,他还想实现在ABC 中闪现过但未曾实现的东西。
就这样,Python在Guido手中诞生了。可以说,Python是从ABC发展起来,主要受到了Modula-3(另一种相当优美且强大的语言,为小型团体所设计的)的影响。并且结合了Unix shell和C的习惯。

总结:Guido 无聊时开发出 Python! *_*

Python 特点

  • 解释型:无需编译
  • 面向对象
  • 自由度高

Python 安装

查看安装 Python 的版本信息
$ python --version python 2.7 (macOS 自带)
$ python3 --version Python 3.7.4 (安装的 py3k 版本)

Python 解释

  • 交互方式:终端输入python3 出现>>> 即进入交互模式,输入exit()退出或control + c(z)强制退出

  • 脚本方式:.py文件头部一般包含

    1
    2
    #!/usr/bin/env python3   # 告诉系统 Python 脚本可以执行
    # -*- coding: utf-8 -*- # 告诉 Python 按照 UTF-8 读取代码

    记得看权限chmod +x filename.pypython3 filename.py./filename.py

  • IDE工具(排叉、Anaconda)

二、语法基础

开始

  • Python 使用缩进表示代码块,其中约定俗成:4 个空格代替Tab

  • Python 对大小写敏感

  • 空行表示新代码开始

  • '" 完全相同

  • :语句结尾

  • \转义字符: \n换行、\t制表符,还可以使用\实现多行语句

  • 同一行使用多条语句:使用;间隔

  • 终端中:print( )多行字符串输入,输入('''开始,以''')结束

    1
    2
    3
    4
    5
    6
    7
    >>> print('''line1
    ... line2
    ... line3
    ... ''')
    line1
    line2
    line3

注释

  • #:单行注释
  • '''"""包裹:多行注释

保留字

1
2
3
4
5
# 导入 keyword 模块
>>> import keyword
# 查看保留字
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

数字 Number

Python3 支持 int、float、bool、complex(复数)

  • int 只有一种
  • type()可查看类型,type只能查看当前的类型
  • isinstance()判断类型,注意子类是一种父类类型

整数 int

整数只有int类型,表示长整型

1
2
3
4
5
i = 100
# Python 可以多个变量赋值
i = j = 100
# 多个对象指定赋值
i,j, k = 1, 2, 'Hello'

浮点数 float

1
float = 100.0

布尔值 bool

只有TrueFalse两个选项,大小写注意!!!其中TrueFalse的值还是为 1 和 0 ,可以和数值相加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> True and True
True
>>> True or False
True
>>> True and False
False
>>> 1 + 1 == 2 and 1 > 0
True
>>> 1 + 1 != 2 and 1 > 0
False
>>> not True
False
>>> not 1 > 2
True
>>> not 1 +1 = 2 #判断不是赋值!!!
File "<stdin>", line 1
SyntaxError: can't assign to operator
>>> not 1 +1 == 2
False

复数 complex

1 + 2j

空值 None

None为 Python 中的空值,不能理解为 0,因为 0 是有意义的值。

常量

通常用全部大写变量名表示常量,例如PI = 3.14159265359

数据类型转型

引用 runoob:https://www.runoob.com/python3/python3-data-type.html

函数描述
int(x [,base])将x转换为一个整数
float(x)将x转换到一个浮点数
complex(real [,imag])创建一个复数
str(x)将对象 x 转换为字符串
repr(x)将对象 x 转换为表达式字符串
eval(str)用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s)将序列 s 转换为一个元组
list(s)将序列 s 转换为一个列表
set(s)转换为可变集合
dict(d)创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s)转换为不可变集合
chr(x)将一个整数转换为一个字符
ord(x)将一个字符转换为它的整数值
hex(x)将一个整数转换为一个十六进制字符串
oct(x)将一个整数转换为一个八进制字符串

数值运算

  • /表示精确除,为浮点

  • //只取整数部分

  • **表示指数运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 浮点除法
    >>> 10 / 3
    3.3333333333333335
    >>> 9 / 3
    3.0
    # 表示 取整除
    >>> 10 // 3
    3
    # 表示 25次方
    >>> 2 ** 5
    32

运算符优先级

运算符描述
**指数 (最高优先级)
~ + -按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@)
* / % //乘,除,取模和取整除
+ -加法减法
>> <<右移,左移运算符
&位 ‘AND’
^ |位运算符
<= < > >=比较运算符
<> == !=等于运算符
= %= /= //= -= += = *=赋值运算符
is is not身份运算符
in not in成员运算符
not and or逻辑运算符

字符串 str

  • '"包裹 str 等效
  • 索引(从左到右)第一个位置为 0,第二个为 1
  • 索引(从右到左)第一个位置为 -1,第二个为 -2
  • 不能改变
1
2
3
4
5
6
7
8
9
# ord()转字符换为 UTF-8 十进制整数
>>> ord('a')
97
# chr()将 UTF-8 十进制整数转换为字符
>>> chr(97)
'a'
#16进制
>>> '\u4e2d\u6587'
'中文'

使用 ASCII 编码,为bytes字节流

1
2
3
4
>>> 'ABC'.encode('ascii')
b'ABC'
>>> b'ABC'.decode('ascii')
'ABC'

len( )求字符串长度

1
2
3
4
5
6
7
8
9
10
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6
>>> len('中文'.encode('utf-8'))
6
>>> len(b'ABC')
3
>>> len('ABC')
3
>>> len('我的')
2

小黑板

  • 你说str 是不可变的对象?
1
2
3
4
5
6
7
>>> a = 'ABC'
# a.replace('A','a') = 'aBC'实际上是新的一个字符串
>>> a.replace('A','a')
'aBC'
# 可以看出,a 并没有改变
>>> a
'ABC'

格式化

类似 C 语言

1
2
>>> 'Hi, %s, you have $%d.' % ('Ashin', 100) 
'Hi, Ashin, you have $100.'
符号表示
%d整数
%f浮点数
%s字符串
%x十六进制整数
1
2
3
4
5
>>> 'test %x ' % 10000000
'test 989680 '
##
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
  • 有些时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%
1
2
3
4
5
>>> s1 = 72 #小明score1
>>> s2 = 85 #小明score2
>>> r = (s2-s1)/s1*100
>>> print('%s的成绩今年提升了%.2f%%。'%('小明',r))
小明的成绩今年提升了18.06%。

输入和输出

print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> print('i','love','ashin')
# 中间的`,`会变成空格输出
i love ashin
# 100 + 200 = ?
>>> print('100 + 200 =',100 + 200)
100 + 200 = 300
>>>
# 加上 end="" 实现不换行输出,或 end'str'显示不同字符
print(x, end="")
print(y, end="")
>>>
x y
'''
# 计算 n!
'''
n = int(input('n = '))
result = 1
for x in range(1, n + 1):
result *= x
# 注意下面的输出控制方式
print('%d! = %d' % (n, result))

input

1
2
3
4
5
6
>>> name = input()
Ashin
>>> name
'Ashin'
>>> print(name)
Ashin
1
2
3
4
5
6
7
s = input('birth: ')
input()返回的数据类型是 str,注意转型
birth = int(s)
if birth < 2000:
print('00前')
else:
print('00后')
  • 输入是Input,输出是Output,因此,我们把输入输出统称为Input/Output,或者简写为IO。

列表 list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> classmates = ['Ashin', 'Joy', 'Tom']
>>> classmates
['Ashin', 'Joy', 'Tom']
>>> len(classmates)
3
>>> classmates[0]
'Ashin'
>>> classmates[-1]
'Tom'
classmates[-2]
'Joy'
>>> classmates[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
#越界 是 0-2
  • list 是一种有序的集合,其中的元素可修改
  • 元素写在方括号之间,并使用,分隔
  • 索引都是是从 [0] 开始!!!
  • 索引 [-1] 表示倒数第一个,以此类推
1
2
3
4
5
6
7
8
9
10
11
12
13
# append()追加,末尾
>>> classmates.append('Adam')
>>> classmates
['Ashin', 'Joy', 'Tom', 'Adam']
# insert()插入,可加入索引 insert(i,'name')
>>> classmates.insert(0,'Lisa')
>>> classmates
['Lisa', 'Ashin', 'Joy', 'Tom', 'Adam']
# pop()删除末尾,默认推出最后一个,加上索引 pop(i)
>>> classmates.pop()
'Adam'
>>> classmates
['Lisa', 'Ashin', 'Joy', 'Tom']

替换集合中某一个元素,可以直接复制

1
2
3
4
5
6
7
8
9
10
>>> classmates
['Lisa', 'Ashin', 'Joy', 'Tom']
# list 中包含的是基本 number 类型,字符串要用双引号或单引号包裹
>>> classmates[1] = Orange
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'Orange' is not defined
>>> classmates[1] = 'Orange'
>>> classmates
['Lisa', 'Orange', 'Joy', 'Tom']

list里面的元素的数据类型也可以不同,比如:

1
2
3
4
5
6
7
8
9
>>> L = ['Apple', 123, True,['Apple',123,False]]
>>> L
['Apple', 123, True, ['Apple', 123, False]]
>>> len(L)
4
>>> L[3][0]
'Apple'
>>> L[3][2]
False

元组 tuple

  • 元祖-原始的组,一旦元祖元素确定,就无法更改

  • >>> x = (1) 表示整数赋值,因为()·也表示数学计算,通常添加,j解决,如>>> m = (1,)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    >>> t = (1, 2)
    >>> t
    (1, 2)
    >>> t[1]
    2
    # tuple 无法更改
    >>> t[1] = 1
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment
    # 空元祖
    >>> s = ()
    >>> s
    ()
    >>> x = (1)
    >>> x
    1
    # 一个元素
    >>> m = (1,)
    >>> m
    (1,)
  • 下面改变的是元祖中的 list,但 tuple 并未变

    1
    2
    3
    4
    5
    6
    7
    >>> t = ('a', 'b', ['A', 'B'])
    >>> t
    ('a', 'b', ['A', 'B'])
    # 元祖的第三个元素为 list
    >>> t[2][0] = 'X'
    >>> t
    ('a', 'b', ['X', 'B'])

字典 dict

字典 全称 dictionary,在其他语言中也称为 map,使用键-值 key-value存储,查找速度快( hashable type )。

  • 例如使用 list ,当 list 很大时,查找就是从前往后,变得很慢。
1
2
>>> names = ['Mike', 'Tim', 'Jobs']
>>> score = [90, 100, 80]
  • 使用 dict 无论查询那个都会根据索引查找,所以很快

    1
    2
    3
    >>> d = {'Mike': 90, 'Tim': 100, 'Jobs': 80}
    >>> d["Jobs"]
    80
  • 字典的 key 只能对应一个 value,后面的值会冲掉前面的值

1
2
3
4
5
6
>>> d['haha'] = 100
>>> d['haha']
100
>>> d['haha'] = 101
>>> d['haha']
101
  • 判断字典的值是否存在,'haha'是否在d中存在 ( ‘haha’ in d )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> d['haha'] = 101
>>> d['haha']
101
# 元素 in dict-name
>>> 'haha' in d
True
# 使用 get()
>>> d.get('haha')
101
# 当无 value 时,自定义返回 'none',默认不显示
>>> d.get('hahaha','none')
'none'
>>> d.get('haha','none')
101
  • 要删除一个 key,用pop(key)方法,对应的 value 也会从 dict 中删除
1
2
3
4
5
6
7
8
>>> d = {'Mike': 90,'Tim':100,'Jobs':80}
>>> d
{'Mike': 90, 'Tim': 100, 'Jobs': 80}
# 删除 Mike
>>> d.pop('Mike')
90
>>> d
{'Tim': 100, 'Jobs': 80}
  • dict 特点(相比 list)

    1. 占用内存大
    2. 查找、插入速度快(hash 算法)
    3. key 为整数、字符串(在 Python 中不可变)

集合 set

  • set 跟 dict 相似,但是不存 value ,而且 key 唯一
  • 注意 set 跟 list 、dict 、tuple之间的区别
  • 无序不重复
  • 创建空集合,必须使用set()
1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用 {元素1, 元素2, 元素...} 创建 set 
>>> s = {1, 2, 3}
>>> s
{1, 2, 3}
>>> type(s)
<class 'set'>
# 使用 set([]) 创建
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
>>> s = set([1, 2, 3, 3, 3, 3])
>>> s
{1, 2, 3}
  • add( ) 添加 key
1
2
3
>>> s.add(4)
>>> s
{1, 2, 3, 4}
  • remove( ) 删除元素
1
2
3
>>> s.remove(2)
>>> s
{1, 3, 4}
  • set可以看成数学意义上的无序和无重复元素的集合,可以做集合运算
1
2
3
4
5
6
7
8
>>> s1 = set([1, 2, 3])
>>> s2 = set([1, 3, 5])
#进行 与 运算
>>> s1 & s2
{1, 3}
#进行 或 运算
>>> s1 | s2
{1, 2, 3, 5}

条件判断

1
2
3
4
5
6
7
8
if <条件判断1>:
<执行1>
elif <条件判断2>:
<执行2>
elif <条件判断3>:
<执行3>
else:
<执行4>
  • if 判断是从上至下
  • 注意 elif
  • 输入转型

循环

for…in… 循环

1
2
3
4
5
6
7
8
names = ['xiaomi','huawei','apple']
for name in names:
print(name)

>>>
xiaomi
huawei
apple
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sum = 0
# s为变量
for s in [1,2,3,4,5,6,7,8,9,10]:
sum = sum + s
print(sum)
print(sum)
>>>
1
3
6
10
15
21
28
36
45
55
55
1
2
3
4
5
6
7
sum = 0
#range(101)表示产生1-100的整数序列
for x in range(101):
sum = sum + x
print(sum)
>>>
5050

while

1
2
3
4
5
6
7
8
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print(sum)
>>>
2500

break

  • 提前结束循环

continue

  • 结束本次循环,进入下次循环

三、函数基础

调用函数

查看函数使用帮助 help( function )

调用函数,直接使用function( )

函数别名 直接通过变量赋值形式 a = abs

1
2
3
>>> a = abs
>>> a(-100)
100
  • abs( )绝对值转换
  • int( ) float( ) str( ) 数值转型

定义函数

定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。

1
2
3
4
5
6
7
8
9
10
11
12
def 函数名(参数列表):
函数体
# --------------------
# my_abs()为函数名,x 为参数
def my_abs(x):
# 下面是函数体
if x >= 0:
return x
else:
return -x

print(my_abs(-99))

空函数

1
2
def nop():
pass
  • pass 的作用就是直接过

匿名函数

Python 使用 lambda 来创建匿名函数。

1
2
3
4
5
6
7
# 匿名函数
lambda [arg1 [,arg2,.....argn]]:expression
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))
print ("相加后的值为 : ", sum( 20, 20 ))

函数参数

参数检查

TypeError 调用函数出错,抛出提示

1
2
3
4
5
6
7
8
9
10
11
12
def my_abs(x):
# isinstance(x,(int, float)) 进行整数、浮点数检查
if not isinstance(x, (int, float)):
# 如果不是 int float 就抛出 TypeError:bad operand type
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
my_abs('A')

>>> TypeError: bad operand type

返回多个值

  • Pyhotn 返回多个值时采用 tuple 方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import math

    def move(x, y, step, angle = 0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

    x, y = move(100, 100, 60, math.pi / 6)
    r = move(100, 100, 60, math.pi / 6)

    print(x, y)
    print(r)

    >>>
    151.96152422706632 70.0
    (151.96152422706632, 70.0)
  • return时,默认return None

默认参数

def func(参数1,参数2,参数3 = xx): 这样第三个参数默认为 xx 可以不用输入。

  • 默认参数必须指向不变对象

    1
    2
    3
    4
    5
    def add_end( L = None):
    if L is None:
    L = []
    L.append('END')
    return L

可变参数

定义可变参数,在参数前面加了一个*号,参数个数不限制。

1
2
3
4
5
6
7
8
9
10
11
# 多一个* 
def calc(*
):
sum = 0
for n in numbers:
sum = sum + n * n
return sum

>>> num = [1, 2, 3]
# calc(nums)相当于 calc(1, 2, 3)
>>> calc(nums)

关键字参数

1
2
3
4
5
6
7
# 参数装载为 tuple
>>> def person(name, age, **kw):
... print('name', name, 'age', age, 'other', kw)
...
>>> person('ashin', 18)
# 可变参数调用返回一个 dict
name ashin age 18 other {}
  • 如果限制关键字参数的名字,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数

  • *后面的参数如有默认值,则可以不写

  • 可通过 tuple 或 dict调用 func(*args, **kw)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # * 后面的参数名字必须给出
    def person(name, age, *, city, job):
    print(name, age, city, job)

    >>> person('jack',24,beijing,engineering)
    # 参数NameError
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    NameError: name 'beijing' is not defined

    >>> person('jack',24,city = 'beijing', job = 'engineering')
    jack 24 beijing engineering
    -----------------------------------------------------------
    # 默认了 city ,可以省略不写
    >>> def person(name, age, *, city='Beijing', job):
    ... print(name, age, city, job)
    >>> person('jack',18,job = 'Teacher')
    jack 18 Beijing Teacher

参数组合

1
2
3
4
5
6
>>> def f1(a, b, c=0, *args, **kw):
... print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
>>> args = (1, 2, 3, 4)
>>> kw = {'x':100 , 'y': '##'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'x': 100, 'y': '##'}

递归函数

递归函数:一个函数在内部调用自身本身

1
2
3
4
5
# 阶乘Demo,fact()调用自身
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)

四、高级特性

切片 slice

根据索引切片,只包含索引中间的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> L = ['apple', 'orange', 'berry', 'tomato']
>>> L
['apple', 'orange', 'berry', 'tomato']
# [-1::-1] 第一个 -1 代表从右到左,第二个元素(::中间的元素)为空,第三个元素 -1 表示步长为 1 # 且从右到左
>>> L[-1::-1]
['tomato', 'berry', 'orange', 'apple']
# 切[0:2] 就是0-1-2中间的元素
>>> L[0:2]
['apple', 'orange']
>>> L[0:4]
['apple', 'orange', 'berry', 'tomato']
>>> L[3:4]
['tomato']
>>> L[2:3]
['berry']
>>> L[-2]
'berry'
>>> L[-1]
'tomato'

关于索引位置可理解为下图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 生成一个 list[1-100]
>>> L = list(range(100))
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
# 切片取前10
>>> L[:10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 取后10
>>> L[-10:]
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
# 取 11-19
>>> L[11:20]
[11, 12, 13, 14, 15, 16, 17, 18, 19]
# 取 11-20
>>> L[11:21]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
# 取 11-20 间隔 2 位
>>> L[10:21:2]
[10, 12, 14, 16, 18, 20]
>>> L[10:21:1]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
# 取 11-20 间隔 3 位
>>> L[10:21:3]
[10, 13, 16, 19]
# 取整个
>>> L[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
  • tuple 也是一种 list,区别是不可变

    1
    2
    >>> (0, 1, 2, 3, 4, 5)[:3]
    (0, 1, 2)
  • 字符串 也是 list

    1
    2
    >>> 'ABCDEFG'[:3]
    'ABC'

迭代 iteration

给定一个 list 或 tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
>>> d = {'a': 1, 'b': 2, 'c': 3}
# 打印 key
>>> for key in d:
... print(key)
...
a
b
c
# 打印 value
>>> for value in d.values():
... print(value)
...
1
2
3
# 打印key
>>> for key in d.keys():
... print(key)
...
a
b
c
# 打印 item = key + value
>>> for k, v in d.items():
... print(k, v)
...
a 1
b 2
c 3
  • dict 的存储方式跟 list 不太一样,可能出来的顺序不一样

  • 字符串也是可迭代对象

1
2
3
4
5
6
>>> for ch in 'ABC':
... print(ch)
...
A
B
C
  • 判断是否可以实例化,通过 collections 模块的 Iterable 类型判断
1
2
3
4
5
6
7
8
>>> from collections import Iterable
>>> isinstance('abc',Iterable)
True
>>> isinstance('123',Iterable)
True
# 123 为整数
>>> isinstance(123,Iterable)
False
  • 把 list 变成 索引-元素 enumerate
1
2
3
4
5
6
>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2
  • 同时引用两个变量
1
2
3
4
5
>>> for x, y in  [(1, 1), (2, 2)]:
... print(x, y)
...
1 1
2 2

列表生成式 List Comprehensions

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 创建一个 1-9 的 list 
>>> list(range(1, 10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

# 创建一个 1-10 的 list
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 数组[1*1 2*2 3*3 ... 10*10] 写法一
>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 数组[1*1 2*2 3*3 ... 10*10] 写法二
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 数组[1*1 2*2 3*3 ... 10*10 且为偶数]
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

# 两个字符串相加
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

# 查看当前目录下的文件和文件夹 ls
>>> import os
>>> [d for d in os.listdir('.')]
['.config', 'Music', '.DS_Store', 'VirtualBox VMs', '.CFUserTextEncoding', '.sogouinput', 'Pictures', '.pylint.d', '.zprofile', '.zsh_history', 'Desktop', 'Library', '.ShadowsocksX-NG', 'blog', '.bash_sessions', 'Public', '.ssh', 'Movies', 'Applications', '.Trash', '.npm', 'Documents', '.vscode', 'Downloads', '.python_history', '.gitconfig', '.bash_history', '.viminfo']

# lower() 大写换小写
>>> L = ['Hello', 'Ashin']
>>> [s.lower() for s in L]
['hello', 'ashin']

生成器 generator

能一边循环又一边计算,称为生成器:generator

  • 创建 generator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# list 产生方法[]
>>> L = [x * x for x in range(1, 11)]
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# generator 产生方法()
>>> g = (x * x for x in range(11))
>>> g
<generator object <genexpr> at 0x102a068d

# 可使用 next() 打印
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
100

# 当没有元素时,出现 StopIteration
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
  • 使用 for 迭代
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> g = (x * x for  x in range(11))
>>> for n in g:
... print(n)
...
0
1
4
9
16
25
36
49
64
81
100
  • 斐波拉契
1
2
3
4
5
6
7
8
9
10
def  fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
# a = b, b = a + b
a, b = b, a + b
n = n + 1
return 'done'

fib(10)

使用yield 创建 generator,遇到yield就会中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> def odd():
... print('step 1')
... yield 1
... print('step 2')
... yield(3)
... print('step 3')
... yield(5)
...
>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

迭代器 iterator

1
2
3
4
5
6
7
8
9
>>> list=[1,2,3,4]
# 创建迭代器对象
>>> it = iter(list)
# 输出迭代器的下一个元素
>>> print (next(it))
1
>>> print (next(it))
2
>>>

可直接作用于for循环的数据类型有以下几种:

  • 集合数据类型,如listtupledictsetstr

  • generator,包括生成器和带yieldgenerator function

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable,可以使用isinstance()判断一个对象是否是Iterable对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
>>> from collections import Iterable
# 用 isinstance() 判断一个对象是否是Iterator对象
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance((), Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance(100, Iterable)
False
>>> isinstance((x * x for x in range(1, 10)), Iterable)
True

小结

  • 能 for 循环的对象,都是 Iterable (能迭代)类型

  • 能 next( ) 的对象,都是 Iteraor (迭代器)类型

  • 集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象

1
2
3
4
5
6
7
8
9
10
11
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
# [] {} () 不是 Iterator
>>> isinstance([], Iterator)
False
>>> isinstance('abc', Iterator)
False
# 通过 iter( ) 获得 Iterator
>>> isinstance(iter('abc'), Iterator)
True

五、函数式编程

高阶函数 Higher-order function

变量指向函数

1
2
3
4
5
6
7
8
>>> f = abs
>>> f(-1)
1
>>> abs
<built-in function abs>
# f() 和 abs() 一样,相当于给 abs 取别名 f
>>> f
<built-in function abs>

函数名也是变量

传入函数

一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

1
2
3
4
5
>>> def add(x, y, f):
... return f(x) + f(y)
...
>>> add(-5, 6, abs)
11

map

map(function, Iterable) map()函数接收两个参数,一个是函数,一个是Iterablemap将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

1
2
3
4
5
6
7
8
9
>>> def f(x):
... return x * x
...
>>>
# map(f, [])
>>> r = map(f, [1, 2 , 3, 4, 5, 6, 7, 8, 9])
# list(r) 将 r 计算并返还为序列,因为 r 是一个 Iterator
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce

reduce 把一个函数作用在序列上,进行累f( ),如reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

1
2
3
4
5
6
7
>>> from functools import reduce
>>> def add(x, y):
... return x + y
...
# 使用 reduce 进行累加
>>> reduce(add,[1, 3, 5, 7, 9])
25

filter

filter()函数用于过滤序列

1
2
3
4
5
>>> def is_odd(n):
... return n % 2 == 1
...
>>> list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
[1, 5, 9, 15]
  • filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list

sorted

sorted()函数就可以对list进行排序

1
2
3
4
5
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
# 按绝对值大小排列
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
1
2
3
4
5
6
7
8
9
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
# 按照 ASCII 大小排列
['Credit', 'Zoo', 'about', 'bob']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
# str.lower 变成小写再排
['about', 'bob', 'Credit', 'Zoo']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
# 倒序 reverse = True
['Zoo', 'Credit', 'bob', 'about']

返回函数

函数作为返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
>>> def lazy_sum(*args):
... def sum():
... ax = 0
... for n in args:
... ax = ax + n
... return ax
... return sum
...
>>> f = lazy_sum(1, 3, 5, 7, 9)
# lazy_sum( ) 返回一 sum 函数
>>> f
<function lazy_sum.<locals>.sum at 0x10171df80>
# f()
>>> f()
25
# 相同的传入参数
>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1()
25
>>> f2()
25
>>> f1 == f2
False
# f1 返回在0x1017210e0函数
>>> f1
<function lazy_sum.<locals>.sum at 0x1017210e0>
# f2 返回在0x101721050函数
>>> f2
<function lazy_sum.<locals>.sum at 0x101721050>

闭包

匿名函数

不需要显式地定义函数,直接传入匿名函数更方便

1
2
3
# 关键字 lambda 表示匿名函数,冒号前面的 x 表示函数参数
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 匿名函数限制,只能有一个表达式,不用写return,返回值就是该表达式的结果

  • 匿名函数作为返回值

    1
    2
    3
    4
    5
    6
    7
    8
    >>> def build(x, y):
    ... return lambda: x * x + y * y
    ...
    >>> build(5,5)
    <function build.<locals>.<lambda> at 0x101729170>
    >>> f = build(5,5)
    >>> f()
    50

装饰器 decorator

偏函数 Partial function

六、模块

  • 在 Python 中,一个.py文件就称之为一个模块Module
  • 按目录来组织模块的方法,称为包Package
  • \init__.py 包名下必要文件
  • import

使用模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 下面这条语句可让 xxx.py 直接在Unix/Linux/Mac上运行
#!/usr/bin/env python3

# 采用标准的 utf-8 编码
# -*- coding: utf-8 -*-

# 模块文档解释
' a test module '

# 作者信息
__author__ = 'Michael Liao'

# 导入 sys 模块
import sys

def test():
args = sys.argv
if len(args)==1:
print('Hello, world!')
elif len(args)==2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')


# if 测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试
# 如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。
if __name__=='__main__':
test()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
sound/                          顶层包
__init__.py 初始化 sound 包
formats/ 文件格式转换子包
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ 声音效果子包
__init__.py
echo.py
surround.py
reverse.py
...
filters/ filters 子包
__init__.py
equalizer.py
vocoder.py
karaoke.py
...

作用域

  • public: abc

  • private: _abc

安装第三方模块

  • pip install + module.name
  • Anaonda

七、面向对象编程 OOP

面向对象编程——Object Oriented Programming,简称 OOP,是一种程序设计思想。OOP 把对象作为程序的基本单元,一个对象包含了数据操作数据的函数

类和实例

  • 类定义:通过class关键字 ,类名通常是大写,如Classname(object) object表示所有类都会继承的类
  • 创建实例:类名( )
  • __init__(self, , ) 注意前后是两个_ _ 绑定需要的属性
    • __init__(self, , )第一个参数是self 表示创建实例的本身,不需要传递参数,其他绑定的属性需要传递。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 定义类通过 class 关键字
class Student(object):
# 这里是初始化将要创建的实例的属性 __init__(self, , )
def __init__(self, name, score):
self.name = name
self.score = score

# 定义实例需要的分数
def print_score(self):
print('%s:%s' % (self.name, self.score))

# 创建实例 Classname()
tim = Student('Tim Fon', 59)
# 使用实例
tim.print_score()

>>>
Tim Fon:59
>>> tim
# tim 是指向 Student 的实例
<__main__.Student object at 0x1029aea58>
# 可给 tim(实例变量) 绑定一个 name 属性
>>> tim.name
'Tim Fon'

访问限制

  • 私有变量 private:在变量名前添加两个短杆__

继承

  • Class: Subclass, Baseclass,Superclass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 创建Animal类
class Animal(object):
def run(self):
print('Animal is running...')
# 创建 Dog 类并继承 Animal
class Dog(Animal):
pass

class Cat(Animal):
def run(self):
print('Cat is running...')

def eat(self):
print('Eating fish...')

dog = Dog()
# dog 继承 Animal 的 run()
dog.run()

# Cat 覆盖了父类 Animal 的方法 run()
cat = Cat()
cat.run()
cat.eat()

>>>
Animal is running...
Cat is running...
Eating fish...

多态

class 可以理解为数据类型,例如跟str, list, dict 没什么两样。

判断一个变量是否是某个类型可以用isinstance()判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> a = list() # a是list类型
>>> b = Animal() # b是Animal类型
>>> c = Dog() # c是Dog类型
>>> isinstance(a, list)
True
>>> isinstance(b, Animal)
True
>>> isinstance(c, Dog)
True
# Dog 继承 Animal 因为 Dog 是 Animal 的一种
>>> isinstance(c, Animal)
True
# b 是 Animal 是 Dog 的父类,不能倒
>>> isinstance(b, Dog)
False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Animal(object):
def run(self):
print('Animal is running...')
# 定义一个 run_twice()函数
def run_twice(animal):
animal.run()
animal.run()
# 定义一个 Cat 类
class Cat(Animal):
def run(self):
print('Cat is running...')

def eat(self):
print('Eating fish...')
# 定义一个 Tortoise 类
class Tortoise(Animal):
def run(self):
print('Tortoise is running slowly...')

cat = Cat()


run_twice(Animal())
run_twice(Cat())
run_twice(Tortoise())


>>>
Animal is running...
Animal is running...
Cat is running...
Cat is running...
# 继承了 Animal 的 run_twice()方法
Tortoise is running slowly...
Tortoise is running slowly...
  • 开闭原则

    • 对扩展开放:允许新增Animal
    • 对修改封闭:不需要修改依赖Animal类型的run_twice()函数
  • 继承不严格要求

获取对象信息

判断对象类型 type( )

1
2
3
4
5
6
7
8
9
10
11
12
13
# 判断 基本类型
>>> type(123)
<class 'int'>
>>> type('123')
<class 'str'>
>>> type(None)
<class 'NoneType'>
# 判断 函数
>>> type(abs)
<class 'builtin_function_or_method'>
# 判断类
>>> type(dog)
<class '__main__.Dog'>
  • type()函数返回对应的Class类型
1
2
3
4
5
6
7
8
9
10
>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False
  • 判断一个对象,使用types模块 或 isinstance()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用 types 模块
>>> import types
>>> def fn():
... pass
...
# 判断
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
  • 获得一个对象的所有属性和方法,使用dir()
1
2
3
4
5
6
7
8
9
# 返还 str 的所有属性和方法
>>> dir('asd')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
# 类似__xxx__的属性和方法在Python中都是有特殊用途的
>>> len('asd')
3
# 普通方法
>>> 'asd'.upper()
'ASD'
  • getattr()
  • setattr()
  • hasattr()

注意

  • 实用属性 和 类属性 不要同名

使用 __slots__

Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> class Student(object):
# 用tuple定义允许绑定的属性名称
... __slots__ = ('name', 'age')
...
>>> s = Student()
>>> s.name = 'Ashin'
>>> s.age = 18
# score 没有放在 slots 中,所以不能被绑定
>>> s.socore = 100
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'socore'

# slots 对继承的子类无影响
>>> class GoodStudent(Student):
... pass
...
>>> g = GoodStudent()
>>> g.score = 100

使用 @property

多重继承

__str__

__getitem__

__iter__

__getattr__

__call__

定义枚举

通过Enum()实现

type( )

metaclass( )

八、错误、调试、测试

错误处理

try...except...finally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 将可能会出错的代码放置 try 中
try:
print('try...')
r = 10 / 0
print('result:', r)
# 如果执行错误 跳转 except 语句
except ZeroDivisionError as e:
print('except:', e)
# finally 在 except 后执行,若有 一定会被执行,可以不用 fanally 语句
finally:
print('finally...')
print('END')
>>>
try...
except: division by zero
finally...
END
------------------------
# 令 r = 10 / 2
try:
print('try...')
r = 10 / 2
print('result:', r)
except ZeroDivisionError as e:
print('except:', e)
# finally 在 except 后执行,except 不一定执行,若有 finally 一定会被执行,可以不用 fanally
finally:
print('finally...')
print('END')
>>>
try...
result: 5.0
finally...
END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 try:
print('try...')
r = 10 / int('2')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
# 当没有出错时,else 后面的语句会自动执行
else:
print('no error!')
# finally 当然也要
finally:
print('finally...')
print('END')
>>>
try...
result: 5.0
no error!
finally...
END

调用栈

错误没被捕获,会一直向上抛,最后解释器捕获,并打印一个错误,然后退出。

记录错误

内置logging模块,可打印错误,并正常退出。

抛出错误

根据需要定义一个错误的 Class 使用raise抛出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 定义一个错误类 FooError 继承 ValueError
class FooError(ValueError):
pass
def foo(x):
n = int(x)
if n==0:
# 使用 raise 抛出
raise FooError('invalid value: %s' % x)
return 10 / n
foo('0')
>>>
Traceback (most recent call last):
File "err_throw.py", line 11, in <module>
foo('0')
File "err_throw.py", line 8, in foo
raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0
  • rasie 是向上抛错误

调试

使用 print( ) 打印

将可能会出错的地方使用print( )打印出来

断言 assert

使用assert代替print

使用 logging

使用logging代替print

使用 pdb

输入python -m pdb filename.py进入调试

  • 输入 1 查看代码
  • 输入 n 单步执行
  • 输入 p + 变量名 查看变量
  • 输入 q 退出调试

使用pdb.set_trace( )

1
2
3
4
5
6
7
# 导入 pdb 
import pdb
s = '0'
n = int(s)
# 运行到这里会自动暂停,进入调试模式
pdb.set_trace()
print(10 / n)

使用 IDE

  • 排叉 PyCharm
  • VS Code (微软良心)

单元测试

TDD Test Driven Development 测试驱动开发

运行测试

1
2
if __name__ == '__main__':
unittest.main()
  • 加参数 python -m unittest mydict_test

setUp tearDown

文档测试

docktest

九、IO编程

IO: Input/Output 输入和输出

Stream 流

异步IO 同步IO

文件读写

1
2
3
4
5
6
# 使用 open() 打开
>>> f = open('/Users/ashin/Desktop/text.txt','r')
# read() 读写,read() 是一次性读写,注意文件的大小(内存够?)
>>> f.read()
# close() 关闭
>>> f.close

使用 with 语句,不必 try finally ,也不必使用 f.close( )

1
2
with open('/Users/ashin/Desktop/text.txt', 'r') as f:
print(f.read())

二进制文件

1
2
3
4
5
# binary 文件读取,rb 方式打开
>>> f = open('/Users/ashin/Desktop/test.png', 'rb')
>>> f.read()
# 十六进制显示
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x0b@\x00\x00\x07\x08\x08\x06\x00\x00\x00\xaf\xe4@\x15\x00\x00\x0cMiCCPICC Profile\x00\x00H\x89\x95W\x07\\\x93G\x1b\xbfwd\x92\xb0\x02\x11\x90\x11\xf6\x12e\x13@F\x08+\x82\x80LATB\x12H\x181&\x04\x117R\xaa`\xdd"\njE\xab"\x16\xadV@\xeaD\xad\xb3(n\xeb(JQ\xa9\xd4b\x15\x17*\xdfe@\xad\xfd\xc6\xef{

字符编码

1
2
3
4
# 加入 encoding 参数 errors = 'ignore'
>>> f = open('/Users/Ashin/Desktop/text.txt','r',encoding = 'gbk',errors = 'ignore')
>>> f.read()
'浣犲ソ'

写文件

使用w模式(write 覆盖)

使用a模式(append 追加)

f.write('Hello Python!')

StringIO

StringIO 在内存中读写 str

1
2
3
4
5
6
7
8
9
>>> from io import StringIO
# 创建 StringIO
>>> f = StringIO()
# 写入
>>> f.write('Hello StrngIO')
13
# 使用 getvalue() 获得写入的 str
>>> print(f.getvalue())
Hello StrngIO
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> from io import StringIO
# 使用 str 初始化 StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
... s = f.readline()
# '' 结尾
... if s == '':
... break
... print(s.strip())
...
Hello!
Hi!
Goodbye!

BytesIO

内存中二进制文件操作

1
2
3
4
5
6
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'
1
2
3
4
5
>>> from io import BytesIO
# 写入的是 utf-8 编码后的 BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'

环境变量

s.environ 获取环境变量

操作文件和目录

1
2
3
4
5
6
7
8
9
10
# 查看当前绝对路径
>>> os.path.abspath('.')

# 路径表示
>>> os.path.join('/Users/ashin/Desktop/','creatdir')
'/Users/ashin/Desktop/creatdir'
# 创建目录
>>> os.mkdir('/Users/ashin/Desktop/creatdir')
# 删除目录
>>> os.rmdir('/Users/ashin/Desktop/creatdir')

os.path.split() 遍历文件

os.path.splitext() 获取文件后缀名

os.rename() 重命名

os.remove() 删除文件

检索文件 listdir( ) isfile( ) 和splitext( )

1
[x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']

序列化

pickle.dumps( )

pickle.dump( )

pickle.load( )

JSON

JSON XML

JSONPython
objectdict
arraylist
stringstr
number (int)int
number (real)float
trueTrue
falseFalse
nullNone

dumps() 返回的 str 为标准的 JSON

十、进程和线程

多线程

Unix/Linux中 fork( )调用 调用一次,返回两次,子进程返回 0 ,父进程返回 每个子进程的 ID

fork( )

getppid( )

1
2
3
4
5
6
7
8
9
10
11
import os
# 子进程调用getppid()到父进程的ID
print('Process (%s) start...' % os.getpid())
# Only works on Unix/Linux/Mac:
# fork()调用
pid = os.fork()
# 返回两次,子进程返回 0 ,父进程返回子进程的 ID
if pid == 0:
print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
print('I (%s) just created a child process (%s).' % (os.getpid(), pid))

multiprocessing模块 Windows多进程

start( )

join( ) 子进程结束后再继续运行

close( )

Pool 进程池 批量创建子进程

subprocess模块 控制其输入输出

注意:编码问题,Windows中文版 系统编码是GBK,而 Python 的编码我们一般默认为 UTF-8

进程间通信

Process Queue Pipes

ThreadLocal

import threading 再创建ThreadLocal对象

进程和线程

分布式进程

十一、正则表达式

  • 给定字符:精确匹配
  • \d匹配一个数字
  • \w匹配一个字母
  • .匹配任意一个字符
  • *匹配任意个字符
  • \s一个空格(或 Tab)
  • +至少一个字符
  • ?表示 0 个或 1 个字符
  • {n}表示 n 个字符
  • {n,m}表示 n-m 个字符
  • 使用\转义特殊字符

组合起来,例如:\d{3}\s+\d{3,8}

  • \d{3}表示匹配3个数字,例如'010'
  • \s+表示至少有一个空格,例如匹配' '' '
  • d{3,8}表示有3-8个数字

使用[] 表示范围

  • [0-9a-zA-Z\_]可以匹配一个数字、字母、下划线
  • [0-9a-zA-Z\_]+可以匹配至少一个数字、字母、下划线组成的字符串,比如aaa100_ss
  • [a-zA-Z\_][0-9a-zA-Z\_]*字母或下划线开头,后接任意个数字、字母
  • [a-zA-Z\_][0-9a-zA-Z\_]{0 ,19}字母或下划线开头, 后接1-19 个数字、字母(一个 + 后接最多 19 个)
  • A|B 匹配 A 或 B,(P|p)thon可以匹配 Python 和 python
  • ^表示行开头
  • ^\d表示以数字开头
  • $表示行结束
  • \d$表示以数字结束

re 模块

使用r不用考虑 Python 自身的转义

match( ) 匹配检查

切分字符串

1
2
3
4
5
6
7
8
9
10
11
# 按空格切分为数组
>>> 'a b c'.split(' ')
['a', 'b', '', '', 'c']
# 导入 re 模块
>>> import re
# 规范数组
>>> re.split(r'\s+', 'a b c')
['a', 'b', 'c']
# 规范数组 去掉 空格 英文逗号 英文分号
>>> re.split(r'[\s\,\;]+', 'a,b;; c d')
['a', 'b', 'c', 'd']

分组

使用()包裹

例如:^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
>>> m
<re.Match object; span=(0, 9), match='010-12345'>
# 分组查看
>>> m.groups()
('010', '12345')
# group(0)原始字符串为 0
>>> m.group(0)
'010-12345'
# 组(1)
>>> m.group(1)
'010'
# 组(2)
>>> m.group(2)
'12345'

贪婪匹配

1
2
3
4
5
6
# \d+ 会尽量多匹配后面的 0 (默认方式)
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')
# \d+? 尽量少匹配后面的 0,加上 ? 为非贪婪匹配
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')

编译

到一个正则重复很多次,可预编译正则表达式

十二、常用内建模块

“Batteries included” Python 内部集成很多模块

datetime

datetime 时间和日期处理的标准库。

  • 获取当前时间
1
2
3
4
5
6
7
8
9
# datetime 模块包含 datetime 类,如果是 import datetime,引用需要使用全名 datetime.datetime
>>> from datetime import datetime
# datetime.now() 返回当前日期和时间
>>> now = datetime.now()
>>> print(now)
2019-10-22 15:57:31.668157
#
>>> type(now)
<class 'datetime.datetime'>
  • 获取指定日期和时间
1
2
3
4
5
6
# 导入 datetime 类
>>> from datetime import datetime
# 指定时期
>>> dt = datetime(2015, 4, 19, 12, 20)
>>> print(dt)
2015-04-19 12:20:00

timestamp

在计算机当中,时间使用数字表示,把 1970 年 1 月 1 日 00:00:00 UTC+00:00 时区的时刻称为 epoch time,记为0(1970 年以前的时间 timestamp 为负数),当前时间就是相对于 epoch time 的秒数,称为timestamp。

1
2
3
timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
# beijing time
timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> from datetime import datetime
>>> dt = datetime(2015, 4, 19, 12, 20)
>>> print(dt)
2015-04-19 12:20:00
# 把 datetime 转换为 timestamp
>>> dt.timestamp()
# 小数位表示毫秒级
1429417200.0
# 把 timestamp 转换为 datetime,使用 datetime 提供的 fromtimestamp() 方法
>>> tt =1429417200.0
>>> print(datetime.fromtimestamp(tt))
2015-04-19 12:20:00
# 转换为 UTC 时间,默认是系统时区
>>> print(datetime.utcfromtimestamp(tt))
2015-04-19 04:20:00

str 时间

1
2
3
4
5
6
7
8
9
10
# 使用 strptime() 将 str 转换为 datetime,无时区
>>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
>>> print(cday)
2015-06-01 18:19:59

# 使用 strftime() 将 datetime() 转换为 str,可定义格式
# https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
>>> now = datetime.now()
>>> print(now.strftime('%a, %b %d %H:%M'))
Tue, Oct 22 16:23

datetime 加减

1
2
3
4
5
6
7
8
9
10
11
12
# 导入 timedelta 类
>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2019, 10, 22, 21, 16, 10, 149480)
# + 10小时
>>> now + timedelta(hours=10)
datetime.datetime(2019, 10, 23, 7, 16, 10, 149480)
>>> now - timedelta(days=1)
datetime.datetime(2019, 10, 21, 21, 16, 10, 149480)
>>> now + timedelta(days=2, hours=12)
datetime.datetime(2019, 10, 25, 9, 16, 10, 149480)

本地时间转换为UTC时间

1
2
3
4
5
6
7
8
9
10
11
# 导入 datetime, timedelta, timezone
>>> from datetime import datetime, timedelta, timezone
# 设置一个时区为 UTC+8:00
>>> tz_utc_8 = timezone(timedelta(hours=8))
>>> now = datetime.now()
>>> now
datetime.datetime(2019, 10, 22, 21, 20, 5, 973507)
# tzinfo时区属性 默认为None
>>> dt = now.replace(tzinfo=tz_utc_8)
>>> dt
datetime.datetime(2019, 10, 22, 21, 20, 5, 973507, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800)))

时区转换

1
2
3
4
5
6
7
8
9
10
11
12
# utcnow()获取 UTC 时间,并设置为 UTC+0:00
>>> utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
>>> print(utc_dt)
2019-10-22 13:28:05.587079+00:00
# astimezone()将转换时区为北京时间
>>> bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
>>> print(bj_dt)
2019-10-22 21:28:05.587079+08:00
# astimezone()将转换时区为东京时间
>>> tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt)
2019-10-22 22:28:05.587079+09:00

collections

collections是Python内建的一个集合模块,提供了许多有用的集合类。

namedtuple

namedtuple(‘名称’, [属性list])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> from collections import namedtuple
# namedtuple 自定义 tuple 对象,规定 tuple 个数
# namedtuple('名称', [属性list]):
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(3,6)
>>> p.x
3
>>> p.y
6
# 可以验证 Point 就是 tuple 的一种子类
>>> isinstance(p, Point)
True
>>> isinstance(p, tuple)
True

# 当我们尝试传递更多的参数时
>>> pp = Point(3, 4, 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __new__() takes 3 positional arguments but 4 were given
>>> pp = Point(3, 4, 5, 6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __new__() takes 3 positional arguments but 5 were given

deque

list 是线性存储,插入和删除效率低下,使用 deque 可实现高效的插入和删除(队列、栈 双向链表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
# 增加在左边
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])
# popleft() 删除左边第一个
>>> q.popleft()
'y'
>>> q
deque(['a', 'b', 'c', 'x'])
# 删除右边
>>> q.pop()
'x'
>>> q
deque(['a', 'b', 'c'])

defaultdict

使用 defaultdict 构造一个默认值,当引用的 dict-Key不存在时,返回默认值

1
2
3
4
5
6
7
8
9
10
11
>>> from collections import defaultdict
# 构造默认返回值
>>> dd = defaultdict(lambda: 'N/A')
# dd['key1'] = 'abc'
>>> dd['key1'] = 'abc'
>>> dd['key1']
'abc'
>>> dd['key2']
'N/A'
>>> dd['key3']
'N/A'

OrderedDict

dict-Key 是无序的,可使用 OrderedDict 排序(OrderedDict 是按照插入的顺序 )FIFO 先进先出

1
2
3
4
5
6
>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['x'] = 3
>>> od['y'] = 2
>>> list(od.keys())
['z', 'x', 'y']

ChainMap

###Counter

1
2
3
4
5
6
7
8
>>> from collections import Counter
>>> c = Counter()
# 统计 'programming' 中字符出现个数
>>> for ch in 'programming':
... c[ch] = c[ch] + 1
...
>>> c
Counter({'r': 2, 'g': 2, 'm': 2, 'p': 1, 'o': 1, 'a': 1, 'i': 1, 'n': 1})

base64

Base64 是用 64 个字符来表示任意二进制数据,二进制编码

原理:

1
2
#  base64 包含 26 个大写字母,26 个小写字母,10 个数字,+ 和 /
['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

对二进制进行编码,每 3 个字节一组,一共为 3 x 8 = 24 bit,再划分为 4 组,每组 6 bit,n1, n2, n3, n4 通过查表得到对应的字符

若二进制不是 3 的倍数,用\x00字节在末尾补足后,再在编码的末尾加上1个或2个=号,表示补了多少字节,解码的时候,会自动去掉。

1
2
3
4
5
>>> import base64
>>> base64.b64encode(b'binary\00String')
b'YmluYXJ5AFN0cmluZw=='
>>> base64.b64decode(b'YmluYXJ5AFN0cmluZw==')
b'binary\x00String'
  • 在 URl Safe中,把字符+/分别变成-_ (+ / 不能直接作为参数)

  • 在 URL、Cookie 中,=会被自动去掉

hashlib

Python 的 hashlib 提供了常见的摘要算法,如 MD5,SHA1 等等。

摘要算法、哈希算法、散列算法:通过函数把任意长度的数据转换一个长度固定的数据串(通常 16 进制)

md5

MD5 是最常见的摘要算法,速度很快,生成结果是固定的 128 bit 字节,通常用一个 32 位的 16 进制字符串表示。

1
2
3
4
5
6
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
>>>
d26a53750bc40b38b65a520292f69306

SHA1

SHA1的结果是 160 bit 字节,通常用一个 40 位的 16 进制字符串表示。比 SHA1 更安全的算法是 SHA256 和SHA512,不过越安全的算法不仅越慢,而且摘要长度更长。

1
2
3
4
5
6
7
import hashlib
sha1 = hashlib.sha1()
sha1.update('how to use sha1 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())
>>>
2c76b57293ce30acef38d98f6046927161b46a44

HMAC

HMAC:Keyed-Hashing for Message Authentication 在计算哈希的过程中,常常把 Key 混入计算 md5(message + salt)

1
2
3
4
5
6
7
8
>>> import hmac
>>> message = b'Hello, world!'
>>> key = b'secret'
>>> h = hmac.new(key, message, digestmod='MD5')
>>> # 如果消息很长,可以多次调用h.update(msg)
>>> h.hexdigest()
# 与原来的 hash 长度一致
'fa4ee7d173f2d97ee79022d1a7355bcf'

itertools

itertools.count( ) 创建无线迭代器,停不下来

1
2
3
4
5
6
7
8
9
10
>>> import itertools
# count()
>>> natuals = itertools.count(1)
>>> for n in natuals:
... print(n)
...
1
2
3
...

cycle( ) 会把一个序列无限重复

1
2
3
4
5
6
7
8
9
10
11
12
>>> import itertools
>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
>>> for c in cs:
... print(c)
...
'A'
'B'
'C'
'A'
'B'
'C'
..

`repeat()负责把一个元素无限重复下去,不过如果提供第二个参数就可以限定重复次数:

1
2
3
4
5
6
7
>>> ns = itertools.repeat('A', 3)
>>> for n in ns:
... print(n)
...
A
A
A

takewhile()等函数根据条件判断来截取出一个有限的序列:

1
2
3
4
>>> natuals = itertools.count(1)
>>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
>>> list(ns)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

chain

chain( ) 吧一组的迭代对象串联起来,形成一个更大的迭代器

groupby

groupby( ) 找出重复元素

contextlib

urllib

Get

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 导入 request 模块
from urllib import request
# 请求一个 URL,返回响应
with request.urlopen('https://ashin.wang') as f:
data = f.read()
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', data.decode('utf-8'))

>>>
Status: 200 OK
Server: GitHub.com
Content-Type: text/html; charset=utf-8
Strict-Transport-Security: max-age=31556952
Last-Modified: Tue, 22 Oct 2019 15:45:00 GMT
ETag: "5daf23fc-7a60"
Access-Control-Allow-Origin: *
Expires: Wed, 23 Oct 2019 03:23:02 GMT
Cache-Control: max-age=600
X-Proxy-Cache: MISS
X-GitHub-Request-Id: 266C:3E2C:D41CD:117E34:5DAFC53E
Content-Length: 31328
Accept-Ranges: bytes
Date: Wed, 23 Oct 2019 03:13:02 GMT
Via: 1.1 varnish
Age: 0
Connection: close
X-Served-By: cache-hkg17923-HKG
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1571800382.364482,VS0,VE226
Vary: Accept-Encoding
X-Fastly-Request-ID: 07b0570da3a1cb2a1764bef1f3c77013b1192f3b
Data: <!DOCTYPE html><html lang="zh-CN">
...

Post

User-Agent 模拟浏览器

Handler

通过 ProxyHandlder 访问

XML

HTML Parser