python基础

摘要

python能做什么

  • web开发
1
2
3
4
5
6
django
pyramid
tornado
bottle
flask
webpy
  • 网络编程
1
2
3
4
twisted
requests
scrapy
paramiko
  • 科学计算
1
2
3
4
numpy
scipy
pandas
ipython
  • gui图形开发
1
2
3
wxpython
pyqt
kivy
  • 运维自动化
1
2
3
4
openstack
saltstack
ansible
蓝鲸

其他

  • 枚举 enumerate
  • 元组是只读列表
  • 字符串不能修改,只能给变量重新赋值
  • eval(),字符串转字典
  • functools.wraps使装饰器不会对原本的函数造成影响
  • 高阶函数:传入参数有函数,返回的时候用到这个传入的函数参数

Python基础

解释器

执行 python /home/dev/hello.py 时,明确的指出 hello.py 脚本由 python 解释器来执行。

如果想要类似于执行shell脚本一样执行python脚本,例: ./hello.py ,那么就需要在 hello.py 文件的头部指定解释器,如下:

1
2
3
#!/usr/bin/env python
print "hello,world"

如此一来,执行: ./hello.py 即可。

ps:执行前需给予 hello.py 执行权限,chmod 755 hello.py

内容编码

python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill)

ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言,其最多只能用 8 位来表示(一个字节),即:2**8 = 256,所以,ASCII码最多只能表示 256 个符号。

显然ASCII码无法将世界上的各种文字和符号全部表示,所以,就需要新出一种可以代表所有字符和符号的编码,即:Unicode

Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,规定虽有的字符和符号最少由 16 位来表示(2个字节),即:2 **16 = 65536,
注:此处说的的是最少2个字节,可能更多

UTF-8,是对Unicode编码的压缩和优化,他不再使用最少使用2个字节,而是将所有的字符和符号进行分类:ascii码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存…

所以,python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill),如果是如下代码的话:

报错:ascii码无法表示中文

1
2
3
#!/usr/bin/env python
print "你好,世界"

改正:应该显示的告诉python解释器,用什么编码来执行源代码,即:

1
2
3
4
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print "你好,世界"

字符编码

python2

  • py2里默认编码是ascii
  • 文件开头那个编码声明是告诉解释这个代码的程序 以什么编码格式 把这段代码读入到内存,因为到了内存里,这段代码其实是以bytes二进制格式存的,不过即使是2进制流,也可以按不同的编码格式转成2进制流,你懂么?
  • 如果在文件头声明了#_*_coding:utf-8_*_就可以写中文了, 不声明的话,python在处理这段代码时按ascii,显然会出错, 加了这个声明后,里面的代码就全是utf-8格式了
  • 在有#_*_coding:utf-8_*_的情况下,你在声明变量如果写成name=u”大保健”,那这个字符就是unicode格式,不加这个u,那你声明的字符串就是utf-8格式
  • utf-8 to gbk怎么转,utf8先decode成unicode,再encode成gbk

python3

  • py3里默认文件编码就是utf-8,所以可以直接写中文,也不需要文件头声明编码了,干的漂亮
  • 你声明的变量默认是unicode编码,不是utf-8, 因为默认即是unicode了(不像在py2里,你想直接声明成unicode还得在变量前加个u), 此时你想转成gbk的话,直接your_str.encode(“gbk”)即可以
  • 但py3里,你在your_str.encode(“gbk”)时,感觉好像还加了一个动作,就是就是encode的数据变成了bytes里,我擦,这是怎么个情况,因为在py3里,str and bytes做了明确的区分,你可以理解为bytes就是2进制流,你会说,我看到的不是010101这样的2进制呀, 那是因为python为了让你能对数据进行操作而在内存级别又帮你做了一层封装,否则让你直接看到一堆2进制,你能看出哪个字符对应哪段2进制么?什么?自己换算,得了吧,你连超过2位数的数字加减运算都费劲,还还是省省心吧。
  • 那你说,在py2里好像也有bytes呀,是的,不过py2里的bytes只是对str做了个别名(python2里的str就是bytes, py3里的str是unicode),没有像py3一样给你显示的多出来一层封装,但其实其内部还是封装了的。 这么讲吧, 无论是2还是三, 从硬盘到内存,数据格式都是 010101二进制到–>b’\xe4\xbd\xa0\xe5\xa5\xbd’ bytes类型-->按照指定编码转成你能看懂的文字

