Python3 函数-数据结构-模块

前言:
包括:函数def、数据结构、模块、python输入和输出…

函数 def

函数定义及调用

(1)定义:函数是组织好的可重复使用的,用来实现单一,或相关联功能的代码段
(2)优点:函数能提高应用的模块性,和代码的重复利用率。Python提供了许多内建函数,比如print()。也可以自己创建函数,这被叫做用户自定义函数
(3)函数定义规则:

  • 函数代码块以def关键词开头,后接函数标识符名称和圆括号()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明
  • 函数内容以冒号起始,并且缩进
  • return [表达式]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None

(4)语法:

1
2
def 函数名(参数列表):
函数体

例如:

1
2
3
4
5
def area(width, height):	# 计算面积函数
return width * height

w,h = 4,5
print("width =", w, " height =", h, " area =", area(w, h))

参数传递

(1)在 python 中,类型属于对象,变量是没有类型的

1
2
a=[1,2,3]
a="Runoob"

以上代码中,[1,2,3]List类型,"Runoob"String类型,而变量a是没有类型,她仅仅是一个对象的引用(一个指针),可以是指向List类型对象,也可以是指向String类型对象
(2)可更改mutable与不可更改immutable对象:

  • 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组)

  • 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)
    (3)函数的参数传递

  • 不可变数据(3 个):类似c++的值传递,如:整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在fun(a)内部修改a的值,只是修改另一个复制的对象,不会影响a本身

    1
    2
    3
    4
    5
    6
    7
    8
    def ChangeInt( a ):
    a = 10
    return a

    b = 2
    # 实例中有 int 对象 2,指向它的变量是 b,在传递给ChangeInt函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它
    print('a is :',ChangeInt(b)) # 结果是 10
    print('b is :',b ) # 结果是 2
  • 可变数据(3 个):类似c++的引用传递,如:列表,字典。如fun(la),则是将la真正的传过去,修改后fun外部的la也会受影响

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def changeme( mylist2 ):
    "修改传入的列表"
    mylist2.append([1,2,3,4])
    print ("mylist2函数内取值: ", mylist2) # mylist2函数外取值: [10, 20, 30, [1, 2, 3, 4]]
    return

    # 传入函数的和在末尾添加新内容的对象用的是同一个引用
    mylist = [10,20,30]
    changeme( mylist )
    print ("mylist函数外取值: ", mylist) # mylist函数外取值: [10, 20, 30, [1, 2, 3, 4]]

参数

调用函数时可使用的正式参数类型:必需参数、关键字参数、默认参数、不定长参数
(1)必需参数:必需参数须以正确的顺序传入函数,调用时的数量必须和声明时的一样

1
2
3
4
5
6
def printme( str ):
print (str)
return

# printme() # 调用 printme 函数,不加参数会报错:TypeError: printme() missing 1 required positional argument: 'str'
printme('abcdef') # abcdef

(2)关键字参数:函数调用使用关键字参数来确定传入的参数值,使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值

1
2
3
4
5
def printme(a, str ):
print ('a is:',a,' str is:',str)
return

printme(str='abcdef',a=10) # a is: 10 str is: abcdef

(3)默认参数:调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入age参数,则使用默认值

1
2
3
4
5
6
7
def printinfo( name, age = 35 ):    #  # 默认参数必须在非默认参数后面,否则会报错
print ("名字: ", name," 年龄: ", age)
return

#调用printinfo函数
printinfo( age=50, name="runoob" ) # 名字: runoob 年龄: 50
printinfo( name="runoob" ) # 名字: runoob 年龄: 35

默认参数必须在非默认参数后面,否则会报错:SyntaxError: non-default argument follows default argument

(4)不定长参数:一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数。和上述 2 种参数不同,声明时不会命名

1
2
3
4
5
def printme(arg1, *vartuple,a):	# 加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数
print ('arg1 is:',arg1,' vartuple is:',vartuple,'a is:',a)
return

printme(10,20,30,'abcdef',40,a=50) # arg1 is: 10 vartuple is: (20, 30, 'abcdef', 40) a is: 50

加了星号*的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数
单独出现星号*后的参数必须用关键字传入,如上述示例参数a

1
2
3
4
5
def printme(arg1,**vardict):	# 加了两个星号 ** 的参数会以字典的形式导入
print ('arg1 is:',arg1,' vardict is:',vardict)
return

printme(10,a=1 ,b='a',c=2 ,d='b',e=3 ,f='c') # arg1 is: 10 vardict is: {'b': 'a', 'f': 'c', 'a': 1, 'c': 2, 'd': 'b', 'e': 3}

匿名函数

(1)python使用lambda来创建匿名函数,所谓匿名,意即不再使用def语句这样标准的形式定义一个函数

  • lambda 只是一个表达式,函数体比 def 简单很多
  • lambda 的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率

(2)语法:

1
2
# lambda 函数的语法只包含一个语句
lambda [arg1 [,arg2,.....argn]]:expression
1
2
3
4
5
6
7
8
sum = lambda arg1, arg2: arg1 + arg2
print ("相加后的值为 : ", sum( 10, 20 )) # 相加后的值为 : 30

mul = [(lambda x:x*x)(x) for x in range(1,11)]
print ("平方后的值为 : ", mul) # 平方后的值为 : [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

from functools import reduce
print ("相加后的值为 : ", reduce(lambda x,y:x+y,range(1,101))) # 相加后的值为 : 5050

关于函数

(1)通过函数名.__doc__的方式来显示函数的说明文档,感觉这个如果在阅读比较大的程序时应该会有用,同时也在提示自己在写函数时注意添加文档说明

1
2
3
4
5
def add(a,b):
"传入参数a,b,返回a与b的和"
return a+b

print ('函数add的说明文档为:',add.__doc__) # 函数add的说明文档为: 传入参数a,b,返回a与b的和

(2)函数返回值的注意事项: ,Python 函数可以返回多个值,多个值以元组的方式返回

1
2
3
4
def fun(a,b):    
"返回多个值,结果以元组形式表示"
return a,b,a+b
print(fun(4,6)) # (4, 6, 10)

