文章大部分摘抄,侵权请联系删除
python3入门基础
一、Python变量和数据类型
基础数据类型
整数
二进制数
在Python中,二进制整数使用前缀0b表示,比如:0b0110,0b1100。
十六进制数
十六进制数除了0~9十个数字以外,还使用a、b、c、d、e、f,在Python中,十六进制使用前缀0x,比如:0x12ef,0xde2431af。
浮点数
为什么小数在计算机领域被称为浮点数呢?这是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的(浮动的),比如,1.23x10 ^ 9和12.3x10^8是相等的,因此称为浮点数。
浮点数可以用数学写法,如1.23,3.14,-9.01。但是对于很大或很小的浮点数,就必须用科学计数法表示。
在Python中,把10用e替代,比如:1.23x10^9就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5
注意:整数和浮点数在计算机内部存储的方式是不同的,
整数运算永远是精确的,而浮点数运算则可能会有四舍五入的误差
布尔值
布尔值对应于生活中的就是对和错,在计算机的世界里,大部分判断都是非错则对的,布尔值和布尔代数的表示完全一致,一个布尔值只有True、False两种值,要么是True,要么是False,在Python中,可以直接用True、False表示布尔值(请注意大小写,不需要使用字符串符号括起来),也可以通过布尔运算计算出来。
布尔值可以用and、or和not(非)运算(注意and,or,not都是Python语言本身的关键字)。
定义变量的方法
合法的变量名
在Python中,定义一个变量需要遵循一定的约束,否则,Python可能识别不出它是一个变量。
变量名由大小写英文字母、数字和下划线_组成
变量不能用数字开头
变量尽量不要和Python关键字重合(比如前面学习过的:and、or、not,否则可能导致Python原有关键字发挥不出作用)
在Python里面,一个变量可以先后存储多种不同类型的数据。
a = 1 # 这个时候a存储的是整数类型
print(a)
a = 'ABC' # 这个时候a存储的是字符串类型
print(a)
这是Python这类语言特有的特性,我们称之为动态语言,与之对应的是静态语言,Python、Javascript等等都是动态语言,Java、C、C++等等属于静态语言。
整数与浮点数
四则运算
整数和浮点数运算后 ,得到的结果不管小数点后是否有值,结果都变成浮点数了,这是合理的,浮点数可以表达整数的结果,但是整数不能表达浮点数的结果。
整数、浮点数可以直接进行四则运算。
# 加法
num1 = 10
num2 = 0.5
result = num1 + num2
print(result) # ==> 10.5
# 减法
result = num1 - num2
print(result) # ==> 9.5
# 乘法
result = num1 * num2
print(result) # ==> 5.0
# 除法
result = num1 / num2
print(result) # ==>20.0
注意:在Python2使用除法可能和Python3得到不一样的结果
# python2
num1 = 10
num2 = 3
result = num1 / num2
print(result) # ==> 3
# python3
num1 = 10
num2 = 3
result = num1 / num2
print(result) # ==> 3.3333333333333335
可以看到在python2,得到的是一个整数的结果,这是因为除数和被除数都是整数时,得到的结果也默认保存为整数了,这是非常不科学的,因此在python3,改进了这一点。
取模运算
Python数字支持取模运算,使用百分号%表示取模。
print(3 % 2) # ==> 1
print(33 % 10) # ==> 3
print(99 % 30) # ==> 9
可以用取模运算方法来判断奇数和偶数
地板除
Python除了普通除法以外,还有一个特殊的除法被称为地板除,对于地板除,得到的结果会忽略纯小数的部分,得到整数的部分,地板除使用//进行。
10//4 # ==> 2
10//2.5 # ==> 4.0
10//3 # ==> 3
小数点位数
使用Python计算小数的时候,经常需要保留小数点后若干位,可以使用round()函数来处理,这里先了解round的调用方式,使用两个参数,第一个是需要保留小数点位数的数值,第二个是保留的位数。
num = 10 / 3
print(num) # ==> 3.3333333333333335
# 使用round保留两位小数
round(num, 2) # ==> 3.33
实例:一个长方形的长为3.14cm,宽为1.57cm,请计算这个长方形的面积,保留小数点后两位。
length = 3.14
width = 1.57
result = round(length * width, 2)
print(result)
Python的布尔类型
主要运算有and、or和not(非)运算
这些运算有什么用呢?计算机程序是由无数的逻辑分支组成的,
通过布尔运算,可以在计算机中实现条件判断,根据计算结果为True或者False,
计算机就可以自动执行不同的后续代码。
Python中,布尔类型还可以与其他数据类型(字符串,数字等)做 and、or和not运算
a = True
print(a and 0 or 99) # ==> 99 #得到的计算结果不是布尔类型,而是数字99,这是为什么呢?
因为Python把0、空字符串和None看成False,其他数值和非空字符串都看成True
所以:True and 0计算结果是0
继续计算0 or 99计算结果是 99
因此,结果是99。
需要注意的是,not计算的优先级是高于and和or的。
True and not False # ==> True
先计算not False = True,然后再计算True and True,因此得到True的结果
短路计算
在计算a and b时,如果 a 是 False,则根据与运算法则,整个结果必定为 False,
因此返回 a;如果 a 是 True,则整个计算结果必定取决与 b,因此返回 b。
在计算a or b时,如果 a 是 True,则根据或运算法则,整个计算结果必定为 True,
因此返回 a;如果 a 是 False,则整个计算结果必定取决于 b,因此返回 b。
Python的字符串
字符串可以用’ '或者" "括起来表示。
如果字符串本身包含’怎么办?比如我们要表示字符串 I’m OK ,这时,可以用" "括起来表示:
"I'm OK"
类似的,如果字符串包含",我们就可以用’ '括起来表示:
'Learn "Python" in imooc'
但是,如果字符串既包含’又包含"怎么办?
这个时候,就需要对字符串中的某些特殊字符进行“转义”,Python字符串用\进行转义。
要表示字符串Bob said “I’m OK”
'Bob said \"I\'m OK\".'
注意:转义字符 \不计入字符串的内容中。
raw字符串与多行字符串
raw 字符串:里面的字符就不需要再转义。
如果一个字符串包含很多需要转义的字符,对每一个字符都进行转义会很麻烦。
我们可以在字符串前面加个前缀r,表示这是一个 raw 字符串,里面的字符就不需要转义了。例如:
r' \(~_~)/ \(~_~)/ '
#r'...'表示法不能表示多行字符串,也不能表示包含'和 "的字符串。
如果要表示多行字符串,可以用’’’…’’'表示:
'''Line 1
Line 2
Line 3'''
上面这个字符串的表示方法和下面的是完全一样的:
'Line 1\nLine 2\nLine 3'
也可以在多行字符串前面添加r,把这个多行字符串也变成一个raw字符串:
r'''Python is created by "Guido".
It is free and easy to learn.
Let's start learn Python in imooc!'''
Python的字符串format
目前为止,我们输出的字符串的内容都是固定的,但有时候通过字符串输出的内容不是固定的,这个时候需要使用format来处理字符串,输出不固定的内容。
format由两个部分组成,字符串模板和模板数据内容组成,通过大括号{},就可以把模板数据内容嵌到字符串模板对应的位置。
# 字符串模板
template = 'Hello {}'
# 模板数据内容
world = 'World'
result = template.format(world)
print(result) # ==> Hello World
如果模板中{}比较多,也可以指定模板数据内容的顺序。
# 指定顺序
template = 'Hello {0}, Hello {1}, Hello {2}, Hello {3}.'
result = template.format('World', 'China', 'Beijing', 'imooc')
print(result) # ==> Hello World, Hello China, Hello Beijing, Hello imooc.
# 调整顺序
template = 'Hello {3}, Hello {2}, Hello {1}, Hello {0}.'
result = template.format('World', 'China', 'Beijing', 'imooc')
print(result) # ==> Hello imooc, Hello Beijing, Hello China, Hello World.
除了使用顺序,还可以指定对应的名字,使得在format过程更加清晰。
# 指定{}的名字w,c,b,i
template = 'Hello {w}, Hello {c}, Hello {b}, Hello {i}.'
world = 'World'
china = 'China'
beijing = 'Beijing'
imooc = 'imooc'
# 指定名字对应的模板数据内容
result = template.format(w = world, c = china, b = beijing, i = imooc)
print(result) # ==> Hello World, Hello China, Hello Beijing, Hello imooc.
实例:使用两种format的方式打印字符串Life is short, you need Python。
print('Life is short, you need {}'.format('Python'))
print('Life is short, you need {launguage}'.format( launguage = 'Python'))
python3的编码
在python3中,默认使用UTF-8 Unicode来进行编码
# coding: utf-8 //在头部添加
Python的字符串切片
有时候,我们会想获取字符串的一部分(子串),这个时候我们采取切片的方式获取,切片需要在中括号[]中填入两个数字,中间用冒号分开,表示子串的开始位置和结束位置,并且这是半闭半开区间,不包括最后的位置。
ab = s[0:2] # 取字符串s中的第一个字符到第三个字符,不包括第三个字符
print(ab) # ==> AB
定义一个更长的字符串,了解切片更多的细节。
s = 'ABCDEFGHIJK'
abcd = s[0:4] # 取字符串s中的第一个字符到第五个字符,不包括第五个字符
print(abcd) # ==> ABCD
cdef = s[2:6] # 取字符串s中的第三个字符到第七个字符,不包括第七个字符
print(cdef) # ==> CDEF
二、Python语言的控制流程
Python之if语句
计算机之所以能做很多自动化的任务,因为它可以自己做条件判断,通过条件判断,选择做什么样的逻辑(当然,逻辑是需要我们提前写好的),我们称之为条件分支判断。
举个例子,在100分试卷的考试中,小于60分我们认为是不及格的,因此,我们可以使用程序自动判断考试是否及格。
score = 59
if score < 60:
print('抱歉,考试不及格')
# ==> 抱歉,考试不及格
这里有需要注意的地方:
在if语句的最后,有一个冒号:,这是条件分支判断的格式,在最后加入冒号:,表示接下来是分支代码块
Python之if-else语句
比如:在上个例子中,希望当分数小于60分时输出,抱歉,考试不及格,否则,输出恭喜你,考试及格,这个时候可以使用if-else语句。
score = 59
if score < 60:
print('抱歉,考试不及格')
else:
print('恭喜你,考试及格')
同样需要注意两个地方,第一个是冒号:,在else中,同样需要冒号;其次是缩进,在else的子逻辑分支,同样需要缩进。
Python之if-elif-else语句
在100分的考试当中,分数达到或超过90分是顶尖的,达到或超过80分是优秀的,如果想对达到或者超过60分的学生进行不同的分类,使用if-else进行判断,代码如下:
score = 59
if score < 60:
print('抱歉,考试不及格')
else:
if score >= 90:
print('恭喜你,拿到卓越的成绩')
else:
if score >= 80:
print('恭喜你,拿到优秀的成绩')
else:
print('恭喜你,考试及格')
在这个程序里,做了多次分类,第一次,我们把低于60分和大于等于60分的分开,第二次,我们把大于等于90分和小于90分的分开,第三次,我们把大于等于80分和小于80分的分开。
这样写,我们得到一个两层嵌套的if-else语句,这样的实现可以满足我们的要求,但是如果继续增加条件,比如继续判断高于70分和低于70分的话,那么这个代码将会缩进越来越多,代码逻辑看起来也不够清晰。
我们可以使用if-elif-else语句来简化以上的逻辑。其中elif就是else if的意思。
score = 59
if score < 60:
print('抱歉,考试不及格')
elif score >= 90:
print('恭喜你,拿到卓越的成绩')
elif score >= 80:
print('恭喜你,拿到优秀的成绩')
else:
print('恭喜你,考试及格')
特别注意: 这一系列条件判断会从上到下依次判断,如果某个判断为 True,执行完对应的代码块,后面的条件判断就直接忽略,不再执行了。
比如:下面代码会输出’恭喜你,拿到优秀的成绩’,而不会输出’恭喜你,拿到卓越的成绩’。
score = 95
if score < 60:
print('抱歉,考试不及格')
elif score >= 80:
print('恭喜你,拿到优秀的成绩')
elif score >= 90:
print('恭喜你,拿到卓越的成绩')
else:
print('恭喜你,考试及格')
Python之for循环
s = 'ABCD'
for ch in s: #注意冒号
print(ch) # 注意缩进
在上述代码中,ch是在for循环中定义的,意思是把字符串s中的每一个元素依次赋值给ch,然后再把ch打印出来,直到打印出字符串s的最后一个字符为止。
Python之while循环
和 for 循环不同的另一种循环是 while 循环,while循环可以继续进行下去的条件更加简单,只需要判断while循环的条件是否为True即可,当条件为True时,即继续运行下去。
当while无限为真时,会无限运行下去。
比如:
while True:
print(1)
##请不要轻易尝试这个代码
##请不要轻易尝试这个代码
##请不要轻易尝试这个代码
比如计算1~100的和。
num = 1
sum = 0
while num <= 100:
sum = sum + num # 注意缩进
num = num + 1 # 注意缩进
print(sum) # ==> 5050
Python之break跳出循环
用 for 循环或者 while 循环时,如果要在循环体内直接退出循环,可以使用 break 语句。
比如在前面的无限循环里面,只要在恰当的时机,我们使用break跳出循环,也可以求出1~100的和。
num = 1
sum = 0
while True:
if num > 100:
break
sum = sum + num
num = num + 1
print(sum)
同样的,对于字符串s = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’,假如希望输出s的前20个字符,而不是所有字符,我们也可以使用break。
s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
num = 1
for ch in s:
if num > 20:
break
print(ch)
num = num + 1
Python之continue继续循环
使用continue,我们可以控制循环继续下去,并跳过continue后面的逻辑,比如,对于字符串s = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’,假如希望输出字符串s中第10个以后的字符,而不是所有字符,这个时候, 我们可以使用continue跳过前面的9个字符。
s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
num = 1
for ch in s:
if num < 10:
num = num + 1
continue # 当num < 10时,跳过后续循环代码,继续下一次循环
print(ch)
num = num + 1
Python之嵌套循环
我们使用两层嵌套循环输出字符串’ABC’中每个字符和字符串’123’每个字符的排列。
s1 = 'ABC'
s2 = '123'
for x in s1:
for y in s2:
print(x + y)
在上述代码中,对于外层循环,外层每循环1次,内层就会循环3次,
因此,我们将会得到如下结果:
A1
A2
A3
B1
B2
B3
C1
C2
C3
三、Python的List容器
什么是容器、什么是list
在Python中,包括列表(list)、元组(tuple)、字典(dict)、集合(set)等,他们都可以放入多个元素,因此都可以算作是容器,这些容器是Python编程中非常重要的数据结构
list
列表(list)是一种有序的容器,放入list中的元素,将会按照一定顺序排列。构造list的方法非常简单,使用中括号[]把需要放在容器里面的元素括起来,就定义了一个列表。
list可以放入数字、字符串等数据类型,list不对放入其中的类型进行判断,也就是说,list可以同时放入任意类型的数据,这是Python这门语言决定的,因为Python是动态语言。
L = ['Alice', 66, 'Bob', True, 'False', 100]# 注意,字符串元素仍需要引号
对于list,我们可以直接把list的内容打印出来。
L = ['Alice', 66, 'Bob', True, 'False', 100]
print(L)
Python按顺序访问list
列表是有序的,因此我们可以按顺序访问列表中的元素。
L = ['Alice', 66, 'Bob', True, 'False', 100]
for item in L:
print(item)
上面的操作会将L里面的元素一个一个打印输出
Python按索引访问list
names只有四个元素,所以我们最多只能通过索引3访问到最后一个元素。试想一下,如果我们print(names[4]),会怎么样?
names = ['Alice', 'Bob', 'David', 'Ellena']
print(names[4])#访问不存在元素
这会引起Python运行的错误,提示索引访问超出范围。
同时,列表和字符串一样,也支持切片,通过切片的方式,获取到列表的子列表。
names = ['Alice', 'Bob', 'David', 'Ellena']
sub_names = names[0:2]
print(sub_names)
注意:越界切片的话,不会出现Python运行错误,但是按照这样的下标去切片,获取不到任何元素。
Python倒序访问list
Python的列表,除了支持正向顺序索引获取列表中的每一个元素以外,也支持倒序访问list中的每一个元素。
names = ['Alice', 'Bob', 'David', 'Ellena']
对于names列表,Ellena的名字排在最后,也就是我们所说的倒数第一个,在Python中,可以使用-1来表示最后一个元素,也可以使用-2、-3等来表示。
注意:查看不存在元素,也就是越界,同样会报错。
Python向list添加新的元素
假如现在有4名同学,新来一位同学该怎么添加进去?
names = ['Alice', 'Bob', 'David', 'Ellena']
添加元素的方法:第一个办法是用append()方法,把新同学追加到列表的末尾:
names = ['Alice', 'Bob', 'David', 'Ellena']
names.append('Candy')
print(names) # ==> ['Alice', 'Bob', 'David', 'Ellena', 'Candy']
#注意,append()方法总是将元素添加到list的尾部。
如果上面的列表需要按照首字母排序的话,那么Candy应该是排在第三的位置的。
这就需要使用list的insert()方法,insert()方法和append()方法不一样,insert()方法需要两个参数,分别是需要插入的位置,以及需要插入的元素。
names = ['Alice', 'Bob', 'David', 'Ellena']
names.insert(2, 'Candy')
print(names) # ==> ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
注意,将Candy插入到第三的位置之后,原来的名字,都将自动往后移动一位,这个时候再使用相同的索引获取后面的元素,将会得到不一样的结果
Python从list删除元素
如何把Ellena从已有的列表里面删除呢?
这个时候我们可以使用列表的pop()方法,pop()方法默认删除列表的最后一个元素,并返回。
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name = L.pop()
print(name) # ==> Ellena
print(L) # ==> L = ['Alice', 'Bob', 'Candy', 'David']
pop()方法,除了可以删除最后一个元素以外,pop()还可以接收一个参数,指定需要删除的元素的位置。
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name = L.pop(2)
print(name) # ==> Candy
print(L) # ==> ['Alice', 'Bob', 'David', 'Ellena']
Python替换list中的元素
对于列表,除了可以向列表添加元素,删除列表元素以外,列表已有的元素,也是可以修改的,通过索引指定位置,并赋值新的元素,即可替换列表中原有的元素。
假如班上同学Candy需要转走了,同时有一个新的同学Canlina转入,那么按照字母排序,Canlina的位置恰好是Candy的位置。
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
L[2] = 'Canlina'
print(L)
#也可以使用倒序来实现
注意,如果替换一个不存在的下标,则同样会引起Python运行错误。
Python二维list
有时候,一维list并不能满足所有的要求(上述所有list均为一维list),这个时候需要二维list甚至更高维的list。
比如:
Alice最近的三次成绩分别是[100, 89, 92]
Bob最近的三次成绩分别是[70, 65, 81]
Candy最近的三次成绩分别是[88, 72, 77]
如果需要用一个列表存放三个同学的成绩,则需要这样:
alice_scores = [100, 89, 92]
bob_scores = [70, 65, 81]
candy_scores = [88, 72, 77]
all_scores = [alice_scores, bob_scores, candy_scores]
print(all_scores) # ==> [[100, 89, 92], [70, 65, 81], [88, 72, 77]]
这个时候得到的就是一个二维list,对于二维list,列表里面的每一个元素仍然是一个列表。这个时候,如果需要从二维list all_scores获取Bob最近第三次考试的成绩,可以这样写
alice_scores = [100,89,92]
bob_scores = [70,65,81]
candy_scores = [88,72,77]
all_scores = [alice_scores, bob_scores, candy_scores]
score = all_scores[1][2] # ==> 81
其中all_scores[1]得到Bob的最近三次成绩的列表,
再通过下标[2],则可以得到Bob第三次的成绩。
四、Python的tuple容器
什么是tuple
元组(tuple)和list一样,也是一个有序容器,在元组中,同样可以包含0个或者多个元素,并且也支持索引访问、切片等操作。
定义元组的方式是使用小括号()将元组内的元素括起来。
T = ('Alice', 'Bob', 'Candy', 'David', 'Ellena')
# 通过下标的方式访问元素
print(T[0]) # ==> Alice
print(T[4]) # ==> Ellena
# 切片
print(T[1:3]) # ==> ('Bob', 'Candy')
元组数据类型可以把不是元组的容器转换为元组,比如将列表转换成元组。
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
print(L) # ==> ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
T = tuple(L)
print(T) # ==> ('Alice', 'Bob', 'Candy', 'David', 'Ellena')
同样的,对于列表数据类型,也可以把元组转换成列表。
但是,tuple和list不一样的是,tuple是固定不变的,一旦变成tuple,
tuple中的每一个元素都不可被改变,同时也不能再往tuple中添加数据,而list是可以的。
##正因为是这种固定的特性,使在运行上tuple的性能是list的数倍。
访问tuple元素的其他方法
由于tuple一旦定义之后便不可修改,所以在实际编程中,tuple经常用于存放固定不变的数据。
因此在使用上,tuple提供了便捷的方法可以访问tuple中的数据。
count()方法
count()方法用来统计tuple中某个元素出现的次数。
T = (1, 1, 2, 2, 3, 3, 1, 3, 5, 7, 9)
print(T.count(1)) # ==> 3
print(T.count(5)) # ==> 1
对于不存在的元素,count方法不会报错,而是返回0,这是合理的,因为元组里面有0个不存在的元素。
index()方法
index()方法可以返回指定元素的下标,当一个元素多次重复出现时,则返回第一次出现的下标位置。
T = (1, 1, 2, 2, 3, 3, 1, 3, 5, 7, 9)
T.index(9) # ==> 10
T.index(5) # ==> 8
T.index(1) # ==> 0 # 多次出现,返回第一次出现的位置
注意,index()方法和count()方法不一样,当指定的元素不存在时,使用index()方法Python会报错。
Python创建单个元素的tuple
包含 0 个元素的 tuple,也就是空tuple,直接用()表示:
T = ()
print(T) # ==> ()
接着,我们创建包含一个元素的tuple。
T = (1)
print(T) # ==> 1
这和我们期望的输出有些差异,为什么包含一个元素的元组打印出来之后没有小括号,而是只有一个数字1呢?
因为()既可以表示tuple,又可以作为括号表示运算时的优先级,
结果(1)被Python解释器计算出结果 1,导致我们得到的不是tuple,而是整数 1。
因此,要定义只有一个元素的tuple,需要在元素后面添加一个逗号,。
T = (1, )
print(T) # ==> (1, )
而对于多个元素的tuple,则加和不加这个逗号,效果是一样的。
>>> T = (1, 2, 3,)
>>> print(T) # ==> (1, 2, 3)
Python的可变tuple
前面我们学习了,对于tuple,它和list一个最大的不同点就是tuple是不可变的,tuple里面的元素,也是不可替换的。但是这针对的是仅包含基础数据类型(数字类型、布尔类型、字符串类型)的数据,对于组合数据类型,则不受这个约束。
T = (1, 'CH', [3, 4])
这里T有三个元素,第一个元素是数字类型,第二个元素是字符串类型,第三个元素是列表类型的,我们尝试修改第三个元素的数据。
T = (1, 'CH', [3, 4])
L = T[2]
print(L) # ==> [3, 4]
# 尝试替换L中的元素
L[1] = 40
print(L) # ==> [3, 40]
print(T) # ==> (1, 'CH', [3, 40])
这个时候,我们发现,元组T中的第三个元素已经成功被改变了,这就有悖前面的定义,元组是不可改变的。那么这到底是为什么呢?
因为修改的内容指针指向同一个地址
五、Python的Dict容器
什么是dict
python的dict就是专门保存这种映射的,使用dict可以方便的保存“名字”->“成绩”的映射。
在dict中,每一项包含一个key和一个value,key和value是一一对应的,在解决上面的问题中,我们可以使用名字作为key,成绩作为value,那么dict的定义如下:
d = {
'Alice': 45,
'Bob': 60,
'Candy': 75,
'David': 86,
'Ellena': 49
}
在定义里,我们使用花括号{}表示这是一个dict,然后key和value之间使用冒号:分割,并且每一组key:value的最后,以逗号,表示这一组的结束。
我们也可以使用以下的方式定义一个dict。
d = dict()
print(d) # ==> {}
不过这种定义方式,默认得到的是一个空dict,需要调用函数往里面添加数据。
Python读取dict元素
dict提供通过key找到对应value的功能,通过d[key]的形式,就可以得到对应的value。
d = {
'Alice': 45,
'Bob': 60,
'Candy': 75,
'David': 86,
'Ellena': 49,
'Gaven': 86
}
print(d['Bob']) # ==> 60
print(d['Alice']) # ==> 45
在dict中,当对应的key不存在时,也会引发错误。
dict本身提供get方法,把key当作参数传递给get方法,就可以获取对应的value,
当key不存在时,也不会报错,而是返回None。所以更加推荐用get方法。
Python添加dict元素
dict和tuple不一样,dict是可变的,我们随时可以往dict中添加新的key-value
假如Mimi近两次成绩分别是72,73,Dodo近两次的成绩分别是88,90,则可以使用赋值语句往dict中添加list元素。
d['Mimi'] = [72, 73]
d['Dodo'] = [88, 90]
print(d)
此后,如果Mimi、Dodo的第三次成绩也出来了,分别是75,90,则可以先通过key把对应的value查询出来,然后再往类型是list的value中添加第三次的成绩。
d['Mimi'].append(75)
d['Dodo'].append(90)
print(d)
Python更新dict元素
赋值语句其实有两个功能:
d = {
'Alice': 45,
'Bob': 60,
'Candy': 75,
'David': 86,
'Ellena': 49
}
d['Bob'] = 75
print(d)
# ==> {'Alice': 45, 'Bob': 75, 'Candy': 75, 'David': 86, 'Ellena': 49}
当key不存在时,往dict中添加对应的key: value元素。
当key存在时,会更新dict,用新的value替换原来的value。
因此,在使用赋值语句往dict中添加元素时,为了避免不必要的覆盖问题,我们需要先判断key是否存在,然后再做更新。
Python删除dict元素
dict提供便捷的pop()方法,允许我们快速删除元素,pop()方法需要指定需要删除的元素的key,并返回对应的value。
假设Alice转校了,需要把Alice的成绩删除,可以这样写:
d = {
'Alice': 45,
'Bob': 60,
'Candy': 75,
'David': 86,
'Ellena': 49
}
print(d) # ==> {'Alice': 45, 'Bob': 60, 'Candy': 75, 'David': 86, 'Ellena': 49}
alice_score= d.pop('Alice')
print(alice_score) # ==> 45
print(d) # ==> {'Bob': 60, 'Candy': 75, 'David': 86, 'Ellena': 49}
注意,pop()方法的参数是dict中的key,当key不存在时,同样会引起错误。
Python dict的特点
查找速度快
dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样。而list的查找速度随着元素增加而逐渐下降。
不过dict的查找速度快不是没有代价的,dict的缺点是占用内存大,还会浪费很多内容,list正好相反,占用内存小,但是查找速度慢。
有序与无序
在Python3.5之前,dict中的元素是无序的,也就是dict中元素的插入顺序和打印顺序未必一致,一般在需要有序的dict时,我们会使用一种叫做Ordereddict的字典,来确保有序。
key不可变
tuple是不可变的,list是可变的,因此tuple可以作为dict的key,但是list不可以作为dict的key,否则将会报错。
Python遍历dict
通过直接print(d),我们打印出来的是完整的一个dict;有时候,我们需要把dict中m一定条件的元素打印出来,比如成绩超过60的,在这种情况下,我们需要则需要遍历dict(这种时候需要使用for循环),并通过条件判断把满足条件的打印出来。
遍历dict有两种方法, 第一种是遍历dict的所有key,并通过key获得对应的value。
d = {
'Alice': 45,
'Bob': 60,
'Candy': 75,
'David': 86,
'Ellena': 49
}
for key in d: # 遍历d的key
value = d[key]
if value > 60:
print(key, value)
# ==> Candy 75
# ==> David 86
第二种方法是通过dict提供的items()方法,items()方法会返回dict中所有的元素,每个元素包含key和value。
for key, value in d.items():
if value > 60:
print(key, value)
# ==> Candy 75
# ==> David 86
Python操作dict的其他方法
获取dict的所有key
dict提供keys()函数,可以返回dict中所有的key。
d = {'Alice': [50, 61, 66], 'Bob': [80, 61, 66], 'Candy': [88, 75, 90]}
for key in d.keys():
print(key)
# ==> Alice
# ==> Bob
# ==> Candy
获取dict所有的value
dict提供values()函数,可以返回dict中所有的value。
把上述代码的keys函数换成values函数即可。
清除所有元素
dict提供clear()函数,可以直接清除dict中所有的元素。
d = {'Alice': [50, 61, 66], 'Bob': [80, 61, 66], 'Candy': [88, 75, 90]}
print(d) # ==> {'Alice': [50, 61, 66], 'Bob': [80, 61, 66], 'Candy': [88, 75, 90]}
d.clear()
print(d) # ==> {}
六、Python的Set容器
什么是set
前面,我们学习了dict,知道dict的key是不重复的,当我们往dict里添加一个相同key的value时,新的value将会覆盖旧的value。
有的时候,我们只想要 dict 的 key,不关心 key 对应的 value,目的就是保证这个集合的元素不会重复,这时,set就派上用场了。
set和list类似,拥有一系列元素,但是set和list不一样,set里面的元素是不允许重复的,而list里面可以包含相同的元素;set与list的另一个区别是,set里面的元素是没有顺序的。
set里面的元素是唯一的
set里面的元素是无序的
创建set的方式是使用set(),并传入一个list,list的元素将会被转换成set的元素。
s = set([1, 4, 3, 2, 5])
print(s) # ==> set([1, 2, 3, 4, 5])
需要注意的是,上述打印的形式类似 list, 但它不是 list,仔细看还可以发现,打印的顺序和原始 list 的顺序有可能是不同的,因为set内部存储的元素是无序的。
另外,set不能包含重复的元素,我们传入重复的元素看看会发生什么。
s = set([1, 4, 3, 2, 5, 4, 2, 3, 1])
print(s) # ==> set([1, 2, 3, 4, 5])
可以看到,在传入set()的list中,包含了重复的元素,但是打印的时候,相同的元素只保留了一个,重复的元素都被去掉了,这是set的一个重要特点。
Python读取set元素
访问set中的某个元素实际上就是判断一个元素是否在set中,这个时候我们可以使用in来判断某个元素是否在set中。
set里面的元素区分大小写
比如,存储了班里同学名字的set。
names = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name_set = set(names)
请问'Alice'是班里面的同学吗?
'Alice' in name_set # ==> True
请问'Bobby'是班里面的同学吗?
'Bobby' in name_set # ==>False
请问'bob'是班里面的同学吗?
'bob' in name_set # ==> False
'Bob’是在name_set里面的,为什么输出了False呢?这是因为set元素是区分大小写的,必须大小写完全匹配,才能判断该元素在set里面。
Python添加set元素
set添加单个元素add()方法
set添加多个元素update()方法
set添加已存在元素不会报错
set提供了add()方法,我们可以使用add()方法,往set里面添加元素。
比如,班里面来了新的同学,名字叫Gina。
names = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name_set = set(names)
name_set.add('Gina')
print(name_set) # ==> set(['Gina', 'Alice', 'Candy', 'David', 'Ellena', 'Bob'])
可以看到,'Gina'已经添加到name_set里面去了。对于set,如果添加一个已经存在的元素,
不会报错,也不会改变什么。
names = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name_set = set(names)
name_set.add('Alice')
print(name_set) # ==> set(['Bob', 'Ellena', 'Alice', 'Candy', 'David'])
有没有批量往set里面添加元素的方法呢?
set提供了update()方法,可以一次性给set添加多个元素。
比如,新来了一批同学,名字分别是[‘Hally’, ‘Isen’, ‘Jenny’, ‘Karl’],则可以使用update()方法,批量往set中添加。
names = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
new_names = ['Hally', 'Isen', 'Jenny', 'Karl']
name_set = set(names)
name_set.update(new_names) # ==> set(['Jenny', 'Ellena', 'Alice', 'Candy', 'David', 'Hally', 'Bob', 'Isen', 'Karl'])
print(name_set)
Python删除set元素
set删除元素remove()方法
set删除不存在的元素会报错
set提供了remove()方法允许我们删除set中的元素。
name_set = set([‘Jenny’, ‘Ellena’, ‘Alice’, ‘Candy’, ‘David’, ‘Hally’, ‘Bob’, ‘Isen’, ‘Karl’])
name_set.remove(‘Jenny’)
print(name_set) # ==> set([‘Ellena’, ‘Alice’, ‘Candy’, ‘David’, ‘Hally’, ‘Bob’, ‘Isen’, ‘Karl’])
需要注意的是,如果remove的元素不在set里面的话,那么将会引发错误。
Python 操作set的其他方法
set不会报错的删除方法discard()
set清除所有元素的方法clear()
除了使用remove()方法删除元素以外,还可以使用discard()方法删除元素,并且,和remove()不同的是,当元素不存在时,使用discard()并不会引发错误,所以使用discard()是更加高效的一个方法。
集合的子集和超集
set判断子集函数issubset()
set判断超集函数issuperset()
set提供方法判断两个set之间的关系,比如两个集合set,判断其中一个set是否为另外一个set的子集或者超集。
s1 = set([1, 2, 3, 4, 5])
s2 = set([1, 2, 3, 4, 5, 6, 7, 8, 9])
# 判断s1是否为s2的子集
s1.issubset(s2) # ==> True
# 判断s2是否为s1的超集
s2.issuperset(s1) # ==> True
判断集合是否重合
set判断集合是否重合函数isdisjoint()
重合返回false
有时候需要判断两个集合是否有重合的地方,如果使用传统的方法,需要使用for循环一个一个的去判断,非常麻烦,set提供isdisjoint()方法,可以快速判断两个集合是否有重合,如果有重合,返回False,否则返回True。
s1 = set([1, 2, 3, 4, 5])
s2 = set([1, 2, 3, 4, 5, 6, 7, 8, 9])
s1.isdisjoint(s2) # ==> False,因为有重复元素1、2、3、4、5
七、Python的函数
什么是函数
函数,把重复的逻辑代码封装起来,这样子,我们就不需要每次计算的时候,都写重复的代码了;当我们使用函数的时候,我们只需要定义一次,就可以多次使用。
Python不但能非常灵活地定义函数,而且本身内置了很多有用的函数,可以直接调用。
Python调用函数
在这个文档里面,列举了Python内置的大部分函数,同学们有兴趣可以参考看看。
文档打开是英文的,英文不好的同学可以用谷歌打开,谷歌自带翻译功能
https://docs.python.org/3/library/functions.html
要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数 abs(),它接收一个参数。
对于abs()函数,abs就是函数的名称,括号()内,就是函数的参数,当函数没有参数时,默认就是一个空括号。
abs接收一个参数,这个参数就是需要求绝对值的数,这个参数可以是整数,也可以是浮点数
#求绝对值
abs(-100) # ==> 100
abs(20) # ==> 20
abs(-3.14159) # ==> 3.14159
需要注意的是,传递的参数数量一定要和函数要求的一致,不然将会引起错误,比如,如果在abs()函数中传入两个参数,就会报错。
其次,如果传入的参数数量是对的,但是参数的类型不能被函数所接受,也会引起错误,比如:求绝对值的函数abs(),只有数字才拥有绝对值,如果传递一个字符串进去,将会引起错误。
cmp()函数,可以比较两个数的大小,这个时候,cmp()函数就接收两个参数。
对于cmp(x, y),如果x < y 返回 -1,如果x == y 函数返回0,如果x > y函数返回1。
cmp(1, 2) # ==> -1
cmp(2, 1) # ==> 1
cmp(3, 3) # ==> 0
还有基础数据类型的转换函数,int()函数可以将合法的其它类型数据转换为整数,str()函数可以将其它类型的数据转换为字符串。
int('123') # ==> 123
int(12.34) # ==> 12
str(123) # ==> '123'
str(1.23) # ==> '1.23'
Python定义函数
在Python中,自定义一个函数要使用 def 语句,依次写出函数名、括号()、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。
我们以定义一个求绝对值的函数my_abs函数为例:
def my_abs(x):
if x >= 0:
return x
else:
return -x
例子:定义一个square_of_sum()函数,它接收一个list,返回list中每个元素平方的和。
def square_of_sum(L):
sum = 0
for x in L:
sum = sum + x * x
return sum
print(square_of_sum([1, 2, 3, 4, 5]))
print(square_of_sum([-5, 0, 5, 15, 25]))
Python函数返回值
在函数里面使用return返回了计算的结果,在外部调用这个函数的时候,就可以接收到结果。
有时候函数是没有返回结果的,这个时候从函数获取到的是一个空值None。
除了返回None、一个值以外,函数也可以返回多个值,在函数中,如果需要返回多个值,多个值之间使用逗号分隔即可,但是需要注意顺序。
比如,定义一个函数data_of_square,接收边长一个参数,同时返回正方形的周长和面积。
def data_of_square(side):
C = 4 * side
S = side * side
return C, S
C, S = data_of_square(16)
print('周长 = {}'.format(C)) # ==> 周长 = 64
print('面积 = {}'.format(S)) # ==> 面积 = 256
也可以使用一个值存储函数返回的多值结果。
result = data_of_square(16)
print(result) # ==> (64, 256)
注意打印的result,其实它是tuple类型,如果我们需要取出结果中的周长或者面积,使用对应位置的下标就可以获得对应的结果。
result = data_of_square(16)
C = result[0]
S = result[1]
print('周长 = {}'.format(C)) # ==> 周长 = 64
print('面积 = {}'.format(S)) # ==> 面积 = 256
Python递归函数
函数内部,还可以调用其他函数,比如实现函数data_of_square的时候,它接收边长一个参数,同时返回正方形的周长和面积,而求周长和求面积是完全独立的逻辑,可以定义成两个新的函数,然后在data_of_square函数中再调用这两个函数,得到结果并返回。
def square_area(side):
return side * side
def square_perimeter(side):
return 4 * side
def data_of_square(side):
C = square_perimeter(side)
S = square_area(side)
return C, S
在函数内部调用其他函数,是非常常见的,通过合理拆分逻辑,可以降低程序的复杂度。如果在一个函数内部调用其自身,这个函数就是递归函数。
注意:递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,
但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,
每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。
由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
Python函数参数
我们已经简单接触了函数的参数,现在我们正式来认识它。
函数参数可以是任意的数据类型,只要函数内部逻辑可以处理即可。
为了保证函数的正常运行,有时候需要对函数入参进行类型的校验,Python提供isinstance()函数,可以判断参数类型,它接收两个参数,第一个是需要判断的参数,第二个是类型。
isinstance(100, int) # ==> True
isinstance(100.0, int) # ==> False
isinstance('3.1415926', str) # ==> True
有了isinstance,就可以优化my_abs函数,不在里面运行出错了。
def my_abs(x):
if not isinstance(x, int) or not isinstance(x, float):
print('param type error.')
return None
if x >= 0:
return x
else:
return -x
Python函数使用默认参数
默认参数的意思是当这个参数没有传递的时候,参数就使用定义时的默认值。
例如Python自带的 int() 函数,其实就有两个参数,我们既可以传一个参数,又可以传两个参数:
int('123') # ==> 123
int('123', 8) # ==> 83 //8表示8进制
int()函数的第二个参数是转换进制base,如果不传,默认是十进制 (base=10),如果传了,就用传入的参数。
我们来定义一个计算 x 的N次方的函数:
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
假设计算平方的数字最多,我们就可以把 n 的默认值设定为 2:
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
这样一来,计算平方就不需要传入两个参数了。
需要注意的是,由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面,否则将会出现错误。
Python函数使用可变参数
除了默认参数,Python函数还接收一种参数叫做可变参数,可变参数即任意个参数的意思,可变参数通常使用*args来表示。
def func(*args):
print('args length = {}, args = {}'.format(len(args), args))
func('a') # ==> args length = 1, args = ('a',)
func('a', 'b') # ==> args length = 2, args = ('a', 'b')
func('a', 'b', 'c') # ==> args length = 3, args = ('a', 'b', 'c')
Python会把可变参数定义为一个tuple,所以在函数内部,把可变参数当作tuple来使用就可以了,比如可以通过位置下标取出对应的元素等。
假设我们要计算任意个数的平均值,就可以定义一个可变参数:
def average(*args):
sum = 0
for item in args:
sum += item
avg = sum / len(args)
return avg
这样,在调用的时候,我们就可以这样写:
average(1, 2) # ==> 1.5
average(1, 2, 2, 3, 4) # ==> 2.4
average()##为0会报错
# 报错
Traceback (most recent call last):
ZeroDivisionError: division by zero
在执行average()的时候,却报错了,这是因为在使用可变参数时,没有考虑周全导致的,因为可变参数的长度可能是0,当长度为0的时候,就会出现除0错误。因此需要添加保护的逻辑,这是同学在使用过程中需要特别注意的。
Python函数使用可变关键字参数
可变参数在使用上确实方便,函数会把可变参数当作tuple去处理,tuple在使用上有一定的局限性,比如有时候想找到特定位置的参数,只能通过下标的方式去寻找,如果顺序发生变化得时候,下标就会失效,函数逻辑就得重新修改实现。
Python函数提供可变关键字参数,对于可变关键字参数,可以通过关键字的名字key找到对应的参数值,想想这和我们之前学习过的什么类似?是的没错,dict,Python会把可变关键字参数当作dict去处理;对于可变关键字参数,一般使用**kwargs来表示。
例如,想要打印一个同学的信息,可以这样处理:
def info(**kwargs):
print('name: {}, gender: {}, age: {}'.format(kwargs.get('name'),
kwargs.get('gender'), kwargs.get('age')))
info(name = 'Alice', gender = 'girl', age = 16)
对于一个拥有必需参数,默认参数,可变参数,可变关键字参数的函数,定义顺序是这样的:
def func(param1, param2, param3 = None, *args, **kwargs):
print(param1)
print(param2)
print(param3)
print(args)
print(kwargs)
func(100, 200, 300, 400, 500, name = 'Alice', score = 100)
# ==> 100
# ==> 200
# ==> 300
# ==> (400, 500)
# ==> {'name': 'Alice', 'score': 100}
当然,这么多类型的参数,很容易导致出错,在实际使用上,不建议定义这么多的参数。