python学习笔记(《Python教程全套》杨淑娟)

视频资源来自:b站杨淑娟老师——《Python教程全套》完全入门版
文章仅为个人观看视频后的学习心得笔记,用于个人查看和记录保存。文中定有疏漏错误之处,恳请指正。


目录
一、python入门
二、字符编码
三、运算符
四、程序的组织结构
五、循环
六、列表
七、字典
八-1、元组
八-2、集合
九、字符串
十、函数
十一、异常处理
十二、类与对象
十三、对象
十四、模块化
十五、文件
十六、学生信息管理系统
十七、实操案例

一、python入门

python简介

解释型语言,没有编译环节
交互型语言
面向对象

下载安装python、pycharm

配置解释器

image-20210724181850483

python中的输出函数

print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

print函数默认换行,是end='\n'在起作用。

print(i,end='\t') 

不换行,输出完之后,结尾用制表符代替

print可以输出数字、字符串(加引号)、含有运算符的表达式
输出到文件

fp=open('D:/text.txt','a+')
print('hello world',file=fp)
fp.close()

'a+'如果文件不存在就直接创建,存在就在文件内容的后面继续追加
1.指定的盘符存在,
2.使用file= fp

不进行换行输出(输出内容在一行当中)

print('hello','world','Python')
image

转义字符

\ \ 用两个反斜杠来表示一个反斜杠
\n -> newline换行

\t,每次占一个制表位,一个制表位占4格()

print('a\tbcdefghi')
print('ab\tcdefghi')
print('abc\tdefghi')
print('abcd\tefghi')
image

\r 覆盖

print('hello\rworld')
image

\b 退格

print('hello\bworld')
image

单双引号混用

原字符,不希望字符串中的转义字符起作用,就使用原字符,就是在字符串之前加上r,或R。==注意==:最后一个字符不能是\。想写\可以用\\代替。因为字符的优先级不同

print(r'hello\bworld')
image

二、字符编码

二进制与字符编码

ASCII

graph TD
A(二进制0\,1) -->B(ASCII)
B --> C(GB2312)
B --> D(其他国家的字符编码)
C --> E(GBK)
D --> F(Unicode几乎包含了全世界的字符)
E --> G(GB18030)
F --> H(UTF-8)
G --> F
print(chr(0b100111001011000))
print(chr(20056))
print(ord('乘'))
image

Python中的标识符与保留字

import keyword
print(keyword.kwlist)