(3)函数内可以访问全局(global)变量,但不能更新(修改)其值

1
2
3
4
5
6
7
8
9
10
a = 10
def sum ( n ) :
global a
n += a # 可以访问全局变量a的值
a = 11 # 修改全局变量a的值,需要加上 global 引用,否则会报错:UnboundLocalErro
print ('a = ', a, end = ' , ' )
print ( 'n = ', n )

sum ( 3 )
print ( '外 a = ', a ) # a = 11 , n = 13 外 a = 11

(4)全局变量global和外部变量nonlocal的差别:nonlocal只能修改外层函数的变量而不能修改外层函数所引用的全局变量,global关键字会跳过中间层直接将嵌套作用域内的局部变量变为全局变量

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
x = 0
def outer():
global x
x = 1
def inner():
# nonlocal x # 会报错:SyntaxError: no binding for nonlocal 'x' found
x = 2
print(x,end=' ')
inner()

outer()
print(x,end=' ') # 2 1

num = 20
def outer():
num = 10
def inner():
global num
print (num,end=' ')
num = 100
print (num,end=' ')
inner()
print(num,end=' ')
outer()
print (num,end=' ') # 20 100 10 100

(5)形参实参

  • 形式参数简称形参,是指在定义函数时,定义的一个变量名,作用是用来接收调用函数时输入的值
  • 际参数简称实参,是指在调用函数时传入的实际的数据,这会被绑定到函数的形参上。函数调用时,将值绑定到变量名上,函数调用结束,解除绑定,并且实参将不再存在于程序中
    1
    2
    3
    4
    5
    6
    def foo(x, y, z):   # 此处的x、y、z 就是形参
    print("x=", x)
    print("y=", y)
    print("z=", z)

    foo(1,3,5) # 此处的1,3,5是实参

(6)Python 函数装饰器:装饰器Decorators是Python的一个重要部分。简单地说:他们是修改其他函数的功能的函数。有助于让我们的代码更简短

return语句

return [表达式]语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None

1
2
3
4
def sum( arg1, arg2 ):   # 返回2个参数的和."
return arg1 + arg2

print ("参数和为 :", sum( 10, 20 )) # 参数和为 : 30

强制位置参数

(1)Python3.8新增了一个函数形参语法/用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式

1
2
3
4
5
6
7
# 形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)

f(10, 20, 30, d=40, e=50, f=60) # 语法正确
f(10, b=20, c=30, d=40, e=50, f=60) # b 不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60) # e 必须使用关键字参数的形式

参考链接:python3 函数


数据结构

python内置的数据结构包括:列表(list)、集合(set)、字典(dictionary)

  • 不可变(3 个):Number(数字)、String(字符串)、Tuple(元组);
  • 可变(3 个):List(列表)、Dictionary(字典)、Set(集合)
  • 有序:列表list、字典dict(python3.6之后)、Tuple(元组)、Number(数字)、String(字符串)
  • 无序:字典dict(python3.6之前)、集合set

列表

Python列表函数&方法
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
# Python 列表

testlist1 = ['Google', 'Runoob', 1997, 2000, 'Runoob']
testlist2 = list('987123645')
testlist3 = ['我最', '爱学习', 'python']

# Python有6个序列的内置类型,但最常见的是列表和元组
# 序列都可以进行的操作包括索引,切片,加,乘,检查成员
print('testlist1:', testlist1) # testlist1: ['Google', 'Runoob', 1997, 2000]
print('testlist2:', testlist2) # testlist2: ['1', '2', '3', '4', '5', '6', '7', '8', '9']

testlist1[2] = 2001 # 更新testlist1第三个元素
print('testlist1更新后的第三个元素为 :', testlist1[2]) # testlist1更新后的第三个元素为 : 2001
del testlist1[2] # 删除testlist1第三个元素
print('testlist1删除第三个元素后为 :', testlist1) # testlist1删除第三个元素后为 : ['Google', 'Runoob', 2000]

# Python列表脚本操作符:列表对 + 和 * 的操作符与字符串相似。+ 号用于组合列表,* 号用于重复列表
print('testlist2 长度为:', len(testlist2)) # testlist2 长度为: 9
print('testlist1 和 testlist2 组合后为:',
testlist1 + testlist2) # testlist1 和 testlist2 组合后为: ['Google', 'Runoob', 2000, '1', '2', '3', '4', '5', '6', '7', '8', '9']
print('testlist1 重复输出3次:',
testlist1 * 3) # testlist1 重复输出3次: ['Google', 'Runoob', 2000, 'Google', 'Runoob', 2000, 'Google', 'Runoob', 2000]
print('3 是否在 testlist2中?', 3 in testlist2) # 3 是否在 testlist2中? False
# for x in testlist2:
# print ('testlist2迭代:',x) # testlist2迭代: 1.....

# Python列表函数&方法
# 函数
# len(list):返回列表元素个数
print('range(5) 列表长度为:', len(range(5))) # range(5) 列表长度为: 5
print('testlist2 列表长度为:', len(testlist2)) # testlist2 列表长度为: 9
# max(list):返回列表元素中的最大值
# list元素全部为字符串类型(string)时,则比较的是比较的是每个字符串元素的第一个字符的 ASCII 的大小
# list元素全部为数字类型时,直接根据值的大小比较
# list元素为列表或者元组中的元素为数字类型和字符串类型混杂时,则无法比较
print('testlist2 列表最大值为:', max(testlist2)) # testlist2 列表最大值为: 9
print('testlist3 列表最大值为:', max(testlist3)) # testlist3 列表最大值为: 爱学习
# min(list):返回列表元素中的最小值
print('testlist2 列表最大值为:', min(testlist2)) # testlist2 列表最大值为: 1
print('testlist3 列表最大值为:', min(testlist3)) # testlist3 列表最大值为: python
# list(seq):将元组或字符串转换为列表
print('该元组列表元素为:', list((123, 'Google', 'Runoob', 'Taobao'))) # 该元组列表元素为: [123, 'Google', 'Runoob', 'Taobao']
print('range(5) 列表元素为:', list(range(5))) # range(5) 列表元素为: [0, 1, 2, 3, 4]