编码应用比较多的场景应该是爬虫了,互联网上很多网站用的编码格式很杂,虽然整体趋向都变成utf-8,但现在还是很杂,所以爬网页时就需要你进行各种编码的转换,不过生活正在变美好,期待一个不需要转码的世界。

注释

  • 当行注视:# 被注释内容
  • 多行注释:””” 被注释内容 “””

执行脚本传入参数

Python有大量的模块,从而使得开发Python程序非常简洁。类库有包括三中:

  • Python内部提供的模块
  • 业内开源的模块
  • 程序员自己开发的模块

Python内部提供一个 sys 的模块,其中的 sys.argv 用来捕获执行执行python脚本时传入的参数

pyc 文件

执行Python代码时,如果导入了其他的 .py 文件,那么,执行过程中会自动生成一个与其同名的 .pyc 文件,该文件就是Python解释器编译之后产生的字节码。

ps:代码经过编译可以产生字节码;字节码通过反编译也可以得到代码。

变量

声明变量

1
2
3
4
5
#!/usr/bin/env python
# -*- coding: utf-8 -*-
name = "xxxx"
上述代码声明了一个变量,变量名为: name,变量name的值为:"xxxx"

变量的作用

昵称,其代指内存里某个地址中保存的内容

变量定义的规则

  • 变量名只能是 字母、数字或下划线的任意组合
  • 变量名的第一个字符不能是数字
  • 以下关键字不能声明为变量名
1
['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']

作用域

对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用。

1
2
3
if 1==1:
name = 'xxx'
print name

下面的结论对吗?

  • 外层变量,可以被内层变量使用
  • 内层变量,无法被外层变量使用

三元运算

1
result = 值1 if 条件 else2
  • 如果条件为真:result = 值1
  • 如果条件为假:result = 值2

进制

  • 二进制,01
  • 八进制,01234567
  • 十进制,0123456789
  • 十六进制,0123456789ABCDEF

数据类型

数字

1
2
3
4
2 是一个整数的例子。
长整数 不过是大一些的整数。
3.23和52.3E-4是浮点数的例子。E标记表示10的幂。在这里,52.3E-4表示52.3 * 10-4。
(-5+4j)和(2.3-4.6j)是复数的例子。

int(整型)

  • 在32位机器上,整数的位数为32位,取值范围为-231~231-1,即-2147483648~2147483647
  • 在64位系统上,整数的位数为64位,取值范围为-263~263-1,即-9223372036854775808~9223372036854775807

long(长整型)

跟C语言不同,Python的长整数没有指定位宽,即:Python没有限制长整数数值的大小,但实际上由于机器内存有限,我们使用的长整数数值不可能无限大。

注意,自从Python2.2起,如果整数发生溢出,Python会自动将整数数据转换为长整数,所以如今在长整数数据后面不加字母L也不会导致严重后果了。

float(浮点型)

浮点数用来处理实数,即带有小数的数字。类似于C语言中的double类型,占8个字节(64位),其中52位表示底,11位表示指数,剩下的一位表示符号。

complex(复数)

复数由实数部分和虚数部分组成,一般形式为x+yj,其中的x是复数的实数部分,y是复数的虚数部分,这里的x和y都是实数。

注:Python中存在小数字池:-5 ~ 257

布尔值

  • 真或假
  • 1 或 0

字符串