['False', 'None', 'True', '_peg_parser_', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

标识符严格区分大小写

Python中的变量与数据类型

标识:标识对象所存储的内存地址,使用内置函数id(obj)来获取

类型:标识的是对象的数据类型,使用内置函数type(obj)来获取

name = '玛丽亚'
print('值',name)
print('标识',id(name))
print('类型',type(name))
image

多次赋值后,变量名会指向新的空间

image-20210724203417958

数据类型:int float bool str

整数可以表示为二进制0b、八进制0o、十进制、十六进制0x。

浮点数,计算可能不精确。
解决方法:导入模块

print(1.1+2.2)

from decimal import Decimal
print(Decimal('1.1')+Decimal('2.2'))
image

布尔类型,可以转成证数进行计算。TrueFalse首字母都必须大写

f1=True
f2=False
print(f1+1) #2
print(f2+1) #1

字符串类型,三引号(3个单引号/3个双引号)定义的字符串可以分布在连续的多行。

str1='''好好学习,
天天向上'''
str2="""好好学习,
        天天向上"""
print(str1)
print(str2)
image-20210724205325888

甚至空格也给你记进去

数据类型转换:
str():当str和int型连接时,用+会报错,可以用, 也可以用str()
int():str->int,字符串必须为整数数字串。float->int,截取整数部分。bool->int,1或0。
float():str->float,字符串必须为数字串。int->float,98->98.0

Python中的注释

单行注释:#
多行注释:'''一对三引号之间的为多行注释'''

中文编码声明注释:python默认存储为UTF-8,在文件开头注释

#coding:gbk

该文件就默认存储为GBK了

三、运算符

Python的输入函数input()

present = input('好好学习')
print(present,type(present))
image

想要输入整数类型时,别忘了类型转换int()

a=int(input('输入整数'))

Python中的运算符

算数运算符

标准算数运算符:加、减、乘、除(/)、整除(//,一正一负向下取整,9//-4=-3)
取余运算符:%,余数=被除数-除数*商。9%-4=-3,-9%4=3。
幂运算符:**
2**3=8

赋值运算符

支持链式赋值:a=b=c=20

支持参数赋值:+=、-=、/=、//=、%=

支持系列解包赋值:a,b,c=20,30,40
左右变量数和值的个数要相同。
交换a,b=b,a

比较运算符

结果为bool型。
== 比较运算符,比较值
is ,is not,比较标识

a=10
b=10
print(a==b)
print(a is b)
image

先创建a,在创建b的时候,发现已经有了10,就直接也指向那个对象了。所以 a、b标识一样。

但是数组的id地址不相同

布尔运算符

and 相当于&&

or 相当于||

not 相当于!

in ,not in :

a='hello world'
print('w' in a)
print('s' in a)
print('w'not in a)
image

位运算符

按位与& 、按位或| 、左移<< 、右移>>

运算符的优先级

算数运算->位运算->比较运算->布尔运算->赋值运算

四、程序的组织结构

顺序结构、选择结构、循环结构

对象的布尔值

python一切皆对象,所有对象都有一个布尔值

False:False、数值0、None、空字符串、空列表([]、list())、空元组(()、tuple())、空字典({}、dict())、空集合(set())

其它对象的布尔值均为True

分支结构

单分支结构

双分支结构

多分支结构

money = int(input())
if 90<=money<=100:
    print('优')
elif 80<=money<90:
    print('良')
else:
    print('及')

嵌套if

print('优' if 90<=money<=100 else ('良',money) )

pass语句

什么都不做,只是一个占位符,用在语法上需要语句的地方

if 80<=money<90:
    pass
else:
    print('及')

没想好咋写,这样语法也不会报错

五、循环

内置函数range()

内置函数:前面不需要加任何函数,可以直接使用。

range(),用于生成一个整数序列。默认从0开始,步长1

range(stop),创建一个[0,stop)之间的整数序列,步长为1
range(start,stop),
range(start,stop,step),创建一个[start,stop)之间的整数序列,步长为step

优点:占用内存空间固定,值存储3个值

while循环

a=2
sum=0
while a<=100:
    sum+=a
    a+=2
print('1-100之间的偶数和',sum)

for-in循环

in表达从(字符串、序列等)中依次取值(遍历)
for-in编历的对象必须是可迭代对象

如果不需要使用自定义变量,可将自定义变量改用下划线_表示

for item in 'Python':
    print(item)
for i in range(10):
    print(i)
for _ in range(5):
    print('重复输出5次')

100-999之间的水仙花数

for item in range(100,1000):
    a=item//100
    b=(item-a*100)//10
    c=item%10
    if a**3+b**3+c**3==item:
        print(item)

break、continue与else语句

输出1-50之间所有5的倍数

for item in range(1,51):
    if item%5!=0:
        continue
    print(item)

else与 while、for搭配使用时,没有碰到break时执行else。循环的正常执行次数执行完,就执行else

for i in range(4):
    for j in range(3):
        print('*',end='\t')
    print()# 加了这个就会换行啦

二重循环中的break和continue用于控制本层循环

嵌套循环

六、列表

列表元素按顺序有序排序
所以映射唯一一个数据
列表可以存储重复数据
任意数据类型混存
根据需要动态分配和回收内存

列表的创建与删除

使用中括号

lst1=['hello','world',98]

使用内置函数list()

lst2=list(['hello','world',98])

lst1、lst2,存储 列表对象的引用

列表生成式

lst=[i*i for i in range(1,10)]#[1, 4, 9, 16, 25, 36, 49, 64, 81]

列表的查询操作

获取列表中指定元素的索引index()
如果列表中存在N个相同元素,只返回相同元素中的第一个元素的索引
如果查询的元素在列表中不存在,则会抛出ValueError
还可以在指定start和stop直接进行查找

lst1=['hello','world',98,100]
print(lst1.index('world'))
print(lst1.index('world',1,3))

获取列表中的单个元素
正向索引从0到N-1
逆向元素从-N到-1
指定索引不存,抛出indexError

lst1 = ['hello', 'world', 98, 100]
print(lst1[2])#98
print(lst1[-4],lst1[-3],lst1[-2],lst1[-1])#hello world 98 100

获取列表中的多个元素(切片操作):
切片结果是元列表片段的拷贝
切片的范围[start,stop),默认为[0,N)
步长默认为1

step为正数:从start开始往后计算切片

lst = [0,1,2,3,4,5,6,7,8,9]
print(lst[2:6:2])#[2, 4]
print(lst[2:6])#[2, 3, 4, 5]
print(lst[2:6:])#[2, 3, 4, 5]
print(lst[:6:])#[0, 1, 2, 3, 4, 5]
print(lst[::])#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

step为负数:从start开始往前计算切片

lst = [0,1,2,3,4,5,6,7,8,9]
print(lst[6:2:-2])#[6, 4]
print(lst[2::-1])#[2, 1, 0]
print(lst[:6:-1])#[9, 8, 7]
print(lst[::-1])#[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

可以用in、not in来判断指定元素在列表中是否存在

可以用for 迭代变量 in 列表名来遍历列表

列表元素的增、删、改操作

增加:内存没有更改,就是在元列表中添加

方法 描述
append() 在列表的末尾添加一个元素
extend() 在列表的末尾至少添加一个元素
insert() 在列表的任意位置添加一个元素
切片 在列表的任意位置至少添加一个元素

以下代码分别执行

lst = [0,1,2,3,4,5,6,7]
lst.append(80)#[0, 1, 2, 3, 4, 5, 6, 7, 80]

lst2 = ['a','b','c']
lst.append(lst2)#[0, 1, 2, 3, 4, 5, 6, 7, ['a', 'b', 'c']]
lst.extend(lst2)#[0, 1, 2, 3, 4, 5, 6, 7, 'a', 'b', 'c']
lst.insert(2,90)#[0, 1, 90, 2, 3, 4, 5, 6, 7]
lst.insert(2,lst2)#[0, 1, ['a', 'b', 'c'], 2, 3, 4, 5, 6, 7]
lst[3::]=lst2#[0, 1, 2, 'a', 'b', 'c']
lst[:4:]=lst2#['a', 'b', 'c', 4, 5, 6, 7]
lst[::3]=lst2#['a', 1, 2, 'b', 4, 5, 'c', 7]

删除

方法 描述
remove() 一次删除一个元素;重复元素只删除第一个;元素不存在就抛出ValueError
pop() 删除一个指定索引位置上的元素;不指定索引,则删除列表中最后一个元素;指定索引不存在就抛出ValueError
切片 一次至少删除一个元素
clear() 清空列表
del 删除列表对象

remove写的是元素值,pop写的是索引

切片↓

lst = [0,1,2,3,4,5,6,7]
new_list = lst[1:3]#产生新对象[1, 2]
lst[1:3]=[]#在原列表中删除[0, 3, 4, 5, 6, 7]

修改
以下代码分开执行

lst = [0,1,2,3,4,5]
lst[2]='a'  #[0, 1, 'a', 3, 4, 5]
lst[1:3]=['a','b','c','d']#[0, 'a', 'b', 'c', 'd', 3, 4, 5]

列表元素的排序

sort():不指定reverse,就默认False,升序排序

lst=[20,40,30,10,50]
lst.sort()#[10, 20, 30, 40, 50]
lst.sort(reverse=True)#[50, 40, 30, 20, 10]
new_list = sorted(lst)
new_list = sorted(lst,reverse=True)

使用内置函数sorted(),原列表不发生变化

七、字典

什么是字典

python内置的数据结构之一,与列表一样是一个可变序列
以键值对的方式存储数据,字典是一个无序的序列

image-20210725214331726

键必须是一个不可变序列(不可以执行增删改操作),如整数序列、字符串序列

特点:
所有元素都是一个key-value对,key不允许重复,value可以重复
字典中的元素是无序的
字典中的key必须是不可变对象
字典也可以根据需要动态地伸缩
字典会浪费较大的内存,是一种使用空间换时间的数据结构

字典的实现原理

hash

字典的创建与删除

#{'张三': 100, '李四': 90, '王五': 80}
scores1 = {'张三':100, '李四':90, '王五':80}
scores2 = dict(张三 = 100, 李四 = 90, 王五 = 80)
scores3 = {}#创建空字典

字典的常用操作

查询

print(scores1['张三'])
print(scores1.get('张三'))
print(scores1.get('邓布利多',99))#如果查找不存在,返回默认值99

如果找不到,[]会报KeyError。get会报None

key的判断:in、not in

print('张三' in scores1)

scores1['赵六']=70

del scores1['张三']
scores1.clear()

没有就新增,有就修改

scores1['赵六']=70

获取视图

keys=scores1.keys()
print(keys,type(keys))
print(list(keys))#将所有键组成的视图转成列表

values=scores1.values()
print(values,type(values))
print(list(values))

items=scores1.items()
print(items,type(items))
print(list(items))#转换之后的列表元素是由元组组成的

dict_keys(['张三', '李四', '王五'])
['张三', '李四', '王五']

dict_values([100, 90, 80])
[100, 90, 80]

dict_items([('张三', 100), ('李四', 90), ('王五', 80)])
[('张三', 100), ('李四', 90), ('王五', 80)]

字典元素的编历

for item in scores1:
    print(item,scores1[item],scores1.get(item))

结果:
张三 100 100
李四 90 90
王五 80 80

字典生成式

内置函数zip()
用于将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表

items = ['Fruits','Books','Others']
prices = [10,20,30,40,50]

d={item:price for item,price in zip(items,prices)}
#{'Fruits': 10, 'Books': 20, 'Others': 30}

压缩打包的时候会以元素少的那个列表为基准

八-1、元组

什么是元组

Python内置的数据结构之一,是一个不可变序列。==没有元组生成式==

不可变序列:字符串、元组。没有增删改的操作
可变序列:列表、字典。可以对序列执行增、删、改操作,对象地址不发生改变

列表用[],元组用()

为什么要将元组设计成不可变序列?
设计成不可变序列后,在多任务环境下,同时操作对象时不需要加锁。(可以看数据、取数据,但是不能增删改)因此,在程序中尽量使用不可变序列
注意:元组中存储的对象:
如果元组中的对象本身是不可变对象,则不能再引用其他对象
如果元组中的对象是可变对象,则可变对象的引用不允许改变,但数据可以改变

可以向列表中添加元素,而列表的内容的地址不变

元组的创建方式

()、内置函数tuple()

t1=('hello','world',80)
tw='hello','world',80       #元素有2+个时,小括号可以省略

t3=tuple(('hello','world',80))

t4=('hello',)

t5=()
t6=tuple()

只包含一个元组的元素需要使用逗号和小括号

元组的编历

1、使用索引
2、元组是可迭代对象,所以可以使用for…in进行编历

八-2、集合

什么是集合

集合是没有value的字典(字典中键不能重复,同样 集合中的元素也不能重复)

集合的创建

集合中的元素是无序的,不重复

s1={2,3,4,4,5,6,2,1}#{1, 2, 3, 4, 5, 6}
print(s1)

s=set([3,4,5,10])#列表{10, 3, 4, 5}
s=set((3,4,5,10))#元组{10, 3, 4, 5}
s=set('Hello')#字符串{'o', 'H', 'l', 'e'}
s=set({3,4,5,10})#集合{10, 3, 4, 5}
s=set()#set()

定义空集合时用set,如果直接用{},会被当作为字典类型

集合的增、删、改、查操作

判断:in、not in

新增:
add():一次添加一个元素
update():一次至少添加一个元素(里面可以填集合、列表、元组)

删除:
remove():一次删除一个指定元素,如果指定的元素不存在就抛出KeyError
discard():一次删除一个指定元素,如果指定元素不存在 不抛异常
pop():一次只删除一个任意元素
clear():清空集合

集合间的关系

是否相等==或!=
一个集合是否是另一个集合的子集issubset
一个集合是否是另一个集合的超集issuperset
两个集合是否没有交集isdisjoint

集合的数学操作

s1={2,3,4,6}
s2={3,4,5,6}

#交集{3, 4, 6}
print(s1.intersection(s2))
print(s1 & s2)

#并集{2, 3, 4, 5, 6}
print(s1.union(s2))
print(s1 | s2)

#差集{2}
print(s1.difference(s2))
print(s1-s2)

#对称差集{2, 5}
print(s1.symmetric_difference(s2))
print(s1^s2)

集合生成式

就是把列表生成式的[]改成{}

s1={i*i for i in range(10)}

九、字符串

字符串的驻留机制

字符串是基本数据类型,是一个不可变的字符序列

Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相统字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量

交互模式(cmd)几种情况:
字符串长度为0或1时
符合标识符的字符串:不符合标识符的就不能驻留,比如'abc%'
字符串只在编译时进行驻留,而非运行时:用join连接的和原字符串不能共用
[-5,256]之间的整数数字:驻留

在需要拼接字符串时,建议使用join方法,而不是+。
因为join()方法是先计算出所有字符的长度,然后再拷贝,只new一次对象,效率更高

字符串的常用操作

查询

方法 作用
index() 查找子串第一次出现的位置,如果查找的子串不存在,则抛出ValueError
rindex() 查找子串最后一次出现的位置,如果查找的子串不存在,则抛出ValueError
find() 查找子串第一次出现的位置,如果查找的子串不存在,则返回-1
rfind() 查找子串最后一次出现的位置,如果查找的子串不存在,则返回-1

大小写转换

转换之后,会产生一个新的字符串对象

方法 作用
upper() 把字符串中所有字符都转成大写字母
lower() 把字符串中所有字符都转成小写字母
swapcase() 把字符串中所有小写字符都转成大写字母,所有大写字符都转成小写字母
capitalize() 把第一个字符转换为大写,把其余字符转换成小写
title() 把每个单词的第一个字符转换为大写,把每个单词的剩余字符转换为小写

字符串内容对齐操作的方法

方法 作用
center() 居中对齐,第1个参数指定宽度,第2个参数指定填充符。第2个参数是可选的,默认是空格。如果设置宽度小于实际宽度,则返回原字符串
ljust() 左对齐,第1个参数指定宽度,第2个参数指定填充符。第2个参数是可选的,默认是空格。如果设置宽度小于实际宽度,则返回原字符串
rjust() 右对齐,第1个参数指定宽度,第2个参数指定填充符。第2个参数是可选的,默认是空格。如果设置宽度小于实际宽度,则返回原字符串
zfill() 右对齐,左边用0填充。该方法只接收1个参数,用于指定字符串的宽度。如果设置宽度小于实际宽度,则返回原字符串
strip() 移除字符串头尾指定的字符(默认为空格或换行符)或字符序列

注意:zfill()中如果有负号在开头,那么零填充在符号后。

print('-aads'.zfill(8))#-000aads

字符串劈分操作的方法

方法 作用
split() 从字符串的左边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表;以通过参数sep指定劈分字符串是的劈分符;通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独作为一部分
rsplit() 从字符串的右边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表;以通过参数sep指定劈分字符串是的劈分符;通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独作为一部分
s='hello world python'
lst=s.split()

s='hello|world|python'
lst=s.split(sep='|')

s='hello|world|python'
lst=s.split(sep='|',maxsplit=1)#['hello', 'world|python']

字符串判断的相关方法

方法 作用
isidentifier() 判断指定的字符串是否是合法的标识符
isspace() 判断指定的字符串是否全部由空白字符组成(回车、换行、水平制表符)
isalpha() 判断指定的字符串是否全部由字母组成
isdecimal() 判断指定的字符串是否全部由十进制的数字组成
isnumeric() 如果 string 中只包含数字字符,则返回 True,否则返回 False
isalnum() 判断指定的字符串是否全部由字母和数字组成
isdigit() 如果 string 只包含数字则返回 True 否则返回 False.

https://www.runoob.com/python/python-strings.html
注意:
'张三' 是字母
'四'、'Ⅱ' 是数字,但不是十进制数字

字符串替换

replace():第1个参数指定被替换的子串,第2个参数指定替换子串的字符串,该方法返回替换后得到的字符串,替换前的字符串不发生变化,调用该方法时可以通过第3个参数指定最大替换次数

字符串合并

join():将列表或元组中的字符串合并成一个字符串。

print('-'.join(lst))
print('-'.join('abcd'))#a-b-c-d

字符串的比较

运算符:>,>=,<,<=,==,!=

ord(),字符->原始值

print(ord('a'))#97

chr(),原始值->字符

print(chr(97))#a

== 比较的是value是否相等
is 比较的是id是否相等

字符串的切片操作

字符串是不可变类型,不具备增删改等操作,切片操作将产生新的对象

[start : end : step]

image-20210726162518263

格式化字符串

%作占位符

name = '张三'
age = 20
print('我叫%s,今年%d岁' % (name,age))

print('%10d' % 99)
print('%.3f' % 3.1415926)
print('%10.3f' % 3.1415926)#总宽度为10,小数点后三位

{}作占位符。Python format 格式化函数

name = '张三'
age = 20
print('我叫{0},今年{1}岁'.format(name,age))

print('{:.3}'.format(3.1415926))#3.14
print('{0:.3}'.format(3.1415926))#3.14
print('{0:.3f}'.format(3.1415926))#3.142
print('{0:10.3f}'.format(3.1415926))#     3.142
print('{:^10d}'.format(3.1415926))#中间对齐,宽度为10

f-string

name = '张三'
age = 20
print(f'我叫{name},今年{age}岁')

字符串的编码转换

s='我要吃饭'
print(s.encode(encoding='GBK'))
print(s.encode(encoding='UTF-8'))

输出:
b'\xce\xd2\xd2\xaa\xb3\xd4\xb7\xb9'
b'\xe6\x88\x91\xe8\xa6\x81\xe5\x90\x83\xe9\xa5\xad'

在GBK编码格式中,一个中文占2个字节
在UTF-8编码格式中,一个中文占3个字节

byte=s.encode(encoding='GBK')
print(byte.decode(encoding='GBK'))
byte=s.encode(encoding='UTF-8')
print(byte.decode(encoding='UTF-8'))

十、函数

函数的创建和调用

def clac(a,b):#形参
    c=a+b
    return c

print(clac(2,3))#实参

函数的参数传递

位置实参:根据形参对应的位置进行实参传递。用法如上↑

关键词实参:根据形参名称进行实参传递

def clac(a,b):
    print('a='+str(a))
    print('b='+str(b))
    return

clac(2,3)#a=2 b=3
clac(b=2,a=3)#a=3 b=2

在函数调用过程中,进行参数传递:
如果是不可变对象,在函数体的修改不会影响实参的值。
如果是可变对象,在函数体的修改会影响实参的值。
列表传的是地址,在函数里append追加元素后,调用结束了,在原列表中依旧在

函数的返回值

如果函数没有返回值,return可以省略不写
函数的返回值如果是1个,直接返回类型
函数的返回值如果是多个,返回的结果为元组

def fun(num):
    odd=[]
    even=[]
    for i in num:
        if i%2:
            odd.append(i)
        else:
            even.append(i)
    return odd,even

print(fun([1,3,5,6,7,8,9,20]))
#([1, 3, 5, 7, 9], [6, 8, 20])

函数的参数定义

函数定义默认值参数

def clac(a=30,b=100):
    print('a='+str(a))
    print('b='+str(b))
    return

clac()#a=30  b=100
clac(2)#a=2  b=100

个数可变的位置参数

定义函数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数
使用*定义个数可变的位置形参
结果为一个元组
每个函数只能定义一个

def fun(*a):
    print(a)
fun(1,2,3,4)#(1, 2, 3, 4)
def fun(*lst):

在函数调用时,将列表中的每个元素都转换为位置实参传入

个数可变的关键字形参

定义函数时,无法事先确定传递的关键字实参的个数时,使用可变的关键字形参
使用**定义个数可变的关键字形参
结果为一个字典
每个函数只能定义一个

def fun(**arg):
    print(arg)
    print(arg['a'],arg['c'])
fun(a=1,b=2,c=3)

输出:
{'a': 1, 'b': 2, 'c': 3}
1 3

def fun(**dic):

在函数调用时,将字典中的键值对都转换为关键字实参传入

在一个函数定义过程中,既有个数可变的关键字形参,又有个数可变的位置形参。要求个数可变的位置形参放前面,个数可变的关键字形参放后面

def fun(*a,**arg):
def fun(a,b,*,c,d,**arg):
def fun(a,b=10,*,c,d,**arg):

↓从*之后的参数,在函数调用时,只能采用关键字参数传递

def fun(a,b,*,c,d):
    print('a=',a)
    print('b=',b)
    print('c=',c)
    print('d=',d)
fun(10,20,d=30,c=40)

变量的作用域

局部变量、全局变量

递归函数

组成部分:递归调用与递归终止条件

算阶乘:

def fun(num):
    if num==1:
        return 1
    return fun(num-1)*num
print(fun(6))

斐波那契数列:

def fib(num):
    if(num==1 or num==2):
        return 1
    return fib(num-1)+fib(num-2)
for i in range(1,8):
    print(fib(i),end=' ')

十一、异常处理

bug的由来及分类

常见错误:
1.末尾冒号
2.缩进错误
3.英文符号
4.字符串+数字拼接
5.没有定义变量
6.==和=

不同异常类型的处理方式

异常处理机制

image
try:
  # res=1/0
  # res='a'/1
  res = 3/2
except ZeroDivisionError:
  print('除数为0')
except BaseException as e:
  print('其它异常',e)
else:
  print('没有异常',res)
finally:
  print('无论是否产生异常,都会被执行的代码')

finally可以用来释放资源

Python常见的异常类型

异常类型 描述
ZeroDivisionError 除(或取模)零(所有数据类型)
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
NameError 未声明/初始化对象(没有属性)
SyntaError Python语法错误
ValueError 传入无效的参数

traceback模块:打印异常信息

import traceback
try:
  a=1/0
except:
  # pass
  traceback.print_exc()

异常后续可以存储到文件中

raise 手动抛出异常

语法格式:

raise [Exception [, args [, traceback]]]

try:
  x = 10
  if x > 5:
      raise Exception('x 不能大于 5。x 的值为: {}'.format(x)
except Exception as e:
      print(e)

PyCham的调试模式

十二、类与对象

两大编程思想

面向过程:事务比较简单,可以用线性的思维去解决

面向对象

类和对象的创建

不同的数据类型属于不同的类。100、99、520都是int类下包含实例/对象

Python中一切皆对象(有id、内存空间、值)

创建类的语法
类的组成:类属性、实例方法、静态方法、类方法

在类之外定义的称为函数,在类之内定义的称为方法

class Student:#取名规范:由一个或多个单词组成,每个单词的首字母大写,其余小写
  native='吉林' #类属性

  def __init__(self,name,age):  #初始化
    self.name=name    #self.name 称为实例属性,进行了一个赋值操作,将局部变量的name的值赋给实体属性
    self.agee=age      #self后面的不一定要叫name、age。但是习惯上局部变量和属性名相同

  def eat(self):  #实例方法
    print('实例方法的输出')

  @staticmethod #静态方法
  def me():
    print('我使用了staticmethod进行修饰,所以我是静态方法')

  @classmethod  #类方法
  def cm(cls):
    print('我使用了classmethod进行修饰,所以我是类方法')

对象的创建(类的实例化)

stu1=Student('张三',20)

使用

stu1=Student('张三',20)
stu1.eat()          #对象名.方法名()
Student.eat(stu1)   #类名.方法名(类的对象self)
print(stu1.name)
print(Student.native)
Student.native='天津' #native被共享,一改,其它对象的native也跟着改
print(stu1.native)
Student.cm()    #类方法
Student.me()    #静态方法

动态绑定

绑定属性

stu1.gender='女'
print(stu1.gender)

对象创建之后,又给stu1增加一个属性。而这个属性只能在stu1用,stu2是不能用的,没有定义。

绑定方法

def show():
  print('我是一个函数')
stu1.show=show
stu1.show()#我是一个函数

同样,stu2也不能用show方法

十三、对象

面向对象三大特征:封装(安全性)、继承(复用性)、多态(扩展性、可维护性)

封装

在python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边加2个_下划线

class Student:
  def __init__(self,name,age):
    self.name=name
    self.__age=age  #不想被外部访问
  def show(self):
    print(self.name,self.__age)

stu=Student('张三',20)
print(stu.name)
# print(stu.__age)#会报错
print(stu._Student__age)

继承

python支持多继承。可以有好多个父类。所有类型的共同父类是Object

class Person(object):
  def __init__(self,name,age):
    self.name=name
    self.age=age
  def info(self):
    print('姓名:{0},年龄:{1}'.format(self.name,self.age))

class Student(Person):
  def __init__(self,name,age,score):
    super().__init__(name,age)
    self.score=score
    
stu=Student('小红',20,'80')
stu.info()#姓名:小红,年龄:20

方法重写

super()表示调用父类

在子类中也可以重写父类,用同一个方法名

def info(self):
  super().info()
  print(self.score)

Object类

print(dir(对象/类))可以显示现在有多少方法

object有一个__str__()方法,用于返回一个对于对象的描述。print(对象)原本输出对象的内存地址。我们可以把它重写,让它输出属性值。

class Student:
  def __init__(self,name,age)
    self.score=score
  def __str__(self):
    return '名字{0},今年{1}岁'.format(self.name,self.age)
  
stu=Student('小红',20,'80')
print(stu)#名字小红,今年20岁

一般会在写完这个类的时候再去重写__str__方法,用于返回对象的描述

多态

在运行过程中,根据变量所引用的对象的类型,动态决定调用哪个对象的方法

动态语言(python)(崇尚鸭子类型):不需要关系对象是什么类型,只关心对象的行为

静态语言(java)实现多态的三个必要条件:继承、方法重写、父类引用指向子类对象

特殊方法和特殊属性

特殊属性

名称 描述
__dict__ 获得类对象所绑定的属性和方法的字典,或实例对象属性的字典
__class__ 输出对象所属的类
__bases__ 父类类型的元素
__base__ 输出一个距离它最近的父类(定义时谁写前边就输出谁)
__mro__ 查看类的层次结构
__subclasses__() 子类的列表

特殊方法

名称 描述
__len__() 通过重写_len_()方法,让内置函数len()的参数可以是自定义类型
__add__() 通过重写_add_()方法,可使自定义对象具有“+”功能
__new__() 用于创建对象
__init__() 对创建的对象进行初始化
c=a+b
d=a.__add__(b)
class Student:
  def __init__(self,name):
    self.name=name
  def __add__(self, other):
    return self.name+other.name

stu1=Student('张三')
stu2=Student('李四')
s=stu1+stu2
print(s)

先new新建,再init初始化

image-20210727225056600

类的浅拷贝与深拷贝

变量的赋值操作

只有一个对象的实例,用了两个变量去指。同一个对象赋给了两个变量

浅拷贝

python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝。
因此,源对象与拷贝对象会引用同一个子对象。

深拷贝

使用copy的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同

cpu=Cpu()
disk=Disk()
computer=Computer(cpu,disk)

computer1=computer  #赋值

import copy
computer2=copy.copy(computer)#浅拷贝。对象地址不同,子对象地址相同

computer3=copy.deepcopy(computer)#深拷贝。对象地址、子对象地址都不相同

十四、模块化

什么叫模块

Modules,一个模块可以包含N多个函数。在Python中一个扩展名为.py的文件就是一个模块。使用模块:方便其它程序/脚本导入并使用;避免函数名和变量冲突;提高代码的可维护性;提高代码的可重用性

自定义模块

创建模块:新建一个.py文件,名称尽量不要与Python自带的标准模块名称相同

导入模块:

import 模块名称 [as 别名]

form 模块名称 import 函数/变量/类
import math
print(pow(2,3))#8
print(math.pow(2,3))#8.0
print(math.ceil(9.001))#10
print(math.floor(9.999))#9

新建一个calc.py

def add(a,b):
  return a+b

在要用的地方导入模块使用

方法1

import calc
print(calc.add(1,2))

方法2

from calc import add
print(add(1,2))
image-20210728105241940

老师说要标记一下。。但是我不标记没报错。。

以主程序的形式执行

每个模块都有一个记录模块名称的变量__name__,程序可以检查该变量,以确定他们在哪个模块中执行。顶级模块的__name__变量的值为__main__

#calc.py
def add(a,b):
  return a+b

if __name__ == '__main__':
  print('只有在运行calc时才输出这句话')

python中的包

包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下

作用:
代码规范、避免模块名称冲突

包与目录的区别:
包含__init__.py文件的目录称为包
目录里通常不包含__init__.py文件

使用import方式进行导入时,只能跟包名或模块名

import calc
import pg1

使用from…import 可以导入包、模块、函数、变量

from pg1 import moduleA
from pg1.moduleA import a

Python中常用的内置模块

模块名 描述
sys 与Python解释器及其环境操作相关的标准库
time 提供与时间相关的各种函数的标准库
os 提供了访问操作系统服务功能的标准库
calendar 提供了与日期相关的各种函数的标准库
urllib 用于读取来自网上(服务器)的数据标准库
json 用于使用json序列化和反序列化对象
re 用于在字符串中执行正则表达式匹配和替换
math 提供标准算术运算函数的标准库
decimal 用于进行精确控制运算精度、有效数位和四舍五入操作的十进制运算
logging 提供了灵活的记录事件、错误、警告和调试信息等日志信息的功能
import sys
print(sys.getsizeof(24))
print(sys.getsizeof(True))
print(sys.getsizeof(False))
import time
print(time.time())
print(time.localtime())
import urllib.request
print(urllib.request.urlopen('http://www.baidu.com').read())
import math
print(math.pi)

第三方模块的安装及使用

第三方模块的安装

在cmd中pip install schdule。(建议直接在pyCharm里import然后按提示安装)
pip不识别的话记得配置环境变量。系统变量path中放入python目录下C的Scripts

import schedule
import time

def job():
  print('haha')
schedule.every(3).seconds.do(job)
while True:
  schedule.run_pending()
  time.sleep(1)

十五、文件

编码格式介绍

Python的解释器使用的是Unicode(内存)
.py文件在磁盘上使用UTF-8存储(外存)

image-20210728144456232

文件的读写原理

image-20210728145042628

文件读写操作

file=open('a.txt','r')
print(file.readlines())
file.close()

输出:
['中国\n', '好吃']

常用的文件打开方式
文本文件:存储的是普通“字符”文本,默认为unicode字符集,可以使用记事本程序打开
二进制文件:把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件打开。如:mp3、jpg、doc

打开方式 描述
r 以只读模式打开文件,文件的指针将会放在文件的开头
w 以只写模式打开文件,如果文件不在则创建。如果文件存在,则覆盖原有内容,文件指针在文件的开头
a 以追加模式打开文件,如果文件不存在则创建,文件指针在文件开头。如果文件存在,则在文件末尾追加内容,文件指针在原文件末尾
b 以二进制方式打开文件,不能单独使用,需要与其他模式一起使用,rb、或者wb
+ 以读写方式打开文件,不能单独使用,需要与其他模式一起使用,a+

文件拷贝:

src_file=open('logo.png','rb')
target_file=open('copylogo.png','wb')
target_file.write(src_file.read())

target_file.close()
src_file.close()

文件对象常用的方法

方法 说明
read([size]) 从文件中读取size个字节或字符内容返回,若省略[size],则读取到文件末尾,即一次读取文件所有内容
readlines() 从文本文件中读取一行内容
write(str) 把文本文件中每一行都作为独立的字符串对象,并将这些对象放入列表中返回
writelines(s_list) 将字符串列表s_list写入文本文件,不添加换行符
seek(offset[,whence]) 把文件指针移动到新的位置,offset表示相对于whence的位置:
offset:正,往结束方向移动。负,往开始方向移动
whence:0,从文件头开始计算。1,从当前位置开始计算。2,从文件尾开始计算
tell() 返回文件指针的当前位置。从0开始计算
flush() 把缓冲区的内容写入文件,但不关闭文件
close() 把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源

with语句(上下文管理器)

with语句可以自动管理上下文资源(不用手动关闭),不论什么原因(是否产生异常)跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的
自动调用__enter__、__exit__方法

文件赋值↓

with open('logo.png','rb') as src_file:
  with open('copy21logo.png','wb') as target_file:
    target_file.write(src_file.read())

目录操作

os模块——操作系统相关的一个模块

import os
os.system('notepad.exe')
os.startfile("D:\\Program Files\\Typora\\Typora.exe")

打开记事本。相当于在运行(win+R)中写notepad。
calc计算器

os模块操作目录:

函数 说明
getcwd() 返回当前的工作目录
listdir(path) 返回指定路径下的文件和目录信息
mkdir(path[,mode]) 创建目录
makedirs(path1/path2...[,made]) 创建多级目录
rmdir(path) 删除目录
removedirs(path1/path2...) 删除多级目录
chdir(path) 将path设置为当前工作目录

os.path模块操作目录相关函数:

函数 说明
abspath(path) 用于获取文件或目录的绝对路径
exists(path) 用于判断文件或目录是否存在,存在返回Ture,否则返回False
join(path,name) 将目录与目录或文件名拼接起来
split() 拆分目录和文件
splitext() 分离文件名和扩展名
basename(path) 从一个目录中提取文件名
dirname(path) 从一个路径中提取文件路径,不包括文件名
isdir(path) 用于判断是否为路径

列出指定目录下的所有py文件

import os
path=os.getcwd()
lst=os.listdir(path)
for filename in lst:
  if filename.endswith('.py'):
    print(filename)

endswith()表示以...结尾

walk可以编历目录下的各种子目录文件

import os
path=os.getcwd()
lst_files=os.walk(path)
for dirpath,dirname,filename in lst_files:
  '''print(dirpath)
  print(dirname)
  print(filename)'''
  for dir in dirname:
    print(os.path.join(dirpath,dir))
  for file in filename:
    print(os.path.join(dirpath,file))

十六、学生信息管理系统

需求分析

系统设计

录入学生信息
查找学生信息
删除学生信息
修改学生信息
学生成绩排名
统计学生总人数
显示全部学生信息

系统开发必备

主函数设计

学生信息维护模块设计

录入学生信息功能:从控制台录入学生信息,并且把它们保存(save())到磁盘文件中

def save(lst):
  try:
    stu_txt=open(filename,'a',encoding='UTF-8')
  except:
    stu_txt=open(filename,'w',encoding='UTF-8')
  for item in lst:
    stu_txt.write(str(item)+'\n')
  stu_txt.close()

删除学生信息

def delete():
  while True:
    student_id=input('请输入要删除的学生的ID:')
    if student_id!='':
      if os.path.exists(filename):#如果文件存在在目录下
        with open(filename,'r',encoding='UTF-8') as file:
          student_old=file.readlines()
      else:
        student_old=[]
      flag=False  #标记是否删除
      if student_old:
        with open(filename,'w',encoding='UTF-8') as wfile:
          # d={}
          for item in student_old:
            d=dict(eval(item))  #将字符串转成字典
            if d['id']!=student_id:
              wfile.write(str(d)+'\n')
            else:
              flag=True
          if flag:
            print(f'id为{student_id}的学生信息已被删除')
          else:
            print(f'没有找到id为{student_id}的学生')
      else:
        print('无学生数据')
        break
      show()  #删完之后重新显示所有学生信息
      answer=input('是否继续删除?y/n\n')
      if answer=='y' or answer=='Y':
        continue
      else:
        break

d=dict(eval(item)) #将字符串转成字典

修改学生信息

查询学生信息:
展示↓

def show_student(lst):
  if len(lst)==0:
    print('没有查询到学生信息,无数据显示!!')
    return
  #定义标题显示格式
  format_title='{:^6}\t{:^12}\t{:^8}\t{:^10}\t{:^10}\t{:^8}'
  print(format_title.format('ID','姓名','英语成绩','python成绩','java成绩','总成绩'))
  #定义内容的显示格式
  format_data='{:^8}\t{:^8}\t{:^8}\t{:^8}\t{:^8}\t{:^8}'
  for item in lst:
    print(format_data.format(item.get('id'),item.get('name'),item.get('english'),item.get('python'),item.get('java'),int(item.get('english')+item.get('python')+item.get('java'))))

统计学生总人数

显示所有学生信息

排序模块设计

sort()函数用于对原列表进行排序,如果指定参数,则使用比较函数指定的比较函数。

list.sort( key=None, reverse=False)
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。

  • reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)。

lambda ※

tudent_new.sort(key=lambda x:int(x['english']),reverse=asc_or_desc_bool)
def sort():
  show()
  if os.path.exists(filename):
    with open(filename,'r',encoding='UTF-8') as rfile:
      student_lst=rfile.readlines()
      student_new=[]
      for item in student_lst:
        d=dict(eval(item))
        student_new.append(d)
  else:
    return
  while True:
    asc_or_desc=input('请选择(0.升序 1.降序):')
    if asc_or_desc=='0':
      asc_or_desc_bool=False
      break
    elif asc_or_desc=='1':
      asc_or_desc_bool = True
      break
    else:
      print('您的输入有误,请重新输入')
  while True:
    mode=input('请选择排序方式(1.按英语成绩排序 2.按Python成绩排序 3.按java成绩排序 4.按总成绩排序):')
    if mode!='1' and mode!='2'and mode!='3'and mode!='4':
      print('您的输入有误,请重新输入')
      sort()
      continue
    elif mode=='1':
      student_new.sort(key=lambda x:int(x['english']),reverse=asc_or_desc_bool)
    elif mode=='2':
      student_new.sort(key=lambda x:int(x['python']),reverse=asc_or_desc_bool)
    elif mode == '3':
      student_new.sort(key=lambda x:int(x['java']),reverse=asc_or_desc_bool)
    elif mode=='4':
      student_new.sort(key=lambda x:int(x['english'])+int(x['python'])+int(x['java']),reverse=asc_or_desc_bool)
    break
  show_student(student_new)

项目打包

安装:pip install PyInstaller

打包:pyinstaller -F D:\study\python\16-\stusystem.py

打包完之后倒数第二行:10833 INFO: Appending archive to EXE C:\WINDOWS\system32\dist\stusystem.exe

然而每次要修改文件的时候就会闪退,我也不知道为什么。┑( ̄Д  ̄)┍

十七、实操案例

print输出

输出到文件

fp=open('D:/test.txt','w')
print('输出到文件',file=fp)
fp.close()

文件读写

有赋值的输出

循环list输出、字典输出、字典的内置函数zip()

lst_name=['林黛玉','薛宝钗','贾元春','贾探春','史湘云']
lst_sig=['①','②','③','④','⑤']
for i in range(5):
  print(lst_sig[i],lst_name[i])

d={'①':'林黛玉','②':'薛宝钗','③':'贾元春','④':'贾探春','⑤':'史湘云'}
for key in d:
  print(key,d[key])

for s,name in zip(lst_sig,lst_name):
  print(s,name)

有颜色的输出

\033[显示方式; 前景色; 背景色m****\033[0m

其中******表示被标记的内容。可以缺省书写,使用默认设定。

print('\033[0:35m图书音像勋章\033[m')
image-20210729002615535

进制转换

num=int(input('请输入一个十进制的整数:'))
print(num,'的二进制数为:',bin(num))
print(str(num)+'的二进制数为:'+bin(num))
print('%s的二进制数为:%s' % (num,bin(num)))
print('{0}的二进制数为:{1}'.format(num,bin(num)))
print(f'{num}的二进制数为:{bin(num)}')

print(f'{num}的八进制数为:{oct(num)}')
print(f'{num}的十六进制数为:{hex(num)}')

支付密码格式验证

s='支付密码合法' if pwd.isdigit() else '支付密码只能是数字'

数字竞猜(随机数)

price=random.randint(1000,2000)

车票购买

dict={'aaa':['1','2','3'],
      'bbb':['4','5','6']}
for item in dict:
  print(item)
  for i in dict[item]:
    print(i)

对字典dict进行for…in,item表示的是key值
对列表lst进行for…in,item表示的是lst[i],也就是元素值(而不是索引)

咖啡购买(元组编历)

enumerate() 函数:用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

t1=('hello','world',80)
for index,item in enumerate(t1):
  print(f'{index} {item}')

也可以逆向查找

print(t1[2])

高铁售票

下载模块:prettytable

import prettytable as pt

tb=pt.PrettyTable()
tb.field_names=['行号','座位1','座位2','座位3','座位4']
for i in range(4):
  lst=[f'第{i}行','有票','有票','有票','有票']
  tb.add_row(lst)
print(tb)

可以显示整齐的表格

image-20210729141803122

计算日期

用到模块:datetime

import datetime
sdate=datetime.datetime.strptime('2021-07-29','%Y-%m-%d')
fdate=sdate+datetime.timedelta(days=20)
print(f'20天之后是{fdate}')
print(f'20天之后是{str(fdate).split(" ")[0]}')

输出:
20天之后是2021-08-18 00:00:00
20天之后是2021-08-18

记录查看登陆日志

你可能感兴趣的:(python学习笔记(《Python教程全套》杨淑娟))