# 方法
# list.append(obj):在列表末尾添加新的对象,该方法无返回值,但是会修改原来的列表
testlist3.append('aaa')
print('testlist3 更新后为:', testlist3) # testlist3 更新后为: ['我最', '爱学习', 'python', 'aaa']
# list.count(obj):用于统计某个元素在列表中出现的次数
print('testlist1 中Runoob出现次数为:', testlist1.count('Runoob')) #
# list.extend(seq):在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表),seq-元素列表,可以是列表、元组、集合、字典,若为字典,则仅会将键(key)作为元素依次添加至原列表的末尾
# 该方法没有返回值,但会在已存在的列表中添加新的列表内容
testlist1.extend(testlist2)
print('testlist1 和 testlist2 组合后为:',
testlist1) # testlist1 和 testlist2 组合后为: ['Google', 'Runoob', 2000, 'Runoob', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# list.index(x[, start[, end]]):从列表中找出某个值第一个匹配项的索引位置,
print('Taobao 索引值为:', ['Google', 'Runoob', 'Taobao'].index('Taobao')) # Taobao 索引值为 2
# list.insert(index, obj):用于将指定对象插入列表的指定位置
# 该方法没有返回值,但会在列表指定位置插入对象
testlist1.insert(1, 'Baidu')
print('testlist1 插入元素后为:',
testlist1) # testlist1 插入元素后为: ['Google', 'Baidu', 'Runoob', 2000, 'Runoob', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# list.pop([i]):移除列表中的一个元素(默认最后一个元素),并且返回该元素的值,索引值不能超过列表总长度,默认为 index=-1,删除最后一个列表值
print('testlist1 移除的元素为:', testlist1.pop(1)) # testlist1 移除的元素为: Baidu
# list.remove(obj):移除列表中某个值的第一个匹配项
# 该方法没有返回值但是会移除列表中的某个值的第一个匹配项
testlist1.remove(2000)
print('testlist1 更新后为:',
testlist1) # testlist1 更新后为: ['Google', 'Runoob', 'Runoob', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# list.reverse():用于反向列表中元
# 该方法没有返回值,但是会对列表的元素进行反向排序
testlist1.reverse()
print('testlist1 反转后为:', testlist1) #
# list.sort( key=None, reverse=False):对原列表进行排序,如果指定参数,则使用比较函数指定的比较函数
# key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序 reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)
# 该方法没有返回值,但是会对列表的对象进行排序
testlist2.sort(reverse=True)
print('testlist2 降序排列:', testlist2) # testlist2 降序排列: ['9', '8', '7', '6', '5', '4', '3', '2', '1']
testlist2.sort()
print('testlist2 升序排列:', testlist2) # testlist2 升序排列: ['1', '2', '3', '4', '5', '6', '7', '8', '9']


def takeSecond(elem): # 获取列表的第二个元素
return elem[1]

random = [(2, 2), (3, 4), (4, 1), (1, 3)] # 列表
random.sort(key=takeSecond) # 指定第二个元素排序
print('排序列表:', random) # 排序列表: [(4, 1), (2, 2), (1, 3), (3, 4)]

# list.clear():清空列表,类似于 del a[:]
# 该方法没有返回值
testlist1.clear()
print('testlist1 列表清空后为:', testlist1) # testlist1 列表清空后为: []
# list.copy():用于复制列表,类似于 a[:],返回复制后的新列表
testlist4 = testlist2.copy()
print('testlist2 后为:', testlist2) # testlist2 后为: ['1', '2', '3', '4', '5', '6', '7', '8', '9']
print('testlist4 后为:', testlist4) # testlist4 后为: ['1', '2', '3', '4', '5', '6', '7', '8', '9']
将列表当做堆栈使用

堆栈作为特定的数据结构,最先进入的元素最后一个被释放(后进先出)。列表方法使得列表可以很方便的作为一个堆栈来使用,用append()方法可以把一个元素添加到堆栈顶,用不指定索引的pop()方法可以把一个元素从堆栈顶释放出来

1
2
3
4
5
6
7
8
stack = [3, 4, 5]
stack.append(6)
stack.append(7)
print('stack is:',stack) # stack is: [3, 4, 5, 6, 7]
print('移除 stack 最后一个元素:',stack.pop()) # 移除 stack 最后一个元素: 7
print('stack is:',stack) # stack is: [3, 4, 5, 6]
print('移除 stack 最后一个元素:',stack.pop()) # 移除 stack 最后一个元素: 6
print('stack is:',stack) # stack is: [3, 4, 5]
将列表当做队列使用

把列表当做队列用,只是在队列里第一加入的元素,第一个取出来(先进先出);
但是拿列表用作这样的目的效率不高,在列表的最后添加或者弹出元素速度快,然而在列表里插入或者从头部弹出速度却不快(因为所有其他的元素都得一个一个地移动)

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

# deque(双向队列):两端都可以操作的队列,常用方法:
# deque.pop():移除并返回序列最后一个元素
# deque.leftpop():移除并返回序列第一个元素
# deque.extend(i):在序列最后添加一个元素 i ,无返回值
# deque.extendleft(i):在序列首位添加元素 i ,无返回值

queue = deque(["Eric", "John", "Michael"])
queue.append("Terry") # Terry arrives
queue.append("Graham") # Graham arrives
print('queue is:',queue) # queue is: deque(['Eric', 'John', 'Michael', 'Terry', 'Graham'])
print('移除 queue 第一个元素:',queue.popleft()) # 移除 queue 第一个元素: Eric
print('queue is:',queue) # queue is: deque(['John', 'Michael', 'Terry', 'Graham'])
print('移除 queue 第一个元素:',queue.popleft()) # 移除 queue 第一个元素: John
print('queue is:',queue) # queue is: deque(['Michael', 'Terry', 'Graham'])
列表推导式(列表解析式)