“hello world”

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
name.capitalize() 首字母大写
name.casefold() 大写全部变小写
name.center(50,"-") 输出 '---------------------Alex Li----------------------'
name.count('lex') 统计 lex出现次数
name.encode() 将字符串编码成bytes格式
name.endswith("Li") 判断字符串是否以 Li结尾
"Alex\tLi".expandtabs(10) 输出'Alex Li', 将\t转换成多长的空格
name.find('A') 查找A,找到返回其索引, 找不到返回-1
format :
>>> msg = "my name is {}, and age is {}"
>>> msg.format("alex",22)
'my name is alex, and age is 22'
>>> msg = "my name is {1}, and age is {0}"
>>> msg.format("alex",22)
'my name is 22, and age is alex'
>>> msg = "my name is {name}, and age is {age}"
>>> msg.format(age=22,name="ale")
'my name is ale, and age is 22'
format_map
>>> msg.format_map({'name':'alex','age':22})
'my name is alex, and age is 22'
msg.index('a') 返回a所在字符串的索引
'9aA'.isalnum() True
'9'.isdigit() 是否整数
name.isnumeric
name.isprintable
name.isspace
name.istitle
name.isupper
"|".join(['alex','jack','rain'])
'alex|jack|rain'
maketrans
>>> intab = "aeiou" #This is the string having actual characters.
>>> outtab = "12345" #This is the string having corresponding mapping character
>>> trantab = str.maketrans(intab, outtab)
>>>
>>> str = "this is string example....wow!!!"
>>> str.translate(trantab)
'th3s 3s str3ng 2x1mpl2....w4w!!!'
msg.partition('is') 输出 ('my name ', 'is', ' {name}, and age is {age}')
>>> "alex li, chinese name is lijie".replace("li","LI",1)
'alex LI, chinese name is lijie'
msg.swapcase 大小写互换
>>> msg.zfill(40)
'00000my name is {name}, and age is {age}'
>>> n4.ljust(40,"-")
'Hello 2orld-----------------------------'
>>> n4.rjust(40,"-")
'-----------------------------Hello 2orld'
>>> b="ddefdsdff_哈哈"
>>> b.isidentifier() #检测一段字符串可否被当作标志符,即是否符合变量命名规则
True

万恶的字符串拼接:

python中的字符串在C语言中体现为是一个字符数组,每次创建字符串时候需要在内存中开辟一块连续的空,并且一旦需要修改字符串的话,就需要再次开辟空间,万恶的+号每出现一次就会在内从中重新开辟一块空间。

列表

创建列表:

1
2
3
name_list = ['alex', 'seven', 'eric']
name_list = list(['alex', 'seven', 'eric'])

基本操作:

  • 索引
  • 切片
  • 追加
  • 删除
  • 长度
  • 切片
  • 循环
  • 包含

元祖

创建元祖:

1
2
3
ages = (11, 22, 33, 44, 55)
ages = tuple((11, 22, 33, 44, 55))

基本操作:

  • 索引
  • 切片
  • 循环
  • 长度
  • 包含

字典(无序)

创建字典:

1
2
3
person = {"name": "mr.wu", 'age': 18}
person = dict({"name": "mr.wu", 'age': 18})

常用操作:

  • 索引
  • 新增
  • 删除
  • 键、值、键值对
  • 循环
  • 长度

PS:循环,range,continue 和 break

运算

http://www.runoob.com/python/python-operators.html

集合

  • 去重
  • 关系测试(交集、差集、并集)
  • 无序

关系测试

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
set(list_1)
list_1
list_2
# 交集
list_1.intersection(list_2)
list_1 & list_2
# 并集
list_2.union(list_2)
list_1 | list_2
# 差集
list_1.difference(list_2)
list_1 - list_2
# 子集
list_1.issubset(list_2)
list_1 <= list_2
# 父集
list_1.issuperset(list_2)
list_1 >= list_2
# 对称差集
list_1.symmetric_difference(list_2)
list_1 ^ list_2
s = set([3,5,9,10]) #创建一个数值集合
t = set("Hello") #创建一个唯一字符的集合
a = t | s # t 和 s的并集
b = t & s # t 和 s的交集
c = t – s # 求差集(项在t中,但不在s中)
d = t ^ s # 对称差集(项在t或s中,但不会同时出现在二者中)
基本操作:
t.add('x') # 添加一项
s.update([10,37,42]) # 在s中添加多项
使用remove()可以删除一项:
t.remove('H')
len(s)
set 的长度
x in s
测试 x 是否是 s 的成员
x not in s
测试 x 是否不是 s 的成员
s.issubset(t)
s <= t
测试是否 s 中的每一个元素都在 t 中
s.issuperset(t)
s >= t
测试是否 t 中的每一个元素都在 s 中
s.union(t)
s | t
返回一个新的 set 包含 s 和 t 中的每一个元素
s.intersection(t)
s & t
返回一个新的 set 包含 s 和 t 中的公共元素
s.difference(t)
s - t
返回一个新的 set 包含 s 中有但是 t 中没有的元素
s.symmetric_difference(t)
s ^ t
返回一个新的 set 包含 s 和 t 中不重复的元素
s.copy()
返回 set “s”的一个浅复制

