前言:本片笔记是本人之前学习时所记录的笔记,通篇纯手打,部分图片借鉴黑马与开源程序员ppt课件与开源中国网站
一、python基础
1.1 基础知识
1.1.1 注释
注释:在程序中对程序代码进行解释说明的文字。
作用:注释不是程序,不能被执行,只是对程序代码进行解释说明,让别人可以看懂程序代码的作用,能够大大增强程序的可读性。
- 单行注释:以 #开头,#右侧 的所有文字当做说明,而不是真正要执行的程序,起辅助说明作用;
- 多行注释:以一对三个双引号引起来(“”“注释内容”“”)来解释说明一段代码的作用使用方法,多行注释可以换行。
1.1.2 转义字符
# 转义字符
print('hello\nworld') #\n换行
print('hello\tworld') #\t制表符
print('helloo\tworld')
print('hello\rworld') #\r回车
print('hello\bworld') #\b回退一格,将o回退了
print('www:\\\\baidu.com')
print('老师说:\'asda\'')
# 原字符,不希望字符串中的转义字符起作用就可以使用原字符,就是在字符串之首加上r或者R
print(r'hello\nworld`')
1.1.3 关键字
下面的列表显示了在Python中的保留字。这些保留字不能用作常数或变数,或任何其他标识符名称。
所有 Python 的关键字只包含小写字母。
and | exec | not |
---|---|---|
assert | finally | or |
break | for | pass |
class | from | |
continue | global | raise |
def | if | return |
del | import | try |
elif | in | while |
else | is | with |
except | lambda | yield |
1.1.4 标识符
在python中我们可以给很多的东西起名字,如变量名、方法名、类名等等这些统称为标识符
标识符命名规范:
- 标识符命名中只允许出现:英文、中文(不推荐)、数字、下划线(_)这四类元素
- 不允许以数字开头
- 不可使用关键字
变量命名规范:
- 尽量做到:见名知意、明了简洁
- 当使用多个单词组合变量名时,应使用下划线连接,如:first_number
- 变量中的英文字母应全小写
1.1.5 pass语句
Python pass 是空语句,是为了保持程序结构的完整性。
pass 不做任何事情,一般用做占位语句。
1.2 python中常用的数据类型
1.3 变量
变量:在程序运行时,能存储计算结果或能表示值的抽象概念。
变量定义的格式: 变量名称=变量值
变量的特征:变量的值是可以改变的
1.3.1 查看变量的类型type()
通过type(变量)查看的是变量中存储的数据的类型。因为变量无类型,但它存储的数据有类型。
- 在print语句中直接输出类型信息,如下代码所示
- 用变量存储type()的结果(返回值)
name = '张三'
print(name)#张三
print('标识',id(name))#标识 1927861047728
print('类型',type(name))#类型 <class 'str'>
print('值',name)#值 张三
name = '赵六'
print(name)#赵六
print('标识',id(name))#标识 1927862147856
print('类型',type(name))#类型 <class 'str'>
print('值',name)#值 赵六
name = 333
print(name)#333
print('标识',id(name))#标识 1927861828912
print('类型',type(name))#类型 <class 'int'>
print('值',name)#值 333
name = name-111
print(name)#222
print('标识',id(name))#标识 2432928146768
print('类型',type(name))#类型 <class 'int'>
print('值',name)#值 222
name = '王五'
print(name)#王五
print('标识',id(name))#标识 1927862148240
print('类型',type(name))#类型 <class 'str'>
print('值',name)#值 王五
1.3.2 数据类型转换
数据类型之间,在特定的场景下,是可以相互转换的,比如字符串转数字、数字转字符串等
语句 | 说明 |
---|---|
int(x) | 将x转化为一个整数 |
float(x) | 将x转化为一个浮点数 |
str(x) | 将x转化为字符串 |
- 任何类型都可以转化为字符串
- 字符串不可以随意转化为数字
- 浮点数转整数会丢失掉小数的部分
name = '张三'
age = 20
# 使用str()函数将age由int类型转为 str类型输出
print('我叫' + name + "今年" + str(age) + '岁')#我叫张三今年20岁
print('-----------------str()将其他类型转为str类型-----------')
a = 10
b = 198.8
c = False
print(type(a), type(b), type(c))#<class 'int'> <class 'float'> <class 'bool'>
print(str(a), str(b), str(c), type(str(a)), type(str(b)), type(str(c)))#10 198.8 False <class 'str'> <class 'str'> <class 'str'>
print('-----------------int()将其他类型转为int类型-----------')
s1 = "111"
s2 = 98.7 # 这个转为int类型会丢失小数点后边的内容
s3 = False
s4 = "99.2" # 字符串为小数,没办法转为int类型
print(type(s1), type(s2), type(s3), type(s4))#<class 'str'> <class 'float'> <class 'bool'> <class 'str'>
print(int(s1), int(s2), int(s3), type(int(s1)), type(int(s2)), type(int(s3)))#111 98 0 <class 'int'> <class 'int'> <class 'int'>
print('-----------------float()将其他类型转为float类型-----------')
f1 = "111"
f2 = 98.7
f3 = False
f4 = "99.2"
print(type(f1), type(f2), type(f3), type(f4))#<class 'str'> <class 'float'> <class 'bool'> <class 'str'>
print(float(f1), float(f2), float(f3), float(f4), type(float(f1)), type(float(f2)), type(float(f3)), type(float(f4)))#111.0 98.7 0.0 99.2 <class 'float'> <class 'float'> <class 'float'> <class 'float'>
1.4 字符串
字符串(string),又称文本,是由任意数量的字符如中文、英文、各类符号、数字组成。所以叫做字符的串。
在python中,字符串需要用双引号包括起来
print(510)
print(98.2)
# 输出字符串
print('helloWord')
print("helloWord")
# 输出到文件
fb = open('D:/test.txt', 'a+') # a+ 如果文件不存在则创建,如果存在则追加
print('helloworld', file=fb)
fb.close()
# 不换行输出
print('hello','word','python')
1.4.1 字符串的三种定义方式
- 单引号定义法: name=‘学python’
- 双引号定义法: name=“我学python”
- 三引号定义法: name=“”“我学python”“”
三引号定义法和多行注释的写法一样,同样支持换行操作,使用变量接收它它就是字符串,不使用变量接收它就可以作为多行注释使用。
如果我想要定义的字符串本身是包含:单引号、双引号自身呢?如何写?
- 单引号定义法,可内含双引号
- 双引号定义法,可内含单引号
- 可以使用转义字符(\)来将引号解除效用,编程普通字符串
1.4.2 字符串拼接
如果我们有两个字符串(文本)字面量,可以将其拼成一个字符串,通过+号即可完成,如:print(‘张’+‘三’) #张三
1.4.3 字符串格式化
'''
类型码
%s 字符串
%d 整数
%f 浮点数 %.1f保留一位小数 %.2f保留两位小数
'''
a = 1
b = 2
print("在这里我们打印ab的,a:"+str(a)+",b:"+str(b))#在这里我们打印ab的,a:1,b:2
# 字符串格式化
str1 = "在这里我们打印ab的值,a:%s,b:%s" % (str(a), str(b))
print(str1)#在这里我们打印ab的值,a:1,b:2
print("在这里我们打印ab的值,a:%s,b:%s" % (str(a), str(b)))#在这里我们打印ab的值,a:1,b:2
print("在这里我们打印ab的值,a:%d,b:%d" % (a,b))#在这里我们打印ab的值,a:1,b:2
print("在这里我们打印ab的值,a:%.1f,b:%.2f" % (10.55, 10.55))#在这里我们打印ab的值,a:10.6,b:10.55
1.4.4 格式化精度控制
我们可以使用辅助符号"m.n"来控制数据的宽度和精度
- m,控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效
- n,控制小数点精度,要求是数字,会进行小数的四舍五入
示例:
- %5d:表示将整数的宽度控制在5为,如果数字11,被设置5d,就会变成:【空格】【空格】
【空格】11,用三个空格补足宽度 - %5.2f:表示将宽度控制为5,将小数点精度设置为2,小数点和小数部分也算入宽度计算。如,对11.345设置%7.2后,结果是【空格】【空格】11.35,2个空格补足宽度,小数部分限制2位精度,四舍五入为.35
1.4.5 字符串格式化方式2
通过语法:f"内容{变量}"的格式来快速格式化
a = 1
b = 2
print(f"在这里我们打印ab的值,a:{a},b:{b}" )#在这里我们打印ab的值,a:1,b:2
这种快速格式化的方法不限制类型,不进行精度控制,适合对精度没有要求的时候快速使用
1.5 运算符
1.5.1 算数运算符与赋值运算符
算数运算符:
**赋值运算符:** ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/89ce2dbd6d48423db5b6df90b4591cf0.png)
print('加法运算', 1 + 1)
print('减法运算', 2 - 1)
print('乘法运算', 2 * 3)
print('除法运算', 9 / 3)
print('取整运算', 9 // 4)
print('取余运算', 9 % 4)
print('幂运算', 3 ** 3)
print(9 // 4) # 2
print(-9 // -4) # 2
# 一正一负取整都是向下取整
print(-9 // 4) # -3
print(9 // -4) # -3
print(9 % 4) # 1
print(-9 % -4) # -1
print(-9 % 4) # 3
print(9 % -4) # -3
a = 10
a+=2
print(a)
a-=2
print(a)
a*=2
print(a)
a/=2
print(a)
a//2
print(a)
a%=4
print(a)
a*=2
print(a)
1.5.2 比较运算符与身份运算符
比较运算符:
我们可以通过比较运算符,计算得到布尔类型的结果
身份运算符:
'''
< > == <= >= 省略
'''
a=10
b=10
c=3
print(a==b) #True,说明a与b的value相等
print(a>c) #True
print(c>b) #False
print(a is b) #True,说明a与b的标识,相等
list1=[11,22,33]
list2=[11,22,33]
print(list1==list2) #True
print(list1 is list2) #False
print(list1 is not list2) #True 这里的意思是list1与list2的id不相等,不相等为True
1.5.3 逻辑运算符
a, b = 1, 2
print(a == 1 and b == 2)#True
print(a == 1 and b < 2)#False
print(a != 1 and b == 2)#False
print(a == 1 or b == 1)#True
print(not a == 1)#False
1.5.4 成员运算符:
print('----------------in与not in------------')
s = "hello world"
print("h" in s) # h 是否存在于变量s中 True
print("k" in s)#False
print("k" not in s) # k 是否不存在于变量s中 True
1.5.5 位运算符
按位运算符是把数字看作二进制来进行计算的
#!/usr/bin/python
# -*- coding: UTF-8 -*-
a = 60 # 60 = 0011 1100
b = 13 # 13 = 0000 1101
c = 0
c = a & b; # 12 = 0000 1100
print("1 - c 的值为:", c)
c = a | b; # 61 = 0011 1101
print("2 - c 的值为:", c)
c = a ^ b; # 49 = 0011 0001
print("3 - c 的值为:", c)
c = ~a; # -61 = 1100 0011
print("4 - c 的值为:", c)
c = a << 2; # 240 = 1111 0000
print("5 - c 的值为:", c)
c = a >> 2; # 15 = 0000 1111
print("6 - c 的值为:", c)
#输出结果
#1 - c 的值为: 12
#2 - c 的值为: 61
#3 - c 的值为: 49
#4 - c 的值为: -61
#5 - c 的值为: 240
#6 - c 的值为: 15
1.5.6 运算符优先级
1.6 数据输入
使用input()语句可以从键盘获取输入,使用一个变量结合搜input语句获取的键盘输入内容即可
注意点: 无论键盘输入什么类型的数据,获取道德数据永远都是字符串类型
present = input('大圣想要什么礼物呢?')
print(present, type(present))
a = input("请输入第一个数")
b = input("请输入第二个数")
print('a+b=',int(a)+int(b))
c = int(input("请输入第一个数"))
d = int(input("请输入第二个数"))
print('c+d=',c+d)
1.7 流程控制
1.7.1 分支结构
1.7.1.1 if、if else、if elif else语句
if语法:
if 要判断的条件:
条件成立时要做的事情
if else 语句
if elif else语句
moeny = 1000
s = int(input('请输入取款金额'))
if moeny >= s:
moeny -= s
print('取款成功')
else:
print('取款失败,余额不足')
'''-----------------多if-----------------------'''
s1 = int(input('请输入月份'))
if s1 > 0 and s1 <= 3:
print("春天")
elif s1 > 3 and s1 <= 6:
print('夏天')
elif s1 > 6 and s1 <= 9:
print('秋天')
elif s1 > 9 and s1 <= 12:
print("冬天")
else:
print("不存在该月份")
1.7.1.2 if判读语句的嵌套
num1 =int(input("请输入会员积分"))
if num1>50:
print('是会员')
if num1>=200 :
print("八折")
else:
if num1>100:
print("9折")
else:
print("9.5折")
else:
print('不是会员')
1.7.2 循环控制
1.7.2.1 while循环
while 判断条件(condition):
执行语句(statements)……
执行过程如下:
while循环的注意事项:
- 条件需提供布尔类型结果,True继续,False停止
- 空格缩进不能忘
- 请规划好循环终止条件,否则将无限循环
a =10 #定义三角形的宽度和高度
while a>=1 :
b =a
while b>=1:
print('*', end="")
b-=1
print('')
a-=1
# 运行结果
# **********
# *********
# ********
# *******
# ******
# *****
# ****
# ***
# **
1.7.2.2 使用while嵌套循环打印九九乘法表
for a in range(1, 10):
for b in range(1, 10):
if b <= a:
print(b, "x", a, "=", a * b, end=" ")
print("")
1.7.2.3 for循环
#语法结构
for iterating_var in sequence:
statements(s)
#示例
list1 =range(1,100)
for a in list1 :
print(a)
sum = 0
for b in range(1,101) :
sum+=b
print(sum)
fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
print ('当前水果 : %s' % fruits[index])
print ("Good bye!")
#运行结果
#当前水果 : banana
#当前水果 : apple
#当前水果 : mango
#Good bye!
1.7.2.4 range
for循环语句,本质上是遍历:序列类型
语法:
- range(num),获取一个从0开始,到num结束的数字序列(不含num本身),如range(5),取得的数据室[0,1,2,3,4]
- range(num1,num2),获得一个从num1开始,到num2结束的数字序列(不含num2本身),如range(5,10),取得的数据室[5,6,7,8,9]
- range(num1,num2,step),获取一个从num1开始,到num2结束的数字序列(不含num2本身),数字之间的步长,以step为准(step默认为1),如range(5,10,2)取得的数据为:[5,7,9]
示例:
#range()的三种创建方式
'''第一种创建方式,只有一个参数'''
r =range(10) #默认从0开始,默认相邻两个数相差1,即步长为1
print(r) #range(0, 10)
print(list(r)) #list可以用于查看range对象中的整数序列 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
'''第二种创建方式,给了两个参数,第一个是 起始位置 ,第二个为结束位置'''
r =range(1,10)
print(list(r)) #[1, 2, 3, 4, 5, 6, 7, 8, 9]
'''第三种创建方式,给了三个参数,起始位置、结束位置、步长'''
r =range(1,10,2)
print(list(r)) #[1, 3, 5, 7, 9]
#判断指定的整数在序列中是否存在
print(10 in r) #10不在当前的整数序列
print(9 in r) #9在当前的序列中
print(10 not in r) #10不在当前的整数序列
print(9 not in r) #9在当前的序列中
小练习:
# 练习:随机产生两个数字,计算其总和
# 一道题10分,总计30分,计算总成绩
import random
from turtle import st
successCount = 0 # 答对次数
for item in range(0, 3):
print("第", item, "题")
# 产生两个随机数
num1 = random.randint(0, 100)
num2 = random.randint(0, 100)
inputNum = int(input('请输入 '+str(num1)+'+'+str(num2)+' 的结果'))
if inputNum == num1+num2:
print('恭喜你答对了')
successCount+=1
else:
print('很遗憾,计算错误')
print("")
print('您一共答对了 ', successCount, " 道题,总分:", successCount*10, "分")
1.7.2.5 break 语句
Python break语句,就像在C语言中,打破了最小封闭for或while循环。
break语句用来终止循环语句,即循环条件没有False条件或者序列还没被完全递归完,也会停止执行循环语句。
break语句用在while和for循环中。
如果您使用嵌套循环,break语句将停止执行最深层的循环,并开始执行下一行代码。
示例:
for letter in 'Python': # 第一个实例
if letter == 'h':
break
print('当前字母 :', letter)
var = 10 # 第二个实例
while var > 0:
print('当前变量值 :', var)
var = var -1
if var == 5: # 当变量 var 等于 5 时退出循环
break
print("Good bye!")
#运行结果:
#当前字母 : P
#当前字母 : y
#当前字母 : t
#当前变量值 : 10
#当前变量值 : 9
#当前变量值 : 8
#当前变量值 : 7
#当前变量值 : 6
#Good bye!
1.7.2.6 continue 语句
Python continue 语句跳出本次循环,而break跳出整个循环。
continue 语句用来告诉Python跳过当前循环的剩余语句,然后继续进行下一轮循环。
continue语句用在while和for循环中。
示例:
for letter in 'Python': # 第一个实例
if letter == 'h':
continue
print('当前字母 :', letter)
var = 10 # 第二个实例
while var > 0:
var = var -1
if var == 5:
continue
print('当前变量值 :', var)
print("Good bye!")
#运行结果
#当前字母 : P
#当前字母 : y
#当前字母 : t
#当前字母 : o
#当前字母 : n
#当前变量值 : 9
#当前变量值 : 8
#当前变量值 : 7
#当前变量值 : 6
#当前变量值 : 4
#当前变量值 : 3
#当前变量值 : 2
#当前变量值 : 1
#当前变量值 : 0
#Good bye!
1.8 函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
1.8.1 定义一个函数
你可以定义一个由自己想要功能的函数,以下是简单的规则:
1.函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
2.任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
3.函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
4.函数内容以冒号起始,并且缩进。
5.return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
函数调用
定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行。
如下实例调用了printme()函数:
# 定义函数
def printme( str ):
"打印任何传入的字符串"
print( str)
return
# 调用函数
printme("我要调用用户自定义函数!")
printme("再次调用同一函数")
1.8.2 函数的参数传递
在 python 中,类型属于对象,变量是没有类型的:
a=[1,2,3]
a="Runoob"
以上代码中,[1,2,3] 是 List 类型,“Runoob” 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是 List 类型对象,也可以指向 String 类型对象。
可更改(mutable)与不可更改(immutable)对象
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
- 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
- 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
- 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
- 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
::: tip
python 传不可变对象实例与传可变对象实例这点一定要区分清楚
:::
传不可变对象实例
def ChangeInt( a ):
a = 10
b = 2
ChangeInt(b)
print b # 结果是 2
实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。
传可变对象实例
# 可写函数说明
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print("函数外取值: ", mylist)
实例中传入函数的和在末尾添加新内容的对象用的是同一个引用,故输出结果如下:
函数内取值: [10, 20, 30, [1, 2, 3, 4]]
函数外取值: [10, 20, 30, [1, 2, 3, 4]]
1.8.2.1 必备参数
必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用printme()函数,你必须传入一个参数,不然会出现语法错误:
#可写函数说明
def printme( str ):
"打印任何传入的字符串"
print str
return
#调用printme函数
printme()
以上实例输出结果:
Traceback (most recent call last):
File "test.py", line 11, in <module>
printme()
TypeError: printme() takes exactly 1 argument (0 given)
1.8.2.2 关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
以下实例在函数 printme() 调用时使用参数名:
#可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print("Name: ", name)
print("Age ", age)
return
#调用printinfo函数
printinfo( age=50, name="miki" )
#以上实例输出结果:
#Name: miki
#Age 50
1.8.2.3 默认参数
调用函数时,默认参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:
def printinfo( name, age = 35 ):#这里在定义函数的时候给age设置默认值
"打印任何传入的字符串"
print("Name: ", name)
print("Age ", age)
return
#调用printinfo函数
printinfo( age=50, name="miki" )
printinfo( name="miki" )
#以下为实例结果
#Name: miki
#Age 50
#Name: miki
#Age 35
1.8.2.4 不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。基本语法如下:
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]
加了星号(*)的变量名会存放所有未命名的变量参数。不定长参数实例如下:
def printinfo( arg1, *vartuple ):
"打印任何传入的参数"
print("输出: ")
print(arg1)
for var in vartuple:
print var
return
# 调用printinfo 函数
printinfo( 10 )
printinfo( 70, 60, 50 )
#输出结果
#输出:
#10
#输出:
#70
#60
#50
1.8.2.5 双星号传参
# 双星号传参,可以传递无数的关键字实参
def fun2(**a):
print(a)
fun2(a=1,b=2,c=3)
#输出结果{'a': 1, 'b': 2, 'c': 3}
1.8.2.6 将函数作为参数传递
在python中,函数是可以作为参数传递给其他函数的
def test_func(compute):
result = compute(1,2)
print(f"compute的参数类型是:{type(compute)}")
print(f"计算结果:{result}")
def compute(x,y):
return x+y
test_func(compute)
执行结果
compute的参数类型是:<class 'function'>
计算结果:3
1.8.3 匿名函数
python 使用 lambda 来创建匿名函数。
- lambda只是一个表达式,函数体比def简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
如下实例:
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print("相加后的值为 : ", sum( 10, 20 ))
print("相加后的值为 : ", sum( 20, 20 ))
#以下为输出结果
#相加后的值为 : 30
#相加后的值为 : 40
1.8.4 return 语句
return语句[表达式]退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。之前的例子都没有示范如何返回数值,下例便告诉你怎么做:
def sum( arg1, arg2 ):
# 返回2个参数的和."
total = arg1 + arg2
print("函数内 : ", total)
return total
# 调用sum函数
total = sum( 10, 20 )
print("函数外 : ", total)
#以上实例输出结果:
#函数内 : 30
#函数外 : 30
1.8.4.1 函数多返回值
函数可以定义多个返回值,return多个值即可,返回的多个结果可以通过索引取出对应位置的值
def multi_return():
return_tuple = ('张三', 12)
return return_tuple
def multi_return2():
return '张三', 12
print(multi_return())
result = multi_return2()
print('multi_return2返回值是=,类型是=', result, type(result))
print( result[0])
print( result[1])
以上代码返回结果
('张三', 12)
multi_return2返回值是=,类型是= ('张三', 12) <class 'tuple'>
张三
12
1.8.5 变量作用域
两种最基本的变量作用域:全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:
total = 0 # 这是一个全局变量
# 可写函数说明
def sum( arg1, arg2 ):
#返回2个参数的和."
total = arg1 + arg2 # total在这里是局部变量.
print("函数内是局部变量 : ", total)
return total
#调用sum函数
sum( 10, 20 )
print("函数外是全局变量 : ", total)
#以上实例输出结果:
#函数内是局部变量 : 30
#函数外是全局变量 : 0
g01 = "yes"
g03="bbb"
print(g01)
def fun1():
# 在函数中可以读取到全局变量
print(g03)
# 创建一一个局部变量g01,而不是修改全局变量
# g01="no"
# 通过global定义全局变量g01
# 修改全局变量
global g01
g01="no"
print(g01)
global g02
g02="aaaa"
fun1()
print(g01)
print(g02)
1.8.6 函数的说明文档
对函数进行必要的的注释方便后期调用和维护,我们通常在函数内部使用多行注释标明函数的作用和所需参数以及返回值
1.9 容器类通用
索引和切片
str1= "我是大阿达的开始就阿卡"
# 索引
print(str1[1])#获取第二个字符
print(str1[2])#获取第三个字符
# 切片
# 从容器中取出相应位置的元素
# 语法: 容器[:开始索引,:结束索引,:步长]
# 开始索引默认为0
print(str1[:8])
# 指定开始索引
print(str1[3:])
# 指定开始索引和结束索引
print(str1[1:8])
# 指定开始索引、结束索引和步长
print(str1[1:8:2])
# 指定从容器尾部开始,所以为负数
print(str1[-1:-8:-1])
# 从尾部向前输出
print(str1[::-1])
以上代码输出结果:
是
大
我是大阿达的开始
阿达的开始就阿卡
是大阿达的开始
是阿的始
卡阿就始开的达
卡阿就始开的达阿大是我
1.10 列表List
序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。
Python有6个序列的内置类型,但最常见的是列表和元组。
序列都可以进行的操作包括索引,切片,加,乘,检查成员。
此外,Python已经内置确定序列的长度以及确定最大和最小的元素的方法。
列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现。
列表的数据项不需要具有相同的类型
创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可。如下所示:
list1 = ['physics', 'chemistry', 1997, 2000]
list2 = [1, 2, 3, 4, 5 ]
list3 = ["a", "b", "c", "d"]
#输出结果
#list1[0]: physics
#list2[1:5]: [2, 3, 4, 5]
1.10.1 列表的增删改操作
# 列表
# 1、创建列表
list1 = []
list2 = list()
# 默认值
list3 = ["张安", "李四", "王五"]
list4 = list("赵六孙琪大圣")
# 索引
print(list3[2])
print(list4[2])
# 切片
print(list3[:1])
print(list4[::-1])
# 添加元素
print(list3)
list3.append("老刘")
print(list3)
# 在指定位置添加元素
print(list3)
list3.insert(1, True)
list3.insert(1, 333)
print(list3)
# 删除元素
# 根据元素删除
print(list3)
list3.remove("张安")
print(list3)
# 根据索引删除,索引位置可以使用切片
del list3[2]
del list3[3:]
print(list3)
# 定义元素,目的:可以增删改查元素
# 删除
print(list4)
del list4[1:2]
print(list4)
# 修改
list4[1:2] = ['a', 'b']
print(list4)
list4[1:2] = []
print(list4)
# 遍历列表
for item in list3:
print(item)
# 倒叙遍历列表
# 不建议使用切片倒叙列表
for item in list3[::-1]:
print(item)
# 倒叙遍历列表
# 建议使用range函数
for item in range(len(list3)-1, -1, -1):
print(list3[item])
1.10.2 列表脚本操作符
列表对 + 和 * 的操作符与字符串相似。+ 号用于组合列表,* 号用于重复列表。
如下所示:
Python 表达式 | 结果 | 描述 |
---|---|---|
len([1, 2, 3]) | 3 | 长度 |
[1, 2, 3] + [4, 5, 6] | [1, 2, 3, 4, 5, 6] | 组合 |
[‘Hi!’] * 4 | [‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’] | 重复 |
3 in [1, 2, 3] | True | 元素是否存在于列表中 |
for x in [1, 2, 3]: print x, | 1 2 3 | 迭代 |
1.10.3 Python列表函数&方法
Python包含以下函数:
序号 | 函数 |
---|---|
1 | cmp(list1, list2) 比较两个列表的元素 |
2 | len(list) 列表元素个数 |
3 | max(list)返回列表元素最大值 |
4 | min(list)返回列表元素最小值 |
5 | list(seq) 将元组转换为列表 |
Python包含以下方法:
序号 | 方法 |
---|---|
1 | list.append(obj)在列表末尾添加新的对象 |
2 | list.count(obj) 统计某个元素在列表中出现的次数 |
3 | list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) |
4 | list.index(obj)从列表中找出某个值第一个匹配项的索引位置 |
5 | list.insert(index, obj)将对象插入列表 |
6 | list.pop([index=-1])移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 |
7 | list.remove(obj)移除列表中某个值的第一个匹配项 |
8 | list.reverse()反向列表中元素 |
9 | list.sort(cmp=None, key=None, reverse=False) 对原列表进行排序 |
1.10.4 列表推导式
使用推导式可以一定程度上简化代码
# 列表推导式
list01=[item for item in range(1,20)]
print(list01)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
1.10.5 列表与字符串
列表与字符串是可以相互转换的:
join()可以将列表转化为字符串
split()可以将字符串,按指定分隔符转化为list
list1=[]
for item in range(0,10):
list1.append(str(item))
# join可以将列表转化为字符串
# join前边得是连接符
print("-".join(list1))
print("".join(list1))
str1="张三-李四-王五-赵六"
list2=str1.split("-")
print(list2)
1.10.6 小练习
随机生成一注彩票,再随机买票,看看需要多久才能中奖
from ntpath import join
import random
import operator
# 创建彩票得方法
def createCaipiao():
list1 = []
while len(list1) < 7:
# 生成六个红球,一个篮球
if(len(list1) == 6):
# 生成篮球
num1 = random.randint(1, 16)
list1.append(num1)
else:
# 生成红球
num1 = random.randint(1, 34)
if(num1 not in list1):
list1.append(num1)
return list1
# 生成一注彩票
list1 = createCaipiao()
# 通过循环生成彩票看看中奖需要多久
# 每注彩票2元
money = 0
while True:
list2 = createCaipiao()
if(operator.eq(list1, list2)):
print("恭喜您中奖了,共买了%d注彩票,共花费%d元,中奖号码是%s" %
(money/2, money, str(list2)))
break
else:
money += 2
print("第%d注,号码为:%s" % (money/2, str(list2)))
if money/2 > 100000:
print("我放弃了")
break
1.11 元组
Python 的元组与列表类似,不同之处在于元组的元素不能修改。
元组使用小括号,列表使用方括号。
元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。
tup1 = ('physics', 'chemistry', 1997, 2000)
tup2 = (1, 2, 3, 4, 5 )
tup3 = "a", "b", "c", "d"
创建空元组
tup1 = ()
元组中只包含一个元素时,需要在元素后面添加逗号
tup1 = (50,)
1.11.1 元组的增删改操作
# 1、创建元组
tuple01=()#空元组
tuple01=(1,2,3)#具有默认值
print(tuple01)
# 列表-》元组
tuple01=tuple(["a","b"])
print(tuple01)
# 元组-》列表
list01=list(tuple01)
print(list01)
# 如果元组只有一个元素,需要加逗号
tuple02=(2,)
print(type(tuple02))#int
# 2、获取元素
tuple03=("a","b","c","d","e")
print(tuple03[1])
print(tuple03[3])
print(tuple03[-2:])
print(tuple03[1:4:2])
tuple04=("a","b")
a,b=tuple04
print(a)
print(b)
# 3、遍历元素
for item in tuple03:
print(item)
print("-------------------")
for item in range(len(tuple03)-1,-1,-1):
print(tuple03[item])
1.11.2 元组运算符
与字符串一样,元组之间可以使用 + 号和 * 号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。
Python 表达式 | 结果 | 描述 |
---|---|---|
len((1, 2, 3)) | 3 | 计算元素个数 |
(1, 2, 3) + (4, 5, 6) | (1, 2, 3, 4, 5, 6) | 连接 |
(‘Hi!’,) * 4 | (‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’) | 复制 |
3 in (1, 2, 3) | True | 元素是否存在 |
for x in (1, 2, 3): print x, | 1 2 3 | 迭代 |
1.11.3 元组内置函数
Python元组包含了以下内置函数
序号 | 方法及描述 |
---|---|
1 | cmp(tuple1, tuple2)比较两个元组元素。 |
2 | len(tuple) 计算元组元素个数。 |
3 | max(tuple)返回元组中元素最大值。 |
4 | min(tuple) 返回元组中元素最小值。 |
5 | tuple(seq)将列表转换为元组。 |
1.12 字典
字典是另一种可变容器模型,且可存储任意类型对象,跟java的HashMap是一样的
字典的每个键值 key:value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:
d = {key1 : value1, key2 : value2 }
注意: dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict。
键一般是唯一的,如果重复最后的一个键值对会替换前面的,值不需要唯一。
1.12.1 字典的增删改取操作
# 1、创建字典
dict01={}
dict01=dict()
# 默认值,存放键值对
dict01={
"wj":100,
"zs":80,
"ls":60
}
dict02=dict([("a","b"),("c","d")])
print(dict01)
print(dict02)
# 2、根据key查找元素
print(dict02["a"])
# 查找元素需要注意,如果存在键再查找,例如:
if "qtx" in dict02:
print(dict02["qtx"])
# 3、根据key修改元素
dict02["a"]="bb"
print(dict02)
# 4、添加元素
dict02["e"]="f"
print(dict02)
# 5、删除
del dict02["a"]
print(dict02)
# 6、遍历
# 获取key
for item in dict01:
# 这里的item是key
print(item,dict01[item])
# 获取value
for item in dict01.values():
# 这里的item是值
print(item)
# 获取key和value
for key,value in dict01.items():
# 这里的item是键值对
print(key,value)
1.12.2字典内置函数&方法
Python字典包含了以下内置函数:
序号 | 函数及描述 |
---|---|
1 | cmp(dict1, dict2)比较两个字典元素。 |
2 | len(dict) 计算字典元素个数,即键的总数。 |
3 | str(dict) 输出字典可打印的字符串表示。 |
4 | type(variable) 返回输入的变量类型,如果变量是字典就返回字典类型。 |
Python字典包含了以下内置方法:
序号 | 函数及描述 |
---|---|
1 | dict.clear() 删除字典内所有元素 |
2 | dict.copy()返回一个字典的浅复制 |
3 | dict.fromkeys(seq[, val])创建一个新字典,以序列 seq 中元素做字典的键,val 为字典所有键对应的初始值 |
4 | dict.get(key, default=None)返回指定键的值,如果值不在字典中返回default值 |
5 | dict.has_key(key)如果键在字典dict里返回true,否则返回false |
6 | dict.items() 以列表返回可遍历的(键, 值) 元组数组 |
7 | dict.keys()以列表返回一个字典所有的键 |
8 | dict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
9 | dict.update(dict2)把字典dict2的键/值对更新到dict里 |
10 | dict.values()以列表返回字典中的所有值 |
11 | pop(key[,default])删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。 |
12 | popitem() 返回并删除字典中的最后一对键和值。 |
1.12.3 字典推导式
#字典推导式
# 1 2 3 4 。。。 10 ->平方
dict01={}
for item in range(1,11):
dict01[item] = item**2
print(dict01)#{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
# 字典推导式写法
dict02={item: item**2 for item in range(1,11)}
print(dict02)#{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
# 列表推导式
list01=[item for item in range(1,20)]
print(list01)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
# 至记录大于五的数字
dict02={item: item**2 for item in range(1,11) if item>5}
print(dict02)#{6: 36, 7: 49, 8: 64, 9: 81, 10: 100}
1.13 set集合
Python 中的集合,和java的set概念一样,用来保存不重复的元素,即集合中的元素都是唯一的,互不相同。
从形式上看,和字典类似,Python 集合会将所有元素放在一对大括号 {} 中,相邻元素之间用“,”分隔
同一集合中,只能存储不可变的数据类型,包括整形、浮点型、字符串、元组,无法存储列表、字典、集合这些可变的数据类型,否则 Python 解释器会抛出 TypeError 错误。
并且需要注意的是,数据必须保证是唯一的,因为集合对于每种数据元素,只会保留一份。
# 1、创建集合
set01 = set()
# 创建带默认值的集合
set01=set("abcabde")
print(set01)
str01="".join(list(set01))
print(str01)
# 2、添加元素
set01.add("v")
print(set01)
# 3、删除元素
set01.remove("v")
print(set01)
# 4、获取所有元素
for item in set01:
print(item)
# 5、数学运算
set01={1,2,3}
set02={2,3,4,5}
# 交集
print(set01&set02)
# 并集
print(set01|set02)
# 补集
print(set01^set02)
# 子集
set03={1,2}
print(set03<set01)
print(set03<set02)
# 超集
print(set03>set01)
print(set03>set01)
输出结果:
{'d', 'e', 'c', 'a', 'b'}
decab
{'d', 'v', 'e', 'c', 'a', 'b'}
{'d', 'e', 'c', 'a', 'b'}
d
e
c
a
b
{2, 3}
{1, 2, 3, 4, 5}
{1, 4, 5}
True
False
False
False
1.14 深拷贝与浅拷贝
浅拷贝: 创建一个新对象,但它和原始对象共享内存中的一部分数据。这意味着在新对象上做出的更改会反映在原始对象上。浅拷贝适用于简单对象(例如列表、元组、字典、集合)。
深拷贝: 创建一个新对象,并递归地复制原始对象及其所有子对象。深拷贝意味着在新对象和原始对象之间没有任何引用关系,即在新对象上做出的更改不会反映在原始对象上。深拷贝适用于复杂对象(例如嵌套列表、元组、字典、对象)。
深浅拷贝的区别关键在于拷贝的对象类型是否可变。
我们可以总结出以下三条规则:
- 对于可变对象来说,深拷贝和浅拷贝都会开辟新地址,完成对象的拷贝
- 而对于不可变对象来说,深浅拷贝都不会开辟新地址,只是建立引用关联 ,等价于赋值
- 对于复合对象来说,浅拷贝只考虑最外层的类型,复合类型数据中的元素仍为引用关系;而深拷贝对复合对象会递归应用前两条规则
背后的逻辑也很容易理解,我们可以在 Python 的官方文档里找到如下解释:
Python 的赋值语句不复制对象,而是创建目标和对象的绑定关系。对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象。
不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。
import copy
list1=[800,[1000,5000]]
# 浅拷贝
list3=list1[:]
list2=list1.copy()
# 深拷贝
list4=copy.deepcopy(list1)
二、文件操作
2.1 open()打开函数和文件关闭
2.1.1 文件打开
2.1.2 文件关闭
文件使用结束后必须关闭
一般使用文件对象.close()
2.2 文件读取操作
'''演示文件的读取操作'''
# 打开文件
f = open("C:\\Users\\11839\\Desktop\\开发备注.txt", "r", encoding="UTF-8")
print(type(f))
# 读取文件 read()方法:文件对象.read(num),num表示要从文件中读取的数据的长度(单位是字节),如果没有传入num,那么就表示读取文件中所有的数据。
# print(f"读取10个全部字节的结果:{f.read(10)}")
# print(f"读取全部字节的结果:{f.read()}")
# 读取文件 - readLines()方法:readLines可以按照行的方式把整个文件的内容进行一次性读取,并且返回的是一个列表,其中每一行数据为一个元素
# lines = f.readlines()
# print(f"lines对象类型是:{type(lines)}")
# print(f"lines对象内容是:{lines}")
# 读取文件 readline()方法,每次读取一行数据
# line1=f.readline()
# line2=f.readline()
# line3=f.readline()
# print(f"读取的第1行数据:{line1}")
# print(f"读取的第2行数据:{line2}")
# print(f"读取的第3行数据:{line3}")
# for循环读取文件行
# for line in f:
# print(f"每一行数据是:{line}")
# 文件的关闭
# f.close()
# with open() as f 通过with open语法打开文件可以自动关闭
with open("C:\\Users\\11839\\Desktop\\开发备注.txt", "r", encoding="UTF-8") as f:
for line in f:
print(f"每一行数据是:{line}")
2.3 文件写入操作
# 打开文件
f = open("C:\\Users\\11839\\Desktop\\开发备注1.txt", "w", encoding="UTF-8")
# 文件写入
f.write("hello")
# 刷新到磁盘
# f.flush()
# 关闭文件并刷新缓冲区内容到磁盘
f.close()
2.4 文件追加操作
# 打开文件
f = open("C:\\Users\\11839\\Desktop\\开发备注1.txt", "a", encoding="UTF-8")
# 文件写入
f.write("hello")
# 刷新到磁盘
# f.flush()
# 关闭文件并刷新缓冲区内容到磁盘
f.close()
三、 异常处理
世界没有完美的程序,任何程序在运行的过程中,都有可能出现异常/也就是出现bug,导致程序无法完美运行下去。
当我们的程序遇到了BUG,那么接下来有两种情况:
- 整个程序因为一个BUG停止运行
- 对BUG进行提醒,整个程序继续运行
捕获异常的作用在于:提前假设某处会出现异常,做好提前准备,当真的出现异常的时候,可以有后续手段。
3.1 捕获常规异常
# 基本捕获语法
try:
f = open("linux.txt", "r")
except:
print("出现异常了")
f = open("linux.txt", "w")
3.2 捕获指定的异常
注意事项:
- 如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
- 一般try下方只放一行尝试执行的代码。
# 捕获指定异常
try:
print(name) #会出现变量未定义异常
# 1/0
except NameError as e: #只捕获变量未定义异常
print("出现了变量未定义异常",e)
3.3 捕获多个异常
当捕获多个异常时,可以把要捕获的异常类型的名字,放到except后,并使用元组的方式进行书写。
try:
# print(name) #会出现变量未定义异常
1/0 #出现除0异常
except (NameError,ZeroDivisionError) as e: #捕获变量未定义异常或者除0异常
print("出现了变量未定义异常或者除0异常",e)
3.4 捕获全部异常
Exception是Python中异常的顶级类,可以表示所有异常
try:
# print(name) #会出现变量未定义异常
1/0 #出现除0异常
except Exception as e: #捕获全部异常
print("捕获全部异常",e)
3.5 异常else
# 异常else
try:
print("hello")
except Exception as e:
print("出现异常")
else:
print("未出现异常")
#程序执行结果:
#hello
#未出现异常
3.6 异常的finally
finally表示的是无论是否异常都要执行的代码,例如关闭文件。
3.7 异常的传递
异常是具有传递性的
当函数func01中发生异常,并且没有捕获处理这个异常的时候,异常
会传递到函func02,当func02也没有捕获处理这个异常的时候
main函数会捕获这个异常,这就是异常的传递性
当所有函数都没有捕获异常的时候,程序就会报错
四、Python模块和Python包
4.1 什么是python模块
Python模块(Modu1e),是一个Python文件,以.PY结尾,模块能定义函数,类和变量,模块里也能包含可执行的代码,
模块的作用:python中有很多各种不同的模块,每一个模块都可以帮助我们快速的实现一些功能,比如实现和时间相关的功能就可以使用time模块我们可以认为一个模块就是一个工具包,每一个工具包中都有各种不同的工具供我们使用进而实现各种不同的功能.
4.2 模块的导入
模块的导入方式:
4.2.1 import 模块名
4.2.2 from 模块名 import 功能名
4.2.3 from 模块名 import *
::: warning
该案例与4.2.1最大的区别是两个方式都可以导入全部功能,但4.2.1中使用sleep方法需要使用time.sleep(),在本案例中直接使用sleep()即可
:::
4.2.4 as定义别名
4.3 自定义模块
**注意:**每个Python文件都可以作为一个模块,模块的名字就是文件的名字,也就是说自定义的模块名必须符合标识符命名规则
4.3.1 导入多个模块注意事项
当导入多个模块的时候,且模块内有同名功能,当调用这个同名功能的时候,调用到的是后面导入的模块的功能
4.3.2 __main__变量
4.3.3 __all__变量
4.3.4 父级目录导包报错问题
import os,sys
parentdir=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#跨文件引用
sys.path.append(parentdir+"\\ui") # 添加自己指定的搜索路径
from main_view_ui import Ui_Form
其中parentdir是根文件夹目录, +\ui是要导入包所在的目录名称,main_view_ui是文件名
4.4 Python包
**包的作用:**当我们的模块文件越来越多时,包可以帮助我们管理这些模块,包的作用就是包含多个模块,但包的本质依旧是模块
4.4.1 创建Python包
4.4.2 导入包
4.5 Python第三方包
我们知道,包可以包含一堆的P贝hon模块,而每个模块又内含许多的功能。
所以/我们可以认为:一个包,就是一堆同类型功能的集合体。
phon程序的生态中,有许多非常多的第三方包(非Python官方),可以极大的帮助我们提高开发效率,如:
- 科学计算中常用的:numpy包
- 数据分析中常用的:pandas包
- 大数据计算中常用的:pyspark、apache-flink包
- 图形可视化常用的:matplotlib、pyecharts
- 人工智能常用的:tensorflow
- 等
这些第三方包,极大的丰富了Python的生态,提高了我们的开发效率
但是由于是第三方,所以Python没有内置,所以需要安装它们才可以导入使用
4.5.1 安装第三方包 -pip
第三方包的安装非常简单,我们只需要使用P№n内置的pip程序即可。
打开我们许久未见的:命令提示符程序,在里面输入:
pip install 包名称
即可通过网络快速安装第三方包
pip的网络优化
1.临时加速
由于pip是连接的国外的网站进行包的下载,所以有的时候会速度很慢。
我们可以通过如下命令,让其连接国内的网站进行包的安装:
pip install -i https://pypi.tuna.tsinghua.edu/cn/simple 包名称
https://pypi.tuna.tsinghua.edu/cn/simple是清华大学提供的一个网站,可供pip程序下载第三方包
2.设置镜像源(长期加速)
上面的方法只是临时有效,且比较麻烦,需要我们每次下载时都加上这个地址,因此我们可以直接使用以下代码设置 pip 的源。
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip config set install.trusted-host mirrors.aliyun.com
3.pip国内镜像源:
# 阿里云 http://mirrors.aliyun.com/pypi/simple/
# 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
# 豆瓣 http://pypi.douban.com/simple
# Python官方 https://pypi.python.org/simple/
# v2ex http://pypi.v2ex.com/simple/
# 中国科学院 http://pypi.mirrors.opencas.cn/simple/
# 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
五、案例-数据可视化图表
5.1 了解JSON数据格式
JSON是一种轻量级的数据交互格式。可以按照JSON指定的格式去组织和封装数据
JSON本质上是一个带有特定格式的字符串
主要功能:json就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互
5.1.1 Python数据和JSON数据的相互转换
import json
# 准备列表,列表内每一个元素都是字典,将其转化为json
data=[{"name":"张三","age":18},{"name":"李四","age":30},{"name":"王五","age":20}]
json_str=json.dumps(data,ensure_ascii=False)#带上 ensure_ascii=False 这个参数之后中文可以正常显示
print("转化后的json_str:",json_str,",type:",type(json_str))
# json字符串转Python数据类型
str1='[{"name": "张三", "age": 18}, {"name": "李四", "age": 30}, {"name": "王五", "age": 20}]'
data1=json.loads(str1)#带上 ensure_ascii=False 这个参数之后中文可以正常显示
print("转化后的data:",data1,",type:",type(data1))
5.2 pyecharts模块
Echarts是个由百度开源的数据可视化/凭借着良好的交互性/精巧的图表设计得到了众多开发者的认可,而Python是门富有表达力的语言很适合用于数据处理.当数据分析遇上数据可视化时pyecharts诞生了
官网:pyecharts官网
pyecharts-gallery官方画廊:这个是pyecharts的扩展库
5.2.1 pyecharts安装
pip install pyecharts
5.2.2 配置项
5.2.2.1 全局配置项
全局配置项可通过 set_global_opts 方法设置
配置方法:获取到图标对象后通过 .set_global_opts()方法配置
更多配置项请查看官网
5.2.2.2 系列配置项
系列配置项仅对该系列的y轴数据图表生效,可参考5.2.4案例
# 给折线图对象添加x轴数据
line.add_xaxis(us_data[0]) #x轴是公用的,所以取一个国家数据即可
# 给折线图添加y轴数据
# 这里label_opts设置的是 系列配置项
line.add_yaxis("美国确诊人数", us_data[1],label_opts=LabelOpts(is_show=False))
line.add_yaxis("日本确诊人数",jp_data[1],label_opts=LabelOpts(is_show=False))
line.add_yaxis("印度确诊人数",in_data[1],label_opts=LabelOpts(is_show=False))
5.2.3 基础折线图使用
'''演示pyecharts的基础入门'''
# 导包
from pyecharts.charts import Line
from pyecharts.options import TitleOpts, LegendOpts, ToolboxOpts, VisualMapOpts
# 创建一个折线图对象
line = Line()
# 给折线图对象添加x轴数据
line.add_xaxis(["中国", "英国", "美国"])
# 给折线图添加y轴数据
line.add_yaxis("GDP", [30, 20, 10])
# 设置全局配置项 set_global_opts 来设置
line.set_global_opts(
title_opts=TitleOpts(title="GDP展示", pos_left="center", pos_bottom="1%"),
legend_opts=LegendOpts(is_show=True),
toolbox_opts=ToolboxOpts(is_show=True),
visualmap_opts=VisualMapOpts(is_show=True),
)
# 通过render方法,将代码生成为图形
line.render() # 执行后会在当前目录下生成一个render.html文件
5.2.4 折线图案例
::: tip
印度数据、日本数据、美国数据,地图数据数据见附件
:::
import json
from pyecharts.charts import Line
from pyecharts.options import TitleOpts, LegendOpts, ToolboxOpts, VisualMapOpts,LabelOpts
def init_data(file_path,replace_str):
'''
对文件数据进行处理,处理为折线图数据
:param file_path: 目标文件路径
:param replace_str: 要替换的字符串前缀
:return:
'''
global us_x_date, us_y_date
# 处理数据
f = open(file_path, "r", encoding="UTF-8")
data = f.read() # 读取美国的全部内容
# 去除不合json规范的开头
data = data.replace(replace_str, "")
# 去除不合json规范的结尾
data = data[:-2]
# json转python字典
dict = json.loads(data)
# 获取trend key
trend_data = dict['data'][0]['trend']
# 获取日期数据,用于x轴,取2020年(到314下标结束)
x_date = trend_data["updateDate"][:314]
# 获取确认数据,用于y轴,取2020年(到315下标结束)
y_date = trend_data["list"][0]["data"][:314]
return x_date,y_date
us_data=init_data("j056可视化案例数据/折线图数据/美国.txt","jsonp_1629344292311_69436(")
jp_data=init_data("j056可视化案例数据/折线图数据/日本.txt","jsonp_1629350871167_29498(")
in_data=init_data("j056可视化案例数据/折线图数据/印度.txt","jsonp_1629350745930_63180(")
# 创建一个折线图对象
line = Line()
# 给折线图对象添加x轴数据
line.add_xaxis(us_data[0]) #x轴是公用的,所以取一个国家数据即可
# 给折线图添加y轴数据
# 这里label_opts设置的是 系列配置项
line.add_yaxis("美国确诊人数", us_data[1],label_opts=LabelOpts(is_show=False))
line.add_yaxis("日本确诊人数",jp_data[1],label_opts=LabelOpts(is_show=False))
line.add_yaxis("印度确诊人数",in_data[1],label_opts=LabelOpts(is_show=False))
# 设置全局配置项 set_global_opts 来设置
line.set_global_opts(
title_opts=TitleOpts(title="疫情概况", pos_left="center", pos_bottom="1%"),
legend_opts=LegendOpts(is_show=True),
toolbox_opts=ToolboxOpts(is_show=True),
visualmap_opts=VisualMapOpts(is_show=True),
)
# 通过render方法,将代码生成为图形
line.render() # 执行后会在当前目录下生成一个render.html文件
5.2.5 基础地图演示
5.2.6 全国疫情地图
::: tip
地图数据数据见附件
:::
from pyecharts.options import VisualMapOpts
from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker
import json
# 定义省份
province_list = {
"北京": "北京市",
"天津": "天津市",
"重庆": "重庆市",
"上海": "上海市",
"河北": "河北省",
"山西": "山西省",
"辽宁": "辽宁省",
"吉林": "吉林省",
"黑龙江": "黑龙江省",
"江苏": "江苏省",
"浙江": "浙江省",
"安徽": "安徽省",
"福建": "福建省",
"江西": "江西省",
"山东": "山东省",
"河南": "河南省",
"湖北": "湖北省",
"湖南": "湖南省",
"广东": "广东省",
"海南": "海南省",
"四川": "四川省",
"贵州": "贵州省",
"云南": "云南省",
"陕西": "陕西省",
"甘肃": "甘肃省",
"青海": "青海省",
"台湾": "台湾省",
"内蒙古": "内蒙古自治区",
"广西": "广西壮族自治区",
"宁夏": "宁夏回族自治区",
"新疆": "新疆维吾尔自治区",
"西藏": "西藏自治区",
"香港": "香港特别行政区",
"澳门": "澳门特别行政区",
"台湾": "台湾省"
}
# 读取文件
f = open("./j056可视化案例数据/地图数据/疫情.txt", "r", encoding="UTF-8")
data = f.read()
# 关闭文件
f.close()
# 取各省份数据
data_dict = json.loads(data)
# 从字典里取出省份数据
province_data_list = data_dict["areaTree"][0]["children"]
data_list = [] # 绘图需要使用的列表
# 组装每个省份和确诊人数为元组
for province_data in province_data_list:
# province_name = province_data["name"]
province_name = province_list[province_data["name"]] # 从此前的集合中获取对应的省份全称
province_confirm = province_data["total"]["confirm"]
# 将数据添加进列表
data_list.append((province_name, province_confirm))
# 准备地图对象
map = Map()
# 添加数据
# map.add("全国疫情实时地图", data_list, "china")
map.add("全国疫情实时地图", [list(z) for z in data_list], "china")
# 设置全局选项
map.set_global_opts(
visualmap_opts=VisualMapOpts(
is_show=True,
is_piecewise=True,
pieces=[
{"min": 1, "max": 499, "label": "1-499", "color": "##DCDCDC"},
{"min": 500, "max": 999, "label": "500-999", "color": "#FFFACD"},
{"min": 1000, "max": 1499, "label": "1000-1499", "color": "#FFFFFF"},
{"min": 1500, "max": 1999, "label": "1000-1999", "color": "#BBFFFF"},
{"min": 2000, "max": 4999, "label": "2000-4999", "color": "#7FFFD4"},
{"min": 5000, "max": 9999, "label": "5000-9999", "color": "#FF3030"},
{"min": 10000, "label": "600以上", "color": "#8B1A1A"}
]
)
)
# 绘图
map.render()
5.2.7 河南省疫情地图绘制
河南省疫情地图数据使用的跟5.2.6中的地图数据一致
from pyecharts.options import VisualMapOpts
from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker
import json
# 读取文件
f = open("./j056可视化案例数据/地图数据/疫情.txt", "r", encoding="UTF-8")
data = f.read()
# 关闭文件
f.close()
# 取各省份数据
data_dict = json.loads(data)
# 从字典里取出市数据
city_data_list = data_dict["areaTree"][0]["children"][3]["children"]
data_list = [] # 绘图需要使用的列表
# 组装每个市和确诊人数为元组
for city_data in city_data_list:
city_name = city_data["name"]+"市"
city_confirm = city_data["total"]["confirm"]
# 将数据添加进列表
data_list.append((city_name, city_confirm))
# 准备地图对象
map = Map()
# 添加数据
map.add("河南省疫情数据", data_list, "河南")
# map.add("全国疫情实时地图", [list(z) for z in data_list], "china")
# 设置全局选项
map.set_global_opts(
visualmap_opts=VisualMapOpts(
is_show=True,
is_piecewise=True,
pieces=[
{"min": 1, "max": 49, "label": "1-49", "color": "##DCDCDC"},
{"min": 50, "max": 99, "label": "50-99", "color": "#FFFACD"},
{"min": 100, "max": 149, "label": "100-149", "color": "#FFFFFF"},
{"min": 150, "max": 199, "label": "100-199", "color": "#BBFFFF"},
{"min": 200, "max": 499, "label": "200-499", "color": "#7FFFD4"},
{"min": 500, "max": 999, "label": "500-999", "color": "#FF3030"},
{"min": 1000, "label": "1000以上", "color": "#8B1A1A"}
]
)
)
# 绘图
map.render()
5.2.8 基础柱状图
from pyecharts.charts import Bar
from pyecharts.options import LabelOpts
# 使用Bar构建基础柱状图
bar = Bar()
# 添加x轴数据
bar.add_xaxis(["中国", "美国", "英国"])
# 添加y轴数据,在label_opts中设置y轴配置项,设置数值标签在右侧
bar.add_yaxis("GDP", [30, 20, 10], label_opts=LabelOpts(position="right"))
# 反转x轴y轴
bar.reversal_axis()
# 绘图
# bar.render("基础柱状图.html")#这个是指定名称的
bar.render()
5.2.9 基础时间线柱状图
from pyecharts.charts import Bar, Timeline
from pyecharts.options import LabelOpts
from pyecharts.globals import ThemeType
bar1 = Bar()
bar1.add_xaxis(["中国", "美国", "英国"])
bar1.add_yaxis("GDP", [30, 20, 10], label_opts=LabelOpts(position="right"))
bar1.reversal_axis()
bar2 = Bar()
bar2.add_xaxis(["中国", "美国", "英国"])
bar2.add_yaxis("GDP", [50, 60, 30], label_opts=LabelOpts(position="right"))
bar2.reversal_axis()
bar3 = Bar()
bar3.add_xaxis(["中国", "美国", "英国"])
bar3.add_yaxis("GDP", [100, 80, 50], label_opts=LabelOpts(position="right"))
bar3.reversal_axis()
# 构建时间线对象,被配置主题设置
timeline = Timeline({"theme":ThemeType.LIGHT})
# 在时间线内添加柱状图对象
timeline.add(bar1, "点1")
timeline.add(bar2, "点2")
timeline.add(bar3, "点3")
# 设置自动播放
timeline.add_schema(
play_interval=1000, # 自动播放的时间间隔,单位毫秒
is_timeline_show=True, # 是否在自动播放的时候显示时间线
is_auto_play=True, # 是否自动播放
is_loop_play=True # 是否循环播放
)
# 绘图是用时间线对象绘图,而不是bar对象绘图了
timeline.render()
5.2.10 动态GDP图案例
列表的sort方法,案例中需要使用
5.2.10.1 案例需求分析:
5.2.10.2 数据
::: tip
数据见附件
:::
5.2.10.3 案例实现
from pyecharts.charts import Bar, Timeline
from pyecharts.options import LabelOpts,TitleOpts
from pyecharts.globals import ThemeType
#读取数据
f=open("./j056可视化案例数据/动态柱状图数据/1960-2019全球GDP数据.csv","r",encoding="GB2312")
data_lines=f.readlines()
# 关闭文件
f.close()
# 删除第一条数据
data_lines.pop(0)
# 将数据转化为字典存储,格式为:
# {年份:[ [国家,gdp], [国家,gdp], [国家,gdp], ...], {年份:[ [国家,gdp], [国家,gdp], [国家,gdp], ...], ...}
# 先定义一个字典对象
data_dict={}
for line in data_lines:
year=int(line.split(",")[0]) #年份
country=line.split(",")[1] #国籍
gdp=float(line.split(",")[2]) #gdp
#如果字典中有指定的key就放入列表,没有就创建
try:
# 不报错说明有这个key
data_dict[year].append([country,gdp])
except KeyError:
# 报错说明没这个key,那么就创建
data_dict[year]=[]
data_dict[year].append([country,gdp])
# 构建时间线对象,被配置主题设置
timeline = Timeline({"theme":ThemeType.LIGHT})
# 排序年份
sorted_year_list=sorted(data_dict.keys())
for year in sorted_year_list:
# 将每一年的数据排序
data_dict[year].sort(key=lambda element:element[1],reverse=True)
# 取出本年份排名前8的国家
year_data=data_dict[year][0:8]
# 构建柱状图数据
x_data=[]
y_data=[]
for country_gdp in year_data:
x_data.append(country_gdp[0])#x轴添加国家
y_data.append(country_gdp[1]/100000000)#y轴添加gdp,亿为单位
#构建柱状图
bar=Bar()
x_data.reverse()#反转数据
y_data.reverse()#反转数据
bar.add_xaxis(x_data)
bar.add_yaxis("GDP(亿)",y_data,label_opts=LabelOpts(position="right"))
# 反转x轴Y轴
bar.reversal_axis()
# 设置每一年的图表标题
bar.set_global_opts(
title_opts=TitleOpts(title=f"{year}年全球前8GDP数据")
)
timeline.add(bar,str(year))
# 设置自动播放
timeline.add_schema(
play_interval=1000, # 自动播放的时间间隔,单位毫秒
is_timeline_show=True, # 是否在自动播放的时候显示时间线
is_auto_play=True, # 是否自动播放
is_loop_play=True # 是否循环播放
)
# 绘制
timeline.render()
六、面向对象
6.1 类与对象
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
6.1.1 初识对象
6.1.1.1 成员变量和成员方法
(1)成员方法的定义语法
(2)注意事项
#定义一个带有成员方法的类
class Student:
name=None #学生的姓名
def say_hi(self):
print(f"我是{self.name},多多关照")
def say_hi2(self,msg):
print(f"大家好我是:{self.name},{msg}")
stu1 = Student()
stu1.name="张三"
stu1.say_hi()#我是张三,多多关照
stu1.say_hi2("不错哦")#大家好我是:张三,不错哦
stu2 = Student()
stu2.name="李四"
stu2.say_hi()#我是李四,多多关照
stu2.say_hi2("看好你")#大家好我是:李四,看好你
6.1.2 构造方法 init()
Python类可以使用: init(),称之为构造方法。
可以实现:
- 在创建类对象(构造类)的时候,会自动执行
- 在创建类对象(构造类)的时候,会将传入参数自动传递给 __init__方法使用
构造方法注意事项:
class Student:
name=None
age=None
tel=None
def __init__(self,name,age,tel):
self.name=name
self.age=age
self.tel=tel
print("Student类创建了一个对象")
def say(self):
print(f"我叫{self.name},年龄{self.age},电话号:{self.tel}")
stu1=Student("张三",18,"13849777777")
stu2=Student("李四",13,"13246579897")
stu1.say()
stu2.say()
6.1.3 内置方法
6.1.3.1 __str__字符串方法
6.1.3.2 __lt__小于符号比较方法
6.1.3.3 __le__小于等于比较符号方法
6.1.3.4 __eq__比较运算符实现方法
6.1.3.5 代码
class Student:
name = None
age = None
tel = None
def __init__(self, name, age, tel):
self.name = name
self.age = age
self.tel = tel
print("Student类创建了一个对象")
def __str__(self):
return f"我叫{self.name},年龄{self.age},电话号:{self.tel}"
# __lt__方法
def __lt__(self, other):
return self.age < other.age
#__le__方法
def __le__(self, other):
return self.age<=other.age
#__eq__方法
def __eq__(self, other):
return self.age==other.age and self.name==other.name and self.tel==other.tel
stu1 = Student("张三", 18, "13849777777")
stu2 = Student("李四", 13, "13246579897")
stu3 = Student("李四", 13, "13246579897")
# __str__
print(stu1) # 我叫张三,年龄18,电话号:13849777777
print(stu2) # 我叫李四,年龄13,电话号:13246579897
# __lt__
print(stu1<stu2) #False
print(stu1>stu2) #True
#__le__方法
print(stu1==stu2) #False
print(stu1>stu2) #True
# __eq__方法
print(stu1==stu2) #False
print(stu2==stu3) #True
6.1.4 封装
class Wife:
def __init__(self, name, age, weight):
self.name = name
# 这里下面定义两个私有变量
# 本质:实际上python将变量名改为了 _类名__变量名
# self.__age = age
self.set_age(age)
self.__weight = weight
def get_age(self):
return self.__age
def get_weight(self):
return self.__weight
def set_age(self, value):
if 21 <= value <= 31:
self.__age = value
else:
raise ValueError("年龄不合适")
def set_weight(self,value):
self.__weight=value
# w01 = Wife("啊飒飒的", 13, 44)
w01 = Wife("啊飒飒的", 22, 44)
# 对象.__dict__ 是python内置变量,存储对象的实例变量
print(w01.__dict__)
print(w01.get_age())
# w01.set_age(10)
w01.set_age(30)
print(w01.get_age())
class Wife:
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight
def get_age(self):
return self.__age
def get_weight(self):
return self.__weight
def set_age(self, value):
if 21 <= value <= 31:
self.__age = value
else:
raise ValueError("年龄不合适")
def set_weight(self, value):
self.__weight = value
# 属性,property拦截对类变量age的读写操作
age = property(get_age, set_age)
# w01 = Wife("啊飒飒的", 13, 44)
w01 = Wife("啊飒飒的", 22, 44)
# 对象.__dict__ 是python内置变量,存储对象的实例变量
print(w01.__dict__)
print(w01.age)#使用property拦截之后也可以直接.出来变量
# w01.set_age(10)
w01.set_age(30)
print(w01.age)
w01.set_age(35)
class Wife:
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.weight = weight
@property # 创建propertu对象只负责拦截读取操作
def age(self):
return self.__age
@age.setter # 只负责拦截写入操作
def age(self, value):
if 21 <= value <= 31:
self.__age = value
else:
raise ValueError("年龄不合适")
@property
def weight(self):
return self.__weight
@weight.setter
def weight(self, value):
self.__weight = value
# w01 = Wife("啊飒飒的", 13, 44)
w01 = Wife("啊飒飒的", 22, 44)
# 对象.__dict__ 是python内置变量,存储对象的实例变量
print(w01.__dict__)
print(w01.age) # 使用property拦截之后也可以之间.出来变量
w01.age=30
print(w01.age)
w01.age=35
6.2 继承
继承的引出
6.2.1 多继承
::: warning
多继承的多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。
即:先继承的保留,后继承的被覆盖
:::
class Phone :
IMEI = None #序列号
producer="HM" #厂商
def call_by_4g(self):
print("4g通话")
class Phone2022(Phone):
face_id="100001" #面部识别id
def call_by_5g(self):
print("5g通话")
phone = Phone2022()
phone.call_by_4g()
phone.call_by_5g()
print(phone.producer)
# 演示多继承
class NFCReader:
nfc_type="第五代"
producer="DM"
def read_card(self):
print("NFC读卡")
def write_card(self):
print("NFC写卡")
class RemoteControl:
rc_type="红外遥控"
def control(self):
print("红外遥控开启了")
class MyPhone(Phone,NFCReader,RemoteControl):
pass #补全语法
myPhone = MyPhone()
print(myPhone.producer)
myPhone.call_by_4g()
myPhone.read_card()
myPhone.write_card()
myPhone.control()
6.2.2 复写
调用父类的同名成员
class Phone :
IMEI = None #序列号
producer="HM" #厂商
def call_by_4g(self):
print("4g通话")
# 定义子类,复写父类的成员和方法
class MyPhone(Phone):
producer = "盛海" #复写父类的成员属性
def call_by_4g(self):
print("被复写的4g通话方法开始")
# 方式一
print(f"父类的厂商是:{Phone.producer}")
Phone.call_by_4g(self) #调用父类的方法
# 方式二
super().call_by_4g()#调用父类的方法
print("被复写的4g通话方法结束")
phone =MyPhone()
phone.call_by_4g()#被复写的4g通话方法
print(phone.producer)#盛海
print(phone.IMEI)#None
6.3 多态(接口)
为什么要实现抽象类呢?
抽象类就好比定义一个标准,包含一些抽象的方法,要求子类必须实现
'''演示面向对象得多态特性以及抽象类(接口)得使用'''
class Animal:
def speak(self):
pass
def eat(self):
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
def eat(self):
print("小狗吃")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def eat(self):
print("小猫吃")
def make_noise(animal:Animal):
'''制造点噪音,需要传入Animal对象'''
animal.speak()
animal.eat()
# 演示多态,使用2个子类对象来调用函数
dog=Dog()
cat=Cat()
make_noise(dog)#汪汪汪 小狗吃
make_noise(cat)#喵喵喵 小猫吃
七、 类型注解
为什么需要
7.1 变量得类型注解
在注释中进行类型注解
类型注解得限制
'''演示变量的类型注解'''
import json
import random
# 基础数据类型注解
var_1:int=10
var_2:str="aaa"
var_3:bool=True
# 类对象注解
class Student:
pass
stu:Student=Student()
# 基础容器类型注解
my_list:list=[1,2,3]
my_tuple:tuple=(1,2,3)
my_dict:dict={"aa":666}
# 容器类型详细注解
my_list:list[int]=[1,2,3]
my_tuple:tuple[int,str,bool]=(1,"bbb",True)
my_dict:dict[str:int]={"aa":666}
# 在注释中进行类型注解
var_1=random.randint(1,10) #type:int
var_2=json.loads('{"name":"zhangsan"}') #type:dict[str,str]
def func():
return 10
var_3=func() #type:int
7.2 函数(方法)得类型注解
'''演示对函数进行类型注解'''
# 对形参进行类型注解
def add(x: int, y: int):
return x + y
add(10,20)
# 对返回值进行类型注解
def func(data:list)->list:
return data
print(func([1,2]))
7.3 Union类型
'''演示Union联合类型注解'''
# 使用Union类型必须先导包
from typing import Union
my_list:list[Union[int,str]]=[1,2,"sss","aaa"]
def func(data:Union[int,str])->Union[int,str]:
pass
func()
八、数据分析案例
目标:
- 使用面向对象思想完成数据读取和处理
- 基于面向对象思想重新认识第三方库得使用(PyEcharts)
::: tip
代码中所用到的数据文件见该文件附件中
:::
main.py
"""
面向对象,数据分许案例,主业务逻辑代码
实现步骤:
1.设计一个类,可以完成数据得封装
2.设计一个抽象类,定义文件读取相关的功能,并使用子类实现具体得功能
3.读取文件,生产数据对象
4.进项数据需求得逻辑计算(计算每一天得销售额)
5.通过PyEcharts进行图形绘制
"""
from file_define import FileReader,TextFileReader,JsonFileReader
from data_define import Record
from pyecharts.charts import Bar
from pyecharts.options import *
from pyecharts.globals import ThemeType
text_file_reader=TextFileReader("2011年1月销售数据.txt")
json_file_reader=JsonFileReader("2011年2月销售数据JSON.txt")
jan_data:list[Record]=text_file_reader.read_data()
feb_data:list[Record]=json_file_reader.read_data()
# 将两个月份的数据合并
all_data:list[Record]=jan_data+feb_data
# 开始进行数据计算
data_dict={}
for record in all_data:
if record.date in data_dict.keys():
#当前日期已经有记录了,所以和老记录累加
data_dict[record.date]+=record.money
else:
data_dict[record.date]=record.money
# 可视化图表开发
bar=Bar(init_opts=InitOpts(theme=ThemeType.LIGHT))
bar.add_xaxis(list(data_dict.keys()))#添加x数据
bar.add_yaxis("销售额",list(data_dict.values()),label_opts=LabelOpts(is_show=False))#添加y轴数据
bar.set_global_opts(
title_opts=TitleOpts(title="每日销售额")
)
bar.render("每日销售额柱状图.html")
file_define.py
'''和文件相关得类定义'''
import json
from data_define import Record
# 先定义一个抽象类用来左顶层设计,确定有哪些功能需要实现
class FileReader:
def read_data(self) -> list[Record]:
'''读取文件得数据,读取到得每一条数据都转换为Record对象,将他们都封装到list内返回即可'''
pass
class TextFileReader(FileReader):
def __init__(self,path):
self.path=path #定义成员变量记录文件得路径
def read_data(self) -> list[Record]:
f=open(self.path,"r",encoding="UTF-8")
record_list:list[Record]=[]
for line in f.readlines():
line=line.strip()#消除读取到得每一行数据中得 \n
data_list=line.split(",")
record = Record(data_list[0],data_list[1],int(data_list[2]),data_list[3])
record_list.append(record)
f.close()
return record_list
class JsonFileReader(FileReader):
def __init__(self,path):
self.path=path #定义成员变量记录文件得路径
def read_data(self) -> list[Record]:
f=open(self.path,"r",encoding="UTF-8")
record_list:list[Record]=[]
for line in f.readlines():
data_dict=json.loads(line)
record=Record(data_dict["date"],data_dict["order_id"],int(data_dict["money"]),data_dict["province"])
record_list.append(record)
f.close()
return record_list
if __name__=="__main__":
text_file_reader=JsonFileReader("2011年2月销售数据JSON.txt")
data.define.py
'''数据定义的类'''
class Record:
def __init__(self, date, order_id, money, province):
self.date = date # 订单日期
self.order_id = order_id # 订单ID
self.money = money # 订单金额
self.province = province # 销售省份
def __str__(self):
return f"{self.date},{self.order_id},{self.money},{self.province}"
八、 Mysql数据库的简单使用
::: tip
MySql的相关教程后续见其相关博客文章
:::
8.1 pymysql
#安装pymysql
pip install pymysql
创建到MySQL的数据库连接
执行非查询性质的SQL语句
执行查询性质的SQL语句
'''演示Python pymysql库的基础操作'''
from pymysql import Connection
# 构建到MySql数据库的链接
conn = Connection(
host="127.0.0.1", # 主机名
port=3306, # 端口号
user="root", # 用户名
password="root" # 密码
)
print(conn.get_server_info())
# 执行非查询性质语句
curosr=conn.cursor()#获取游标对象
# 选择数据库
conn.select_db("test")
# 执行sql
# curosr.execute("create table test_pymysql(id int);")
curosr.execute("select * from test1")
result:tuple=curosr.fetchall()
for r in result:
print(r)
# 关闭连接
conn.close()
commit提交
'''演示Python pymysql库的基础操作'''
from pymysql import Connection
# 构建到MySql数据库的链接
conn = Connection(
host="127.0.0.1", # 主机名
port=3306, # 端口号
user="root", # 用户名
password="root" ,# 密码
autocommit=True #设置自动提交
)
print(conn.get_server_info())
# 执行非查询性质语句
curosr=conn.cursor()#获取游标对象
# 选择数据库
conn.select_db("test")
# 执行sql
# curosr.execute("create table test_pymysql(id int);")
curosr.execute("insert into student values(1001,'张三','男',31)")
# 通过commit确认
conn.commit()
# 关闭连接
conn.close()
九、 PySpark的简单使用
9.1 安装
使用pip进行安装
pip install pyspark
9.2 简单使用
- 构建PySPark执行环境入口对象
'''
演示获取PySPark的执行环境入库对象,SparkContext
并通过SparkContext对象获取当前的PySPark的版本
'''
# 导包
from pyspark import SparkConf, SparkContext
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 打印PySPark运行版本
print(sc.version)
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.3 数据输入
- RDD对象
- Python数据容器转RDD对象
- 读取文件转RDD对象
# 导包
from pyspark import SparkConf, SparkContext
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 通过parallelize方法将Python对象加载到SparkContext内,称为RDD对象
rdd1=sc.parallelize([1,2,3,4,5])
rdd2=sc.parallelize((1,2,3,4,5))
rdd3=sc.parallelize("abcdefg")
rdd4=sc.parallelize({1,2,3,4,5})
rdd5=sc.parallelize({"key1":"val1","key2":"val2"})
# 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd1.collect())#[1, 2, 3, 4, 5]
print(rdd2.collect())#[1, 2, 3, 4, 5]
print(rdd3.collect())#['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(rdd4.collect())#[1, 2, 3, 4, 5]
print(rdd5.collect())#['key1', 'key2']
# t=通过textFile方法,读取文件数据加载到Spark中
rdd6=sc.textFile("D:/test.txt")
print(rdd6.collect())
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.4 数据计算
9.4.1 map方法
# 导包
from pyspark import SparkConf, SparkContext
import os
# 设置Python解释器位置
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 准备一个RDD
rdd=sc.parallelize([1,2,3,4,5])
# 通过map方法将所有数据乘以10
def func(data):
return data*10
rdd2=rdd.map(func)
rdd3=rdd.map(lambda x:x*10)#通过lambda表达式简化
print(rdd.collect())#[1, 2, 3, 4, 5]
print(rdd2.collect())#[10, 20, 30, 40, 50]
print(rdd3.collect())#[10, 20, 30, 40, 50]
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.4.2 flatMap方法
# 导包
from pyspark import SparkConf, SparkContext
import os
# 设置Python解释器位置
os.environ['PYSPARK_PYTHON'] = "G:/python/python.exe"
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 准备一个RDD
rdd = sc.parallelize(['aaasd fass 666' , 'asddfsljlj shkj shki' , 'python itamsh' ])
# 需求:将RDD数据里边的一个个单词提取出来
rdd2 = rdd.flatMap(lambda x: x.split(""))
print(rdd2.collect())
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.4.3 reduceByKey方法
# 导包
from pyspark import SparkConf, SparkContext
import os
# 设置Python解释器位置
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 准备一个RDD
rdd=sc.parallelize([("男",99),("女",66),("女",88),("男",33)])
# 求男生和女生两个组成绩之和
rdd2=rdd.reduceByKey(lambda a,b:a+b)
print(rdd2.collect())#[('男', 132), ('女', 154)]
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.4.4 filter方法
# 导包
from pyspark import SparkConf, SparkContext
import os
# 设置Python解释器位置
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 准备一个RDD
rdd=sc.parallelize([1,2,3,4,5])
# 返回大于3的数
rdd2=rdd.filter(lambda x:x>3)#通过lambda表达式简化
print(rdd.collect())#[1, 2, 3, 4, 5]
print(rdd2.collect())#[4, 5]
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.4.4 distinct方法
# 导包
from pyspark import SparkConf, SparkContext
import os
# 设置Python解释器位置
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
# 创建SparkCong类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext类对象
sc = SparkContext(conf=conf)
# 准备一个RDD
rdd=sc.parallelize([1,2,3,4,4,5,1,3,4,5,44,2])
# 求男生和女生两个组成绩之和
rdd2=rdd.distinct()
print(rdd2.collect())#[1, 2, 3, 4, 5, 44]
# 停止SparkContext对象的运行(停止PySPark程序)
sc.stop()
9.4.5 sortBy方法
"""
演示RDD的sortBy成员方法的使用
代码中得hello.txt文件内容为随机单词,如:
python python spark pyspark pyspark
python1 python1 spark1 pyspark1 pyspark1
"""
from pyspark import SparkConf, SparkContext
import os
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)
# 1. 读取数据文件
rdd = sc.textFile("D:/hello.txt")
# 2. 取出全部单词
word_rdd = rdd.flatMap(lambda x: x.split(" "))
# 3. 将所有单词都转换成二元元组,单词为Key,value设置为1
word_with_one_rdd = word_rdd.map(lambda word: (word, 1))
# 4. 分组并求和
result_rdd = word_with_one_rdd.reduceByKey(lambda a, b: a + b)
# 5. 对结果进行排序
final_rdd = result_rdd.sortBy(lambda x: x[1], ascending=True, numPartitions=1)
print(final_rdd.collect())
9.5 数据输出
9.5.1 输出为对象
"""
演示将RDD输出为Python对象
"""
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)
# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])
# collect算子,输出RDD为list对象
rdd_list: list = rdd.collect()
print(rdd_list)
print(type(rdd_list))
# reduce算子,对RDD进行两两聚合
num = rdd.reduce(lambda a, b: a + b)
print(num)
# take算子,取出RDD前N个元素,组成list返回
take_list = rdd.take(3)
print(take_list)
# count,统计rdd内有多少条数据,返回值为数字
num_count = rdd.count()
print(f"rdd内有{num_count}个元素")
sc.stop()
9.5.2 输出为文件
"""
演示将RDD输出到文件中
"""
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON']="G:/python/python.exe"
os.environ['HADOOP_HOME'] = "D:/dev/hadoop-3.0.0"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)
# 准备RDD1
rdd1 = sc.parallelize([1, 2, 3, 4, 5], numSlices=1)
# 准备RDD2
rdd2 = sc.parallelize([("Hello", 3), ("Spark", 5), ("Hi", 7)], 1)
# 准备RDD3
rdd3 = sc.parallelize([[1, 3, 5], [6, 7, 9], [11, 13, 11]], 1)
# 输出到文件中
rdd1.saveAsTextFile("D:/output1")
rdd2.saveAsTextFile("D:/output2")
rdd3.saveAsTextFile("D:/output3")
十、闭包
为什么要使用闭包?
- 在内部函数中修改外部函数得值
- 闭包得注意事项
'''演示Python的闭包特性'''
# 简单闭包
def outer(logo):
def inner(msg):
print(f"{logo},{msg}")
return inner
fn1=outer("盛海")
fn1("大家好")
# 使用nonlocal关键字修改外部函数得值
def outer1(num1):
def inner(num2):
nonlocal num1
num1+=num2
print(num1)
return inner
fn2=outer1(10)
fn2(10)
fn2(10)
fn2(10)
fn2(10)
# 使用闭包实现ATM小案例
def account_create(initial_amount=0):
def atm(num, deposit=True):
nonlocal initial_amount
if deposit:
initial_amount += num
print(f"存款:+{num}, 账户余额:{initial_amount}")
else:
initial_amount -= num
print(f"取款:-{num}, 账户余额:{initial_amount}")
return atm
atm = account_create()
atm(100)
atm(200)
atm(100, deposit=False)
十一、装饰器
#装饰器的一般写法(闭包)
def outer(func):
def inner():
print("我睡觉了")
func()
print("我起床了")
return inner()
def sleep():
import random
import time
print("睡眠中.......")
time.sleep(random.randint(1,5))
fn=outer(sleep)
fn()
11.1 语法糖
十二、设计模式
设计模式是一种编程套路,可以极大的方便程序的开发。
最常见、最经典的设计模式,就是我们所学习的面向对象了。
除了面向对象外,在编程中也有很多既定的套路可以方便开发,我们称之为设计模式:
- 单例、工厂模式
- 建造者、责任链、状态、备忘录、解释器、访问者、观察者、中介、模板、代理模式
- 等等模式
在这里先简单写一下单例和工厂模式
12.1 单例模式
单例模式(SingletonPattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。
在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
定义:保证一个类只有一个实例,并提供一个访问它的全局访问点
适用场景:当一个类只能有一个实例/而客户可以从一个众所周知的访问点访问它时。
12.2 工厂模式
十三、多线程的简单了解
了解进程、线程
13.1 threading模块简单使用
参数的传递
import threading
import time
def sing(msg):
while True:
print(msg)
time.sleep(1)
def dance(msg):
while True:
print(msg)
time.sleep(1)
if __name__ == '__main__':
# 创建一个唱歌的线程,已元组形式传参
sing_thread=threading.Thread(target=sing,args=("我要唱歌",))
# 创建一个跳舞的线程,已字典方式传参
dance_thread=threading.Thread(target=dance,kwargs={"msg":"我在跳舞"})
sing_thread.start()
dance_thread.start()
十四、socket网络通讯
socket(简称套接字)是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,
进程之间想要进行网络通信需要socket。
Socket负责进程之间的网络数据传输,好比数据的搬运工。
14.1 socket服务端
"""
演示Socket服务端开发
"""
import socket
# 创建Socket对象
socket_server = socket.socket()
# 绑定ip地址和端口
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
# listen方法内接受一个整数传参数,表示接受的链接数量
# 等待客户端链接
# result: tuple = socket_server.accept()
# conn = result[0] # 客户端和服务端的链接对象
# address = result[1] # 客户端的地址信息
conn, address = socket_server.accept()
# accept方法返回的是二元元组(链接对象, 客户端地址信息)
# 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
# accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了
print(f"接收到了客户端的链接,客户端的信息是:{address}")
while True:
# 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
data: str = conn.recv(1024).decode("UTF-8")
# recv接受的参数是缓冲区大小,一般给1024即可
# recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
print(f"客户端发来的消息是:{data}")
# 发送回复消息
msg = input("请输入你要和客户端回复的消息:")
if msg == 'exit':
break
conn.send(msg.encode("UTF-8"))
# 关闭链接
conn.close()
socket_server.close()
14.2 socket客户端
"""
演示Socket客户端开发
"""
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务端
socket_client.connect(("localhost", 8888))
while True:
# 发送消息
msg = input("请输入要给服务端发送的消息:")
if msg == 'exit':
break
socket_client.send(msg.encode("UTF-8"))
# 接收返回消息
recv_data = socket_client.recv(1024) # 1024是缓冲区的大小,一般1024即可。 同样recv方法是阻塞的
print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
# 关闭链接
socket_client.close()
十五、正则表达式
15.1 基础方法
"""
演示Python正则表达式re模块的3个基础匹配方法
"""
import re
s = "1python asdaf python python"
# match 从头匹配
result = re.match("python", s)
print(result)
# print(result.span())
# print(result.group())
# search 搜索匹配
result = re.search("python2", s)
print(result)
# findall 搜索全部匹配
result = re.findall("python", s)
print(result)
15.2 元字符匹配
"""
演示Python正则表达式使用元字符进行匹配
"""
import re
# s = "itheima1 @@python2 !!666 ##itccast3"
#
# result = re.findall(r'[b-eF-Z3-9]', s) # 字符串前面带上r的标记,表示字符串中转义字符无效,就是普通字符的意思
# print(result)
# 匹配账号,只能由字母和数字组成,长度限制6到10位
# r = '^[0-9a-zA-Z]{6,10}$'
# s = '123456_'
# print(re.findall(r, s))
# 匹配QQ号,要求纯数字,长度5-11,第一位不为0
# r = '^[1-9][0-9]{4,10}$'
# s = '123453678'
# print(re.findall(r, s))
# 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
# abc.efg.daw@qq.com.cn.eu.qq.aa.cc
# abc@qq.com
# {内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}@{内容}.{内容}.{内容}
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
# s = 'a.b.c.d.e.f.g@qq.com.a.z.c.d.e'
s = 'a.b.c.d.e.f.g@126.com.a.z.c.d.e'
print(re.match(r, s))
十六、递归调用
递归在编程中是一种非常重要的算法
递归:即方法(函数)自己调用自己的一种特殊编程写法
递归需要注意的是:
- 注意退出的条件,否则容易变成无限递归
- 注意返回值的传递,确保从最内层,层层传递到最外层
"""
演示Python递归操作
需求:通过递归,找出一个指定文件夹内的全部文件
思路:写一个函数,列出文件夹内的全部内容,如果是文件就收集到list
如果是文件夹,就递归调用自己,再次判断。
"""
import os
def test_os():
"""演示os模块的3个基础方法"""
print(os.listdir("D:/test")) # 列出路径下的内容
# print(os.path.isdir("D:/test/a")) # 判断指定路径是不是文件夹
# print(os.path.exists("D:/test")) # 判断指定路径是否存在
def get_files_recursion_from_dir(path):
"""
从指定的文件夹中使用递归的方式,获取全部的文件列表
:param path: 被判断的文件夹
:return: list,包含全部的文件,如果目录不存在或者无文件就返回一个空list
"""
print(f"当前判断的文件夹是:{path}")
file_list = []
if os.path.exists(path):
for f in os.listdir(path):
new_path = path + "/" + f
if os.path.isdir(new_path):
# 进入到这里,表明这个目录是文件夹不是文件
file_list += get_files_recursion_from_dir(new_path)
else:
file_list.append(new_path)
else:
print(f"指定的目录{path},不存在")
return []
return file_list
if __name__ == '__main__':
print(get_files_recursion_from_dir("E:\开发资料"))
def a():
a()