(1)列表推导式提供了从序列创建列表的简单途径。通常应用程序将一些操作应用于某个序列的每个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列
(2)每个列表推导式都在for之后跟一个表达式,然后有零到多个forif子句。返回结果是一个根据表达从其后的forif上下文环境中生成出来的列表
(3)如果希望表达式推导出一个元组,就必须使用括号()。如果希望表达式推导出一个列表,就必须使用中括号[]

1
2
3
4
5
6
7
8
9
10
11
12
# 记录序列每个元素的平方
print('li is:',[x**2 for x in range(1,6)]) # li is: [1, 4, 9, 16, 25]
# 记录序列的每个元素及其平方
print('li is:',[[x,x**2] for x in range(1,6)]) # li is: [[1, 1], [2, 4], [3, 9], [4, 16], [5, 25]]
# 对序列的每个元素调用某个方法
print('li is:',[ s.lower() for s in ['Aa','Bb','Cc','Dd'] ]) # li is: ['aa', 'bb', 'cc', 'dd']
# 用 if 子句作为过滤器,记录序列每个大于3的元素的平方
print('li is:',[x**2 for x in range(1,6) if x>3]) # li is: [16, 25]
# 多个 for 语句
print('li is:',[x*y for x in range(1,6) for y in range(3,4)]) # li is: [3, 6, 9, 12, 15]
# 多个 for 语句加多个 if 语句
print('li is:',[x*y for x in range(1,6) for y in range(3,4) if x>3 if y==3]) # li is: [12, 15]
嵌套列表解析

列表还可以嵌套,如以下3*4矩阵演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]	# 一个 3*4 的矩阵
print('matrix is:',matrix) # matrix is: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
# 转换成 4*3 的矩阵
# 方案1
transposed = []
for i in range(4):
transposed_row = []
for row in matrix:
transposed_row.append(row[i])
transposed.append(transposed_row)
print('transposed is:',transposed) # transposed is: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

# 方案2
transposed = []
for i in range(4):
transposed.append([row[i] for row in matrix])
print('transposed is:',transposed) # transposed is: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

# 方案3
print('transposed is:',[[row[i] for row in matrix] for i in range(4)]) # transposed is: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
del 语句

使用del语句可以从一个列表中依索引而不是值来删除一个元素。这与使用pop()返回一个值不同。可以用del语句从列表中删除一个切割,或清空整个列表

1
2
3
4
5
6
7
8
9
10
a = [-1, 1, 66.25, 333, 333, 1234.5]
print('a is:',a) # a is: [-1, 1, 66.25, 333, 333, 1234.5]
del a[0]
print('a is:',a) # a is: [1, 66.25, 333, 333, 1234.5]
del a[2:4]
print('a is:',a) # a is: [1, 66.25, 1234.5]
del a[:]
print('a is:',a) # a is: []
del a
print('a is:',a) # 报错:NameError: name 'a' is not defined

元组和序列

元组由若干逗号分隔的值组成,元组在输出时总是有括号的,以便于正确表达嵌套结构。在输入时可能有或没有括号,不过括号通常是必须的

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
t = 12345, 54321, 'hello!'
print('t is:',t) # t is: (12345, 54321, 'hello!')
u = t, (1, 2, 3, 4, 5)
print('u is:',u) # u is: ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))

# 元组与列表类似,不同之处在于元组的元素不能修改
# 元组使用小括号,列表使用方括号。元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可
tup1 = ('Google', 'Runoob', 1997, 2000, 'Runoob')
print('tup1:', tup1) # tup1: ('Google', 'Runoob', 1997, 2000, 'Runoob')
tup2 = tuple('987123645')
print('tup2:', tup2) # tup2: ('9', '8', '7', '1', '2', '3', '6', '4', '5')
tup3 = "a", "b", "c", "d", "g", "f", "e", "h" # 不需要括号也可以
print('tup3:', tup3) # tup3: ('a', 'b', 'c', 'd', 'g', 'f', 'e', 'h')
tup4 = () # 创建空元组
print('tup4:', tup4) # tup4: ()
tup5 = 50, # 元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用
print('tup5:', tup5) # tup5: (50,)

# 元组中的元素值是不允许修改的,但我们可以对元组进行连接组合
print('tup1 + tup2:',
tup1 + tup2) # tup1 + tup2: ('Google', 'Runoob', 1997, 2000, 'Runoob', '9', '8', '7', '1', '2', '3', '6', '4', '5')

# 元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组
print('tup3[2] is:', tup3[2]) # tup3[2] is: c
# del tup3 # 删除元组
# print(tup3) # NameError: name 'tup' is not defined

# 元组运算符:元组对 + 和 * 的操作符与字符串相似。+ 号用于组合列表,* 号用于重复列表
print('tup2 长度为:', len(tup2)) # tup2 长度为: 9
print('tup1 和 tup2 组合后为:',
tup1 + tup2) # tup1 和 tup2 组合后为: ('Google', 'Runoob', 1997, 2000, 'Runoob', '9', '8', '7', '1', '2', '3', '6', '4', '5')
print('tup1 重复输出3次:',
tup1 * 3) # tup1 重复输出3次: ('Google', 'Runoob', 1997, 2000, 'Runoob', 'Google', 'Runoob', 1997, 2000, 'Runoob', 'Google', 'Runoob', 1997, 2000, 'Runoob')
print('3 是否在 tup2中?', '3' in tup2) # 3 是否在 tup2中? True
for x in tup2:
print('tup2迭代:', x) # tup2迭代: 9.....

# 元组内置函数
# len(tuple):计算元组元素个数
print('tup1 元素个数为:', len(tup1)) # tup1 元素个数为: 5
# max(tuple):返回元组中元素最大值
# tuple元素全部为字符串类型(string)时,则比较的是比较的是每个字符串元素的第一个字符的 ASCII 的大小
# tuple元素全部为数字类型时,直接根据值的大小比较
# tuple元素为列表或者元组中的元素为数字类型和字符串类型混杂时,则无法比较
print('tup2 最大值为:', max(tup2)) # tup2 最大值为: 9
# min(tuple):返回元组中元素最小值
print('tup3 最小值为:', min(tup3)) # tup3 最小值为: a
# tuple(iterable):将可迭代系列转换为元组
print('tup2 :', tup2) # tup2 : ('9', '8', '7', '1', '2', '3', '6', '4', '5')