collection

计数器(counter)

Counter是对字典类型的补充,用于追踪值的出现次数。

ps:具备字典的所有功能 + 自己的功能

1
2
3
c = Counter('abcdeabcdabcaba')
print c
输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
  • sum(c.values()) # 所有计数的总数
  • c.clear() # 重置Counter对象,注意不是删除
  • list(c) # 将c中的键转为列表
  • set(c) # 将c中的键转为set
  • dict(c) # 将c中的键值对转为字典
  • c.items() # 转为(elem, cnt)格式的列表
  • Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
  • c.most_common()[:-n:-1] # 取出计数最少的n-1个元素
  • c += Counter() # 移除0和负值

有序字典(orderedDict )

orderdDict是对字典类型的补充,他记住了字典元素添加的顺序

默认字典(defaultdict)

可以设置一个key的默认值,能够在字典第一次对某个不存在key操作时给这个key赋予一个空的默认值然后再操作。

defaultdict是对字典的类型的补充,他默认给字典的值设置了一个类型。

可命名元组(namedtuple)

根据nametuple可以创建一个包含tuple所有功能以及其他功能的类型。

1
2
3
import collections
Mytuple = collections.namedtuple('Mytuple',['x', 'y', 'z'])

双向队列(deque)

一个线程安全的双向队列

既然有双向队列,也有单项队列(先进先出 FIFO )(Queue)

文件操作

1
2
3
4
# 打印指针位置
f.tell()
# 移动指针
f.seek()

操作文件时,一般需要经历如下步骤:

  • 打开文件
  • 操作文件

打开文件

文件句柄 = file(‘文件路径’, ‘模式’)

注:python中打开文件有两种方式,即:open(…) 和 file(…) ,本质上前者在内部会调用后者来进行文件操作,推荐使用 open。

打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作。

打开文件的模式有:

  • r,只读模式(默认)。
  • w,只写模式。【不可读;不存在则创建;存在则删除内容;】
  • a,追加模式。【可读; 不存在则创建;存在则只追加内容;】
  • “+” 表示可以同时读写某个文件
    • r+,可读写文件。【可读;可写;可追加】
    • w+,写读
    • a+,同a
  • “U”表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)
    • rU
    • r+U
  • “b”表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
    • rb
    • wb
    • ab

with

为了避免打开文件后忘记关闭,可以通过管理上下文,即:

1
2
3
with open('log','r') as f:
...

如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源。

在Python 2.7 后,with又支持同时对多个文件的上下文进行管理,即:

1
2
with open('log1') as obj1, open('log2') as obj2:
pass

函数

  • 面向过程
  • 面向函数
  • 函数式编程
  • 面向对象

递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

  • 在过程或函数里调用自身
  • 一定要有明确的结束条件,称为递归出口
  • 每深入一层,处理的数据规模要比上次有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
1
2
3
4
5
6
7
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2))
calc(10)