# 关于元组是不可变的:元组的不可变指的是元组所指向的内存中的内容不可变
tup = ('r', 'u', 'n', 'o', 'o', 'b')
print('tup:',tup) #
# tup[0] = 'g' # 不支持修改元素,会报错:TypeError: 'tuple' object does not support item assignment
print('查看内存地址:',id(tup)) # 查看内存地址: 2464144715208
tup = (1,2,3) # 内存地址发生了改变
print('查看内存地址:',id(tup)) # 查看内存地址: 2464146173240

集合

(1)集合是一个无序不重复元素的集。基本功能包括关系测试和消除重复元素
(2)可以用大括号{}创建集合。注意:如果要创建一个空集合,你必须用set()而不是{},后者创建一个空的字典

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
# 创建集合
set1 = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'} # 集合去重功能,去除重复的 apple ;快速判断元素是否在集合内
print('set1:', set1) # set1: {'pear', 'apple', 'banana', 'orange'}
print('orange 在 set1 内吗?:', 'orange' in set1) # orange 在 set1 内吗?: True
set2 = set() # 创建空集合
print('set2:', set2) # set2: set()

# 集合的基本操作:添加元素add()、移除元素remove()、计算集合元素个数len()、清空集合clear()、判断元素是否在集合中存在 in
# s.add( x ):将元素 x 添加到集合 s 中,如果元素已存在,则不进行任何操作,该函数没有任何返回值
set1.add(123)
print('set1:', set1) # set1: {'orange', 123, 'banana', 'pear', 'apple'}
# s.update( x ):添加元素,且参数可以是列表,元组,字典等,该函数没有任何返回值
set1.update(['a','b','c'])
print('set1:', set1) # set1: {'orange', 'b', 'c', 'a', 'banana', 'pear', 'apple', 123}

# s.remove( x ):将元素 x 从集合 s 中移除,如果元素不存在,则会发生KeyError错误,该函数没有任何返回值
set1.remove(123)
print('set1:', set1) # set1: {'pear', 'orange', 'c', 'banana', 'a', 'apple', 'b'}
# s.discard( x ):移除集合中的元素,且如果元素不存在,不会发生错误,该函数没有任何返回值
set1.discard(246)
print('set1:', set1) # set1: {'pear', 'orange', 'c', 'banana', 'a', 'apple', 'b'}
# s.pop():对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除并返回被删除的元素
print('set1 移除的元素为:', set1.pop()) # set1 移除的元素为: banana

# len(s):计算集合 s 元素个数
print('set1 的元素个数为:', len(set1)) # set1 的元素个数为: 6

# s.clear():清空集合 s,该函数没有任何返回值
set1.clear()
print('set1:', set1) # set1: set()

字典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建字典
dict1 = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} # 键值对创建字典
print('dict1:', dict1) # dict1: {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
print("dict1['Name']: ", dict1['Name'], "\tdict1['Class']: ",
dict1['Class']) # dict1['Name']: Runoob dict1['Class']: First

dict2 = dict([('Runoob', 1), ('Google', 2), ('Taobao', 3)]) # 构造函数 dict() 创建字典
print('dict2:', dict2) # dict2: {'Runoob': 1, 'Google': 2, 'Taobao': 3}

dict3 = dict(Runoob=1, Google=2, Taobao=3) # 构造函数 dict() 创建字典
print('dict3:', dict3) # dict2: {'Runoob': 1, 'Google': 2, 'Taobao': 3}

dict4 = {x: x ** 2 for x in (2, 4, 6)} #
print('dict4:', dict4) # dict4: {2: 4, 4: 16, 6: 36}

dict5 = {} # 创建空字典
print('dict5:', dict5) # dict4: {}

遍历技巧

(1)字典中遍历时,关键字和对应的值可以使用items()方法同时解读出来

1
2
3
d={x:x**2 for x in range(5)}
for k,v in d.items():
print(k,'-',v,end=' | ') # 0 - 0 | 1 - 1 | 2 - 4 | 3 - 9 | 4 - 16 |

(2)序列中遍历时,索引位置和对应值可以使用enumerate()函数同时得到

1
2
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i,'-', v,end=' | ') # 0 - tic | 1 - tac | 2 - toe |

(3)同时遍历两个或更多的序列,可以使用zip()组合

1
2
3
4
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
print(q,'-', a,end=' | ') # name - lancelot | quest - the holy grail | favorite color - blue |

(4)反向遍历一个序列,首先指定这个序列,然后调用reversed()函数

1
2
for s in reversed('abcde'):
print(s,end=' ') # e d c b a

(5)按顺序遍历一个序列,使用sorted()函数返回一个已排序的序列,并不修改原值

1
2
for s in sorted(set('axbzcmkdaahejh')):
print(s,end=' ') # a b c d e h j k m x z

参考资料


模块

基本概念

(1)Python提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式的解释器实例使用,这个文件被称为模块
(2)模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用python标准库的方法

  • 在python用import或者from...import来导入相应的模块
  • 将整个模块(somemodule)导入,格式为:import somemodule
  • 将多个模块导入,格式为:’import random,sys,os,math’
  • 从某个模块中导入某个函数,格式为:from somemodule import somefunction
  • 从某个模块中导入多个函数,格式为:from somemodule import firstfunc, secondfunc, thirdfunc
  • 将某个模块中的全部函数(那些由单一下划线_开头的名字不在此例)导入,格式为:from somemodule import *
    1
    2
    3
    4
    5
    6
    import sys
    print('================Python import mode==========================')
    print ('命令行参数为:')
    for i in sys.argv:
    print (i)
    print ('\n python 路径为',sys.path)
1
2
3
4
5
6
from sys import argv,path  #  导入特定的成员

print('================python from import===================================')
print('path:',path) # 因为已经导入path成员,所以此处引用时不需要加sys.path
path.append('E:\python\study\tool') # 将指定路径添加到搜索路径
print('path:',path)
  • import sys引入python标准库中的sys.py模块;这是引入某一模块的方法
  • sys.argv是一个包含命令行参数的列表
  • sys.path包含了一个python解释器自动查找所需模块的路径的列表

搜索路径

(1)当解释器遇到import语句,如果模块在当前的搜索路径就会被导入
(2)搜索路径是一个解释器会先进行搜索的所有目录的列表,Python解释器就依次从这些目录中去寻找所引入的模块
(3)这看起来很像环境变量,事实上,也可以通过定义环境变量的方式来确定搜索路径
(4)搜索路径是在Python编译或安装的时候确定的,安装新的库应该也会修改,搜索路径被存储在sys模块中的path变量,可以用sys.path.append(filepath)来修改对应的搜索路径

1
2
3
================python from import===================================
path: ['E:\\python\\test', 'D:\\python\\python-3.5.0\\python35.zip', 'D:\\python\\python-3.5.0\\DLLs', 'D:\\python\\python-3.5.0\\lib', 'D:\\python\\python-3.5.0', 'D:\\python\\python-3.5.0\\lib\\site-packages']
path: ['E:\\python\\test', 'D:\\python\\python-3.5.0\\python35.zip', 'D:\\python\\python-3.5.0\\DLLs', 'D:\\python\\python-3.5.0\\lib', 'D:\\python\\python-3.5.0', 'D:\\python\\python-3.5.0\\lib\\site-packages', 'E:\\python\\study\tool']

第一项是’E:\python\test’,代表当前脚本所在目录。最后一项’E:\python\study\tool’是指定添加的搜索路径

name属性

(1)一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行

1
2
3
4
5
6
# Filename: using_name.py

if __name__ == '__main__':
print('程序自身在运行')
else:
print('我来自另一模块')

运行输出如下:

1
2
$ python using_name.py
程序自身在运行
1
2
3
$ python
>>> import using_name
我来自另一模块
  • 每个模块都有一个__name__属性,当其值是’main‘时,表明该模块自身在运行,否则是被引入
  • __name____main__底下是双下划线,_ _是这样去掉中间的那个空格

dir() 函数

(1)内置的函数dir()可以找到模块内定义的所有名称。以一个字符串列表的形式返回(如果没有给定参数,那么dir()函数会罗列出当前定义的所有名称)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__',
'__package__', '__stderr__', '__stdin__', '__stdout__',
'_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe',
'_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv',
'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder',
'call_tracing', 'callstats', 'copyright', 'displayhook',
'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix',
'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
'getcheckinterval', 'getdefaultencoding', 'getdlopenflags',
'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit',
'getrefcount', 'getsizeof', 'getswitchinterval', 'gettotalrefcount',
'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
'intern', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path',
'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1',
'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit',
'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout',
'thread_info', 'version', 'version_info', 'warnoptions']

(1)包是一种管理Python模块命名空间的形式,采用”点模块名称”,比如一个模块的名称是A.B, 那么他表示一个包A中的子模块B,采用点模块名称这种形式不用担心不同库之间的模块重名的情况
(2)设计一套统一处理声音文件和数据的模块(或者称之为一个”包”)

  • 现存很多种不同的音频文件格式(基本上都是通过后缀名区分的,例如:.wav,:file:.aiff,:file:.au,),所以你需要有一组不断增加的模块,用来在不同的格式之间转换
  • 并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所以你还需要一组怎么也写不完的模块来处理这些操作。
    这里给出了一种可能的包结构(在分层的文件系统中):
    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
    ...

(3)在导入一个包的时候,Python会根据sys.path中的目录来寻找这个包中包含的子目录
(4)目录只有包含一个叫做__init__.py的文件才会被认作是一个包,主要是为了避免一些滥俗的名字(比如叫做string)不小心的影响搜索路径中的有效模块
(5)最简单的情况,放一个空的:file:__init__.py就可以了。当然这个文件中也可以包含一些初始化代码或者为(将在后面介绍的)__all__变量赋值

1
2
3
4
5
6
7
8
import sound.effects.echo	# 导入子模块:sound.effects.echo,必须使用全名去访问
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

from sound.effects import echo # 导入子模块: echo,不需要那些冗长的前缀,可以使用名称访问
echo.echofilter(input, output, delay=0.7, atten=4)

from sound.effects.echo import echofilter # 直接导入一个函数或者变量,导入子模块: echo,并且可以直接使用他的 echofilter() 函数
echofilter(input, output, delay=0.7, atten=4)

当使用from package import item这种形式的时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量
import语法会首先把item当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,抛出一个:exc:ImportError异常
如果使用形如import item.subitem.subsubitem这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字

从一个包中导入*

(1)如果我们使用from sound.effects import *,Python会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来,对于一些不区分大小写的系统比较不友好(比如Windows)
(2)导入语句遵循如下规则:如果包定义文件__init__.py存在一个叫做__all__的列表变量,那么在使用from package import *的时候就把这个列表中的所有名字作为包内容导入(在更新包之后需要保证__all__也更新)
(3)通常我们并不主张使用*这种方法来导入模块,因为这种方法经常会导致代码的可读性降低,使用from Package import specific_submodule这种方法永远不会有错(推荐的方法)

1
2
3
import sound.effects.echo
import sound.effects.surround
from sound.effects import *

输入和输出

输出格式美化

(1)Python两种输出值的方式: 表达式语句和print()函数
(2)第三种方式是使用文件对象的write()方法,标准输出文件可以用sys.stdout引用
(3)可以使用str.format()函数来格式化输出值,使输出的形式更加多样
(4)可以使用repr()str()函数来实现,将输出的值转成字符串:

  • str(): 函数返回一个用户易读的表达形式。
  • repr(): 产生一个解释器易读的表达形式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    s='Hello World'
    # str() 函数可以输出一个字符串
    print('s is:',str(s)) # s is: Hello World
    # repr() 函数可以转义字符串中的特殊字符
    print('s is:',repr(s)) # s is: 'Hello World'

    # 输出一个平方与立方的表
    for x in range(1, 11):
    print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ') # 字符串对象的 rjust() 方法, 它可以将字符串靠右, 并在左边填充空格,还有ljust() 和 center()
    # 注意前一行 'end' 的使用
    print(repr(x*x*x).rjust(4))
    # 输出一个平方与立方的表
    for x in range(1, 11):
    print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))

    # zfill()会在字符串的左边填充 0
    print('zfill(5) is:','12'.zfill(5)) # zfill(5) is: 00012
    print('zfill(5) is:','a12'.zfill(5)) # zfill(5) is: 00a12