二分查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
def binary_search(dataset,find_num):
print(dataset)
if len(dataset) >1:
mid = int(len(dataset)/2)
if dataset[mid] == find_num: #find it
print("找到数字",dataset[mid])
elif dataset[mid] > find_num :# 找的数在mid左面
print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
return binary_search(dataset[0:mid], find_num)
else:# 找的数在mid右面
print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
return binary_search(dataset[mid+1:],find_num)
else:
if dataset[0] == find_num: #find it
print("找到数字啦",dataset[0])
else:
print("没的分了,要找的数字[%s]不在列表里" % find_num)
binary_search(data,66)

lambda匿名函数

匿名函数就是不需要显式的指定函数

对于简单的函数,也存在一种简便的表示方式,即:lambda表达式

高阶函数

变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

闭包

  • 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包
  • 内函数引用了外函数的局部变量,所以外函数的局部变量没有及时释放,消耗内存
1
2
3
4
5
6
7
8
9
10
11
12
13
def outer(a):
b = 10
d = [a,]
def inner():
# 内函数中想修改闭包变量
nonlocal b
b = b + 1
c = a + b
# 把闭包变量修改成可变数据类型
d[0] += 1
print(c)
# 外函数的返回值是内函数的引用
return inner
  • 装饰器
  • 面向对象:闭包也是实现面向对象的方法之一
  • 实现单利模式   

    装饰器

  • 本质是函数

  • 装饰其他函数、给函数添加功能,使用装饰器可以在函数执行前和执行后添加相应操作
  • 函数即变量
  • 不改变原函数代码,不改变原函数调用方式,不改变原函数执行结果
  • 高阶函数
    • 把一个函数名当做实参传给另一个函数
    • 返回值中包含函数名
  • 嵌套函数
  • 语法堂
  • 三层装饰器
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
def login(auth_type): #把要执行的模块从这里传进来
def auth(func):
def inner(*args,**kwargs):#再定义一层函数
if auth_type == "qq":
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
if user_status == True:
return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
else:
print("only support qq ")
return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
return auth

高阶函数

1
2
3
4
5
def add(x,y,f):
return f(x) + f(y)
res = add(3,-6,abs)
print(res)

迭代器、生成器

生成器generator

定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器

生成器内部基于yield创建,即:对于生成器只有使用时才创建,从而不避免内存浪费

一边循环一边计算的机制,称为生成器:generator

  • 列表生成式
    • [ i*2 for i in range(10) ]
    • [i for i in range(10) if i==9]
  • 生成器 generator
    • ( i*2 for i in range(10) )
    • 只有在调用时才会生成相应的数据
    • 只记录当前位置
    • 只有一个next()方法,next() #2.7
    • yeild StopIteration
    • (生产者,消费者)单线程下的并行效果–协程
  • 生成器是迭代器的一种
  • range不是生成器 和 xrange 是生成器
  • readlines不是生成器 和 xreadlines 是生成器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def con(name):
print(name)
while True:
b = yeild
print(b,name)
def pro(name):
c1 = con('A')
c2 = con('B')
c1.__next__()
c2.__next__()
print("start")
for i in range(10)
tile.sleep(1)
print(i)
c1.send(i)
c2.send(i)

斐波拉契数列

1
2
3
4
5
6
7
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'

迭代器

迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件

特点:

  • 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
  • 不能随机访问集合中的某个值 ,只能从头到尾依次访问
  • 访问到一半时不能往回退
  • 便于循环比较大的数据集合,节省内存

  • 容器(container)

  • assert
  • 可迭代对象(iterable)
    • 可以直接作用于for循环的对象
    • list、tuple、dict、set、str(不是Iterator,不过可以通过iter()函数获得一个Iterator对象)
    • generator,包括生成器和带yield的generator function
    • from collections import Iterable;isinstance([],Iterable)
    • 生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
  • 迭代器(iterator)
    • 可以被next()函数调用并不断返回下一个值的对象
    • from collections import Iterator;isinstance([], Iterator)
    • 把list、dict、str等Iterable变成Iterator可以使用iter()函数:

生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

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
# 生成无限序列:
>>> from itertools import count
>>> counter = count(start=13)
>>> next(counter)
13
>>> next(counter)
14
#从一个有限序列中生成无限序列:
>>> from itertools import cycle
>>> colors = cycle(['red', 'white', 'blue'])
>>> next(colors)
'red'
>>> next(colors)
'white'
>>> next(colors)
'blue'
>>> next(colors)
'red'
#从无限的序列中生成有限序列:
>>> from itertools import islice
>>> colors = cycle(['red', 'white', 'blue']) # infinite
>>> limited = islice(colors, 0, 4) # finite
>>> for x in limited:
... print(x)
red
white
blue
red
# 为了更直观地感受迭代器内部的执行过程,我们自定义一个迭代器,以斐波那契数列为例:
class Fib:
def __init__(self):
self.prev = 0
self.curr = 1
def __iter__(self):
return self
def __next__(self):
value = self.curr
self.curr += self.prev
self.prev = value
return value
>>> f = Fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
def fib():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, curr + prev
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
  • Fib既是一个可迭代对象(因为它实现了iter方法),又是一个迭代器(因为实现了next方法)。实例变量prev和curr用户维护迭代器内部的状态。每次调用next()方法的时候做两件事:

  • 为下一次调用next()方法修改状态

  • 为当前这次调用生成返回结果
  • 迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。

深浅拷贝

为什么要拷贝?

1
当进行修改时,想要保留原来的数据和修改后的数据

数字字符串 和 集合 在修改时的差异? (深浅拷贝不同的终极原因)

1
2
3
在修改数据时:
数字字符串:在内存中新建一份数据
集合:修改内存中的同一份数据

对于集合,如何保留其修改前和修改后的数据?

1
在内存中拷贝一份

对于集合,如何拷贝其n层元素同时拷贝?

1
深拷贝

内置函数

官网文档

  • all() 全部为真才为真
  • any() 有真就为真
  • bin() 转二进制 hex() 16进制 oct() 8进制
  • bool()
  • chr(98) ord(‘c’)
  • classmethod() 类方法
  • compile() 编译代码
  • dir()
  • divmod() 地板除
  • enumerate()
  • eval()
  • exec()
  • filter() filter(lambda a:a==9,[i for i in range(10)]) 对于序列中的元素进行筛选,最终获取符合条件的序列
1
2
3
li = [11, 22, 33]
new_list = filter(lambda arg: arg > 22, li)
#filter第一个参数为空,将获取原来序列
  • map() 遍历序列,对序列中每个元素进行操作,最终获取新的序列。
1
2
3
li = [11, 22, 33]
sl = [1, 2, 3]
new_list = map(lambda a, b: a + b, li, sl)
  • reduce() functools.reduce() 函数会对参数序列中元素进行累积
1
2
3
4
5
6
7
8
9
li = [11, 22, 33]
result = reduce(lambda arg1, arg2: arg1 + arg2, li)
# reduce的第一个参数,函数必须要有两个参数
# reduce的第二个参数,要循环的序列
# reduce的第三个参数,初始值
获取序列所有元素的和
  • format() 格式化字符串
  • globals() 当前所有全局变量 locals() 局部变量
  • hash()
  • help()
  • max() min() sum()
  • next()
  • round() 保留小数
  • slice() 切片
  • sorted() 排序
  • type()
  • vars()
  • zip()
  • import()

模块、包

定义

  • 本质就是一个.py的python文件
  • 用来从逻辑上组织python代码
  • 变量、函数、类、逻辑
  • 实现一个功能
  • 包:用来从逻辑上组织模块,本质就是一个目录(init.py)

导入方法

  • import module_name
  • import module_name1,module_name2
  • from module_name import *
  • from module_name import func,func1
  • from module_name import func as func_module

import本质

  • 导入模块的本质就是把python文件解释一次
  • 导入包的本质就是执行包下的init.py文件
  • 路径搜索(sys.path)
  • 搜索路径

如果sys.path路径列表没有你想要的路径,可以通过 sys.path.append(‘路径’) 添加。

1
2
3
4
5
import sys
import os
pre_path = os.path.abspath('../')
sys.path.append(pre_path)

导入优化

  • from module_name import func,func1

模块的分类

  • 标准库
  • 开源模块–第三方模块