str.format() 的基本使用

(1)括号及其里面的字符 (称作格式化字段) 将会被format()中的参数替换
(2)位置参数:在括号中的数字可以用于指向传入对象在format()中的位置
(3)关键字参数:如果在format()中使用了关键字参数, 那么它们的值会指向使用该名字的参数

1
2
3
4
5
6
7
8
9
print('浏览器:{} 和 {}'.format('Google','Baidu'))	# 浏览器:Google 和 Baidu
# 位置参数
print('浏览器:{0} 和 {1}'.format('Google','Baidu')) # 浏览器:Google 和 Baidu
print('浏览器:{1} 和 {0}'.format('Google','Baidu')) # 浏览器:Baidu 和 Google
# 关键字参数
print('名称:{name} 官网: {site}'.format(site='www.baidu.com',name='Baidu')) # 名称:Baidu 官网: www.baidu.com
# 位置及关键字参数可以任意的结合,但是次序不能乱
print('站点列表 {1}, {0}, 和 {other}。'.format('Google', 'Runoob',other='Taobao')) # 站点列表 Runoob, Google, 和 Taobao。
print('站点列表 {1}, {0}, 和 {other}。'.format(other='Taobao','Google', 'Runoob')) # 报错:SyntaxError: positional argument follows keyword argument

(4)!a(使用ascii()),!s(使用str())和!r(使用repr()) 可以用于在格式化某个值之前对其进行转化

1
2
3
4
import math

print('常量 PI 的值近似为: {}。'.format(math.pi)) # 常量 PI 的值近似为: 3.141592653589793。
print('常量 PI 的值近似为: {!r}。'.format(math.pi)) # 常量 PI 的值近似为: 3.141592653589793。

(5)如果你有一个很长的格式化字符串, 而你不想将它们分开, 那么在格式化时通过变量名而非位置会是很好的事情
a.最简单的就是传入一个字典, 然后使用方括号[]来访问键值
b.也可以通过在table变量前使用**来实现相同的功能

1
2
3
4
5
6
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {0[Runoob]:d}; Google: {0[Google]:d}; Taobao: {0[Taobao]:d}'.format(table)) # Runoob: 2; Google: 1; Taobao: 3

# 也可以通过在 table 变量前使用 ** 来实现相同的功能
table2 = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}'.format(**table2)) # Runoob: 2; Google: 1; Taobao: 3

旧式字符串格式化

(1)%操作符也可以实现字符串格式化。它将左边的参数作为类似sprintf()式的格式化字符串, 而将右边的代入, 然后返回格式化后的字符串

1
2
3
import math

print('常量 PI 的值近似为:%5.3f。' % math.pi) # 常量 PI 的值近似为:3.142。

读取键盘输入

(1)Python提供了input()内置函数从标准输入读入一行文本,默认的标准输入是键盘,input可以接收一个Python表达式作为输入,并将运算结果返回

1
2
inputStr=input('请输入:')
print('输入值为:',inputStr) # 输入值为::111

读和写文件

(1)open()将会返回一个file对象,基本语法格式如下

1
2
3
open(filename, mode)
# filename:包含了你要访问的文件名称的字符串值
# mode:决定了打开文件的模式:只读(r),写入(w),追加(a)等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读(r)
模式 描述
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

下图很好的总结了这几种模式:
文件读写

模式 r r+ w w+ a a+
+ + + +
+ + + + +
覆盖 + +
指针在开始 + + + +
指针在结尾 + +
1
2
3
4
5
6
# 打开一个文件
f = open("../study/file/files/writefile.txt", "w")
# 向文件写入数据
f.write( "这是第一行\n这是第二行\n" )
# 关闭打开的文件
f.close()

执行上述脚本后,writefile.txt文件的内容为:

1
2
这是第一行
这是第二行

文件对象的方法

(1)f.read():
为了读取一个文件的内容,调用f.read(size), 这将读取一定数目的数据, 然后作为字符串或字节对象返回
size是一个可选的数字类型的参数。 当size被忽略了或者为负, 那么该文件的所有内容都将被读取并且返回

(2)f.readline():
f.readline()会从文件中读取单独的一行。换行符为\n
f.readline()如果返回一个空字符串, 说明已经已经读取到最后一行

(3)f.readlines():
f.readlines()将返回该文件中包含的所有行
如果设置可选参数sizehint, 则读取指定长度的字节, 并且将这些字节按行分割

(4)f.write():
f.write(string)string写入到文件中, 然后返回写入的字符数;
如果要写入一些不是字符串的东西, 那么将需要先进行转换,str()方法等

(5)f.tell():
f.tell()返回文件对象当前所处的位置, 它是从文件开头开始算起的字节数

(6)f.seek():
如果要改变文件当前的位置, 可以使用f.seek(offset, from_what)函数
from_what的值, 如果是0表示开头, 如果是1表示当前位置,2表示文件的结尾(默认值为0)

  • seek(x,0) : 从起始位置即文件首行首字符开始移动 x 个字符
  • seek(x,1) : 表示从当前位置往后移动x个字符
  • seek(-x,2):表示从文件的结尾往前移动x个字符

(7)f.close():
在文本文件中 (那些打开文件的模式下没有b的), 只会相对于文件起始位置进行定位。
当你处理完一个文件后, 调用f.close()来关闭文件并释放系统的资源,如果尝试再调用该文件,则会抛出异常

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
# 打开一个文件
f = open("../study/file/files/writefile.txt", "w")
num=f.write( "这是第一行\n这是第二行\n" ) # 将 string 写入到文件中, 然后返回写入的字符数
print('写入字符数为:',num) # 写入字符数为: 12
f.close() # 关闭打开的文件

f = open("../study/file/files/writefile.txt", "r")
str1=f.read() # 获取文件内容,读取一定数目的数据,作为字符串或字节对象返回
print('文件内容是:\n',str1) #
f.close()

f = open("../study/file/files/writefile.txt", "r")
str2=f.readline() # 从文件中读取单独的一行。换行符为 '\n'。如果返回一个空字符串, 说明已经已经读取到最后一行
print('文件内容是:\n',str2) # 这是第一行
f.close()

f=open('../study/file/files/writefile.txt','r')
str3=f.readlines()
print('文件内容是:\n',str3) # ['这是第一行\n', '这是第二行\n']
f.close()

# 迭代一个文件对象然后读取每行
f=open('../study/file/files/writefile.txt','r')
for strline in f:
print(strline,end=' ') # 这是第一行 \n 这是第二行
f.close()

f=open('../study/file/files/writefile.txt','rb+')
f.write(b'123456789abcdefg')
print('移动到文件的第六个字节',f.seek(5)) # 移动到文件的第六个字节 5
print('从当前位置开始读取三个字节:',f.read(3)) # 从当前位置开始读取三个字节: b'678'
print('移动到文件的倒数第三字节:',f.seek(-3,2)) # 移动到文件的倒数第三字节:13
print(f.read(2)) # 从当前位置开始读取两个字节: b'ef'
f.close()

str1=f.read() # 抛出异常:ValueError: read of closed file

pickle 模块

(1)python的pickle模块实现了基本的数据序列化和反序列化,通过pickle的序列化操作可以很好的将程序中运行的 对象信息保存到文件中去,永久存储;通过pickle的反序列化操作可以从文件中创建上一次程序保存的对象

将数据对象转换为二进制流的过程称为对象的序列化(Serialization
(2)基本接口

1
2
3
4
5
6
# 序列化对象:将对象obj保存到文件file中去
# 参数protocol是序列化模式,默认是0(ASCII协议,表示以文本的形式进行序列化),protocol的值还可以是1和2(1和2表示以二进制的形式进行序列化。其中,1是老式的二进制协议;2是新二进制协议)
# file表示保存到的类文件对象,file必须有write()接口,file必须以二进制可写模式打开,即“wb”
pickle.dump(obj, file, [,protocol])
# 反序列化对象:将文件中的数据解析为一个python对象。file中有read()接口和readline()接口
x = pickle.load(file)
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
import pprint,pickle

# 使用pickle模块将数据对象保存到文件
data1 = {'a': [1, 2.0, 3, 4+6j],
'b': ('string', u'Unicode string'),
'c': None}

selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)

output = open('../study/file/files/data.txt', 'wb')
# Pickle dictionary using protocol 0.
pickle.dump(data1, output)
# Pickle the list using the highest protocol available.
pickle.dump(selfref_list, output, -1)
output.close()

# pprint()类似于print()函数,但是pprint()模块打印出来的数据结构更加完整,每行为一个数据结构,更加方便阅读打印输出结果
# 使用pickle模块从文件中重构python对象
f=open('../study/file/files/data.txt', 'rb')

data1 = pickle.load(f)
pprint.pprint(data1)

data2 = pickle.load(f)
pprint.pprint(data2)

f.close()

(3)示例:通过 pickle 序列化实现一个简单联系人信息管理

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import pickle
import os

# 通过 pickle 序列化实现一个简单联系人信息管理

datafile = 'person.data'
line = '======================================='
message = '''
=======================================
Welcome bookmark:
press 1 to show list
press 2 to add pepole
press 3 to edit pepole
press 4 to delete pepole
press 5 to search pepole
press 6 to show menu
press 0 to quit
=======================================
'''
print(message)


class Person(object):
"""通讯录联系人"""

def __init__(self, name, number):
self.name = name
self.number = number


# 获取数据
def get_data(filename=datafile):
# 文件存在且不为空
if os.path.exists(filename) and os.path.getsize(filename):
with open(filename, 'rb') as f:
return pickle.load(f)
return None


# 写入数据
def set_data(name, number, filename=datafile):
personList = {} if get_data() == None else get_data()

with open(filename, 'wb') as f:
personList[name] = Person(name, number)
pickle.dump(personList, f)


# 保存字典格式的数据到文件
def save_data(dictPerson, filename=datafile):
with open(filename, 'wb') as f:
pickle.dump(dictPerson, f)


# 显示所有联系人
def show_all():
personList = get_data()
if personList:
for v in personList.values():
print(v.name, v.number)
print(line)
else:
print('not yet person,please add person')
print(line)


# 添加联系人
def add_person(name, number):
set_data(name, number)
print('success add person')
print(line)


# 编辑联系人
def edit_person(name, number):
personList = get_data()
if personList:
personList[name] = Person(name, number)
save_data(personList)
print('success edit person')
print(line)


# 删除联系人
def delete_person(name):
personList = get_data()
if personList:
if name in personList:
del personList[name]
save_data(personList)
print('success delete person')
else:
print(name, ' is not exists in dict')
print(line)


# 搜索联系人
def search_person(name):
personList = get_data()
if personList:
if name in personList.keys():
print(personList.get(name).name, personList.get(name).number)
else:
print('No this person of ', name)
print(line)


while True:
num = input('>>')

if num == '1':
print('show all personList:')
show_all()
elif num == '2':
print('add person:')
name = input('input name>>')
number = input('input number>>')
add_person(name, number)
elif num == '3':
print('edit person:')
name = input('input name>>')
number = input('input number>>')
edit_person(name, number)
elif num == '4':
print('delete person:')
name = input('input name>>')
delete_person(name)
elif num == '5':
print('search :')
name = input('input name>>')
search_person(name)
elif num == '6':
print(message)
elif num == '0':
break
else:
print('input error, please retry')

—— 感谢您的阅读 ( ゚∀゚) 有什么疑问可以在下方留言哦 ——
坚持原创技术分享,您的支持将鼓励我继续创作!