一、序言
学习python常用基础语法知识,通过实践+记录笔记加深理解。
二、python基础
2.1变量名 命名规范
变量名 :
(1)要遵循标识符的规则
(2)见名知意
(3)命名习惯
驼峰命名法:
-大驼峰,每一个单词的首字母都大写MyName
-小驼峰,第一个单词的首字母小写,其余单词首字母大写 myName
下划线连接
单词与单词之间使用下划线连接,python主要使用这一种
2.1.1标识符:
用户编程时使用的名字,用于给变量、函数、类等命名。
2.1.2标识符规则
(1)由数字,字母,下划线组成
(2)不能使用数字开头
(3)不能使用python内置关键字
(4)严格区分大小写
(5)不建议使用中文
2.2数据类型
2.2.1查看变量数据类型
(1)使用type(变量)函数
(2)使用print()来打印输出到控制台查看

2.3数据类型转换
(1)将一种数据类型转换为另一种数据类型
原数据是什么类型,要转换成什么类型
语法格式:
变量 = 要转换为的类型(原数据)
说明:数据类型转换,不会改变原数据的类型,是生成一个新数据
| 函数 | 说明 | 注意 |
| int(x) | 将x转换为一个整数 | x是字符串时必须是整数类型字符串 |
| float(x) | 将x转换成一个浮点数(小数) | x是字符串时,只要是数字类型字符串即可 |
| str(x) | 将x转换为字符串 | 对任意类型x都可以转换字符串类型 |
| tuple(s) | 将序列s转换为一个元组 | |
| list(s) | 将序列s转换为一个列表 |
2.4交互运行python代码
进行小的代码验证,每行代码都会有一个执行结果

2.5格式化输出

2.6转义字符
将两个字符进行转义,表示一个特殊的字符
(1)\n 表示换行
(2)\t表示制表符(Tab键)

三、逻辑控制语句
3.1if语句的基本结构
(1)单独的if语句,就是 如果条件成立,做什么事
语法格式:
if 判断条件:
判断条件成立,执行的代码
3.2if else结构
语法格式:
# if else 如果... 否则 ...
if 判断条件:
判断条件成立,执行代码
else:
判断条件不成立,执行的代码
3.3if elif else结构
语法格式:
# if elif else 如果 ... 如果 ... 否则 ...
if 判断条件1:
判断条件1成立,执行的代码
elif 判断条件2: # 判断条件1不成立才会执行判断条件2
判断条件2成立,执行的代码
elif ...:
pass
else:
以上判断条件都不成立,才会执行的代码
3.4debug打断点
选中需要调试的代码执行debug,然后按F8

3.5if嵌套
在一个if(elif else)语句中嵌套另一个if(elif else)
判断条件存在递进关系才会使用,只有第一个条件成立,才会判断第二个条件
语法格式:
if 判断条件1:
判断条件1成立,执行的代码
if 判断条件2:
判断条件2成立,执行的代码
else:
判断条件2不成立,执行的代码
else:
判断条件1不成立,执行的代码
3.6while & for循环
3.6.1while语句基本语法
应用场景:让执行的代码按照指定的次数重复执行
初始条件设置 # 通常是重复执行的计数器
while 条件:# 判断计数器是否达到目标次数
条件满足时,做事情1
条件满足时,做事情2
条件满足时,做事情N
处理条件(计数器+1)
3.6.2死循环 & 无限循环
(1)死循环和无限循环 在程序执行上面看起来一样,都是代码一直执行不能停止
(2)死循环:是由于写代码 出现的bug
(3)无限循环:是代码需求编码
(4)无限循环中,一般会存在一个if判断语句 ,当这个判断语句的条件成立,执行break语句来终止循环
(5)关键字 break:当程序代码执行遇到break,break所在的循环就会被终止执行
(6)关键字continue:当程序代码执行遇到continue,continue后续的代码不执行,但是会继续下一次循环
while True:
xxxx
xxxx
....
xxxx
if xxxx:
break
xxxx
3.6.3for循环
for 循环也称为是for遍历,也可以指定次数的循环
遍历:是从容器中将数据逐个取出的过程
容器:字符串、列表、元组、字典
# for循环遍历字符串
for 变量 in 字符串:
重复执行代码
# 字符串中存在多少个字符,代码就执行多少次
# 每次循环会从字符串中取出一个字符保存到前边的变量中
# for和in都是关键字
3.6.4for指定次数的循环
for 变量 in range(n): # n就是要循环的次数
重复执行的代码
# range(n) 可以生成[0,n)的整数的序列,不包含n

四、容器(数据序列)
容器:字符串str,列表list,元组tuple,字典dict,集合set
4.1字符串
使用引号(单引号、双引号、三引号)引起来的内容就是字符串
str1 = 'hello world'
str2 = "hello world"
str3 = """hello world"""
str4 = '''hello world'''
print(type(str1),type(str2),type(str3),type(str4))
# 字符串含有单引号就用双引号定义反之亦然
str5="i'm 小明"
print(f"str5={str5}")
# 转义字符处理
str6 = 'i\'m 小明'
print(f"str6={str6}")

4.1.1下标(索引)
(1)下标(索引),是数据在容器(字符串、列表、元组)中的位置,编号
(2)一般来说,使用的是正数下标从0开始
(3)作用:可以通过下标获取具体位置的数据:容器[下标]
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 正数下标 |
| a | b | c | d | e | f | g | 字符串 |
| -7 | -6 | -5 | -4 | -3 | -2 | -1 | 负数下标 |
4.1.2切片
切片可以一次性获取容器中多个数据,多个数据之间存在一定的规律,数据的下标是等差数列
语法:容器[start:end:step]
(1)start 表示开始位置的下标
(2)end表示结束位置的下标,但是end所对应的下标位置的数据是不能取到的
(3)step步长,表示相邻两个坐标之间的差值
4.1.3字符串的查找find()
语法:字符串.find(sub_str) #在字符串中查找是否存在sub_dtr这样的字符串
4.1.4字符串的替换replace()
语法:字符串.replace(old,new,count) # 将字符串中的old字符串替换为new字符串
-count一般不写,表示全部替换,可以指定替换的次数
4.1.5字符串的拆分split()
字符串.split(sep) #将字符串按照指定的字符串sep进行分隔
data = 'hello python and itcast and itheima'
list=data.split()
print(f"按照空白字符分隔{list}")
data = 'hello python\tand itcast and\nitheima'
list=data.split('and')
print(f"按照and字符分隔{list}")

4.1.6字符串的连接join
字符串.join(容器) # 容器一般是列表,将字符串插入到列表相邻的两个数据之间,组成新字符串
list = ['hello', 'python', 'and', 'itcast', 'and', 'itheima']
str1=' '.join(list)
print(f"使用空格连接字符串{str1}")
str2=','.join(list)
print(f"使用,连接字符串{str2}")

4.2列表list
列表是python中使用最频繁的数据类型,在其他语言中叫数组,专门用来存储一组数据
(1)列表,list,使用[]
(2)列表可以存放任意多个数据
(3)列表中可以存放任意类型的数据
(4)列表中数据之间使用逗号隔开
# 方式1,使用类实列化方式定义列表
# 定义空列表 变量=list()
list1=list()
print(type(list1))
# 定义非空列表,也称为类型转换,list(可迭代类型),可迭代类型:能够使用for循环
# 将容器中的每一个数据都作为列表中一个数据进行保存
list2=list('abcd')
print(list2)
# 方式2直接只用[]定义列表list
# 定义空列表
list3=[]
# 定义非空列表
list4=[1,3,18,'hello',False]
print(f"list4={list4}")

注:列表是容器所以也支持下标和切片
4.2.1列表查询方法index()
(1)index()这个方法的作用和字符串中的find()的作用一样
(2)列表中没有find()方法,但字符串中有find() & inde()
4.2.2列表查询方法count()
列表.count(数据) # 统计,指定数据在列表中出现的次数

4.2.3列表的增(添加数据)append()
列表.append(数据) # 向列表的尾部添加数据
# 返回 none,所以不用 变量=列表.append()
# 直接在原列表添加数据,不会生成新的列表

4.2.4列表删除数据pop()
列表.pop(index) # 根据下标删除列表中的数据
-index不写,默认删除最后一个
-返回,删除的数据


4.2.5列表修改数据
想要修改列表中的数据,直接是所有下标即可
列表[下标]=新数据

4.2.6列表的反转reverse()
(1)字符串 反转 字符串[::-1]
(2)列表反转
列表[::-1] #得到一个新的列表,原列表不会改动
列表.reverse() 直接修改原列表的数据

4.2.7列表的排序
(1)前提:列表中的数据要一样
列表.sort() # 升序,从小到大,直到在原列表中进行排序
列表.sort(reversed=True) # 降序,从大到小,直到在原列表中进行排序

4.2.8列表的嵌套
(1)列表的嵌套就是指列表中数据都是列表



4.3元组tuple()
(1)元组 tuple,使用()定义:tuple()
(2)元组和列表非常相似,都可以存储多个数据,都可以存储任意类型的数据
(3)区别就是,元组中的数据不能修改,列表中可以修改
(4)因为元组中数据不能修改,所以只能查询,如index、count。支持下标和切片
(5)元组,主要用于传参和返回值
说明:语法上支持类实例化方式定义空元组但不用,没有意义,空元组没有数据不支持修改。
通常直接使用小括号定义元组。
4.4字典dict
定义:
(1)字典 dict,使用{}表示
(2)字典是由键key值value对组成的,key:value
(3)一个键值对是一组数据,多个键值对之间使用逗号隔开
(4)在一个字典中主要使用字符串类型,可以是数字
(5)字典中没有下标

4.4.1字典的增加和修改
(1)字典['键'] = 值
# 键 存在,修改
# 键不存在,添加

4.4.2字典的删除方法
(1)字典.pop(键)
说明:在字典数据中根据给出的键删除对应的值

4.2.3字典的查询
(1)根据字典的键,获取对应的值
(2)方法一:
字典[键] # 键 不存在,会报错
(3)方法二:
字典.get(键) # 键不存在,返回None

4.2.4字典的遍历
(1)遍历字典的键
方式1:
for 变量 in 字典:
print(变量)
方式2:
for 变量 in 字典.keys(): # 字典.keys() 可以获取字典所有的键
print(变量)
(2)遍历字典的值
for 变量 字典.valus(): # 字典.valus() 可以获取字典中所有的值
print(变量)
(3)遍历字典的键和值
for 变量1,变量2 in 字典.itmes(): # 字典.itmes() 获取都是字典的键值对
print(变量)
# 类实例化方式定义字典
dict1 = dict()
# 直接使用{}定义字典
dict2 = {}
# 使用{}定义非空字典
dict3 = {"name":"鲁班","age":18,"height":1.72,"isMen":True}
print(f"非空字典数据为dict3={dict3}")
#获取字典的键
for k in dict3:
print(k)
print('-'*30)
for k in dict3.keys():
print(k)
print('-'*30)
# 获取字典的值
for value in dict3.values():
print(value)
print('-'*30)
# 获取字典的键值对
for k,v in dict3.items():
print(f"获取字典键值对为{k}:{v}")

4.5集合set
(1)集合 set,{数据1,数据2,...,数据n}
(2)集合中数据是不能重复的,没有重复的数据
(3)应用:主要对列表进行去重操作
将列表转换为集合可以达到去重要求,再将集合转换为列表。
(4)可以使用2个容器。从A容器拿到数据看在不在B容器里,不在就放进去,达到去重
五、函数
定义:
(1)函数定义,就是给多行代码起名字的过程
(2)函数的定义需要使用关键字 def
def 函数名():
函数中的代码
# 处于def缩进中的代码均属于这个函数
# 函数名要满足标识符的规则
# 函数定义不会执行函数中的代码,想要执行需要调用函数
函数调用:
(1)函数调用,就是使用多行代码的过程
(2)语法:函数名()
5.1函数基础
5.1.1参数
参数:在函数定义的时候,在括号中写入变量,这个变量就称为是函数的参数,形式参数(形参)
在函数调用的时候,可以给定义时候的形参传递具体的数据值,供其使用。实际参数(实参)
即:在函数调用的时候,会将函数的实际值传递给形参
好处:可以让函数更加通用,函数中的数据值不是固定的,是调用的时候,实际传递的
5.1.2函数的嵌套使用
在一个函数中调用另一个函数。
(1)代码从上到下执行
(2)函数定义不会执行函数中的代码
(3)函数调用会进入函数中执行函数中的代码
(4)函数中的代码执行结束,会回到调用的地方继续向下执行
"""
定义名为test01的函数,打印当前函数的名称
定义名为test02的函数,打印当前函数的名称,并调用test01
在main代码中调用test02
"""
def test01():
print(1)
print("这是第一个函数")
print('func01')
def test02():
print(2)
print("这是第二个函数")
print('func02')
test01()
print(5)
test02()
print(6)
# 5 2 1 6

5.1.3函数的返回值
返回值:函数执行的结果
(1)在一个函数中,想要返回一个数据(想要有返回值),需要使用return关键字
(2)为什么需要返回值?因为在函数中可能通过各种代码,得到的数据结果,想要在函数外部使用,就需要使用返回值
(3)如果函数有返回值,一般在调用的时候会使用变量来接收(保存)返回值,以便后续使用
(4)return关键字作用
-将一个数据值返回到调用的地方
-函数遇到return会结束函数的执行
(5)return关键字只能用在函数中
(6)如果一个函数没有写return,可以认为返回值是None
"""
需求:设计一个函数用于获取两个数中的较大数,数据来自于函数的参数。
实现思路分析
1、定义一个函数,例如get_max()
2、为函数定义两个参数,用于接收两个数字
3、使用判断语句分两种情况对两个数字的大小关系进行处理
4、准备测试数据,调用函数
"""
def get_max(a,b):
if a > b:
return a
else:
return b
# 调用函数get_max()
num = get_max(10,20)
print(f"较大的数是:{num}")
5.2模块和包
模块的概念:
1、在python中每一个以.py结尾的python代码文件都是一个模块
2、模块名同样也是一个 标识符 需要符合标识符的命名规则
3、在模块中定义的 全局变量 函数 类 都是提供给外界直接使用的 工具
4、模块就好比是工具包,要想使用这个工具包中的工具就需要先导入模块
模块的导入方式:
(1)import 模块名 # 模块名就是代码文件名,不要.py
# 使用模块中的功能
模块名.功能名 # 功能可以是变量、函数、类
多用于导入系统中的常用的模块和功能
(2)from 模块名 import 功能名 # 导入指定的功能
# 使用
功能名()
多用于导入自己书写的或者第三方的模块
快捷键:在要导入的功能名上使用快捷键 Alt Enter

5.2.1__name__变量
1.导入模块的时候,会执行模块中的代码
2.作用:如果在导入模块的时候,模块中的部分代码不想被执行,可以使用__name__来解决
3.__name__变量,是python解释器内置的变量(变量的值是自动维护的),每个代码文件中都有这个变量
3.1在模块中直接右键运行代码文件,__name__变量的值是 '__main__'
3.2如果是被导入运行代码文件__name__变量的值是模块名(文件名)
例如:
if __name__ == '__main__'
# 在这个if的缩进中书写的代码,导入的时候不会被执行
5.2.2模块的导入顺序
(1)在导入模块的时候,会先从代码所在的目录进行导入
(2)如果没有找到,会去python系统的目录查找导入
(3)如果还没找到就报错
注:自定义的代码文件名不要和要导入的系统模块文件名一样
5.2.3包package
包:将多个模块放在一个目录中集中管理,并在这个目录中创建一个__init__.py文件(可以什么都不写),就是一个包
包的导入:
方式一
import 包名.模块名
使用
包名.模块名.工具名
方式二
from 包名 import 模块名
使用
模块名.工具名
方式三
from 包名.模块名 import 工具名
使用
直接使用工具名
5.3变量类型
5.3.1变量引用
引用:
(1)定义变量的时候,变量和数据都会在内存开辟空间
(2)变量所对应的内存空间中存储的是数据所在内存地址(平时理解为将数据存储到变量中)
(3)变量中保存数据的地址,就称为是引用
(4)python中所有数据的传递,传递的都是引用(即地址)
(5)赋值运算符 = 会改变变量的引用,只有 = 可以修改变量的引用
(6)可以使用id(变量) 函数,查看变量的引用


5.3.2可变类型和不可变类型
根据内存中的数据是否允许修改,将数据类型分为可变类型与不可变类型
简单理解:不使用等号能不能修改数据值
可变类型:可以修改
列表list
字典dict
集合set
不可变类型:不允许修改
数字类型int float bool
字符串str
元组tuple

5.3.3局部变量和全局变量
根据变量定义的位置将变量分为局部变量和全局变量
5.3.3.1局部变量
(1)在函数内部定义的变量,称为局部变量
(2)特点
局部变量:只能在当前函数内部使用
可以在不同函数内定义名字相同的局部变量
(3)生命周期(使用范围)
在函数执行(调用)的时候被创建,函数执行结束被销毁(删除)
(4)形参可以认为是局部变量
(5)如果想要在函数外部使用局部变量的值,使用return返回
def func1():
num = 10 # 局部变量
print(num)
def func2():
num = 20
print(num)
if __name__ == '__main__':
func1() # 10
func2() # 20
5.3.3.2全局变量
1、在函数外部定义的变量
2、特点
(1)全局变量可以在任意函数内访问(读取)
(2)想要在函数内部修改全局变量的引用,需要使用global关键字声明(使用global关键字可以声明为全局变量)
(3)如果在函数内部出现和全局变量名字相同的局部变量,在函数内部使用的是局部变量
3、生命周期
(1)代码执行时候创建,执行结束销毁
# 定义全局变量
global_num = 10
def func1():
print(global_num)
def func2():
global_num = 20 # 定义局部变量
print(global_num)
def func3():
global global_num
global_num = 30
print(global_num)
if __name__ == '__main__':
func1() # 10
func2() # 20
func3() # 30 修改了全局变量,值修改为30
func1() # 30
5.4函数进阶-高级函数
函数返回多个数据值
return关键字的两个作用
(1)返回数据值
(2)结束函数的运行
函数中如果想要返回多个数据值,一般是组成元组进行返回
5.4.1函数传参的方式
是指如何将实参的值传递给形参
(1)位置传参
按照形参的顺序将实参的值传递给形参
(2)关键字传参
在函数调用的时候,指定将实参传递给哪个形参
(3)混合使用
位置参数必须写在关键字参数的前边,关键字参数必须放在位置参数的后边。
同一个形参只能接收一个实参值(不能即使用位置传参和关键字传参给同一个形参传参)
def show_info(name,age):
print(f"name:{name},age:{age}")
# 位置传参
show_info('鲁班',18)
# 关键字传参
show_info(age=18,name='貂蝉')
# 混合使用
show_info('王昭君',age=14)
5.4.2缺省参数(默认参数)
定义:在函数定义的时候,给形参一个默认的数据值,这个参数就是缺省参数(默认参数)
特点:在函数调用的时候,缺省参数可以不用传递实参值
(1)如果不传实参值,使用的就是默认值
(2)如果传递实参值,使用就是传递的实参值
注:缺省参数必须写在普通参数的后边
"""
定义show_info 参数:姓名、年龄、性别
将年龄设置为默认参数,性别设置为默认 保密
"""
# parameter形参,argument实参
def show_info(name,age=18,sex='保密'):
print(name,age,sex)
# 调用
show_info('项羽',18,'男')
# 诸葛亮
show_info('诸葛亮')
# 鲁班 20
show_info('鲁班',20)
# 女娲 女
show_info('女娲',sex='女')
5.4.3多值参数(可变参数/不定长参数)
1、在定义函数的时候,不确定在调用的时候,实参有多少个,此时可以使用多指参数
2、在普通的参数前边加上一个* 这个参数就变为多值参数
3、这个参数可以接收任意多个位置传参的数据,类型 元组
4、这个形参一般写作args(arguments)即*args
5.4.4参数顺序
# 普通,缺省,多值
def 函数名(普通,缺省,*args)
pass
"""
定义一个函数my_sum,作用:可以对任意多个数字进行求和计算
"""
from TestDemo.可变与不可变类型 import my_tuple
def my_sum(*args):
num = 0
for i in args:
num +=i
return num
print(my_sum()) # 0
print(my_sum(1)) # 1
print(my_sum(1,2)) # 3
print(my_sum(1,2,3)) # 6
my_tuples = (1,2,3,4,5)
# 需要对元组中的所有数据使用my_sum进行求和
# 想要把列表(元组)中的数据作为位置参数进行传递,
# 只需要在列表(元组)前边加上一个*进行拆包即可
print(my_sum(*my_tuples)) # 15
5.4.5匿名函数
定义:使用lambda关键字定义的表达式
语法:lambda 参数,参数:一行代码 # 只能实现简单的功能,只能写一行代码
# 匿名函数一般不直接使用,作为函数的参数使用
"""
定义匿名函数,可以对两个数字进行求和
"""
# 匿名函数也可以调用
func = lambda a,b:a+b # 将匿名函数地址保存到变量func中,所以func就代指函数
print(func(1,2))
# 给定一组列表数据根据年龄排序
# user_list 是一个列表,其中包含三个字典元素
user_list = [
{'name':'鲁班','age':30},
{'name':'张飞','age':18},
{'name':'项羽','age':20}
]
"""
user_list.sort() #只能对数字,字符串排序
想要对列表中的字典排序,需要key形参指定根据字典中的什么键排序
列表.sort(key=lambda x:x['键'])
"""
print(f"原数据:{user_list}")
user_list.sort(key=lambda x:x['age'])
print(user_list)
六、面向对象
了解面向过程:根据需求,将某些独立功能封装成一个又一个函数,最后完成的代码就是顺序地调用不同的函数
面向对象概念:相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法,根据职责确定不同的对象,在对象内部封装不同的方法。
面向对象核心:类和对象
6.1类和对象
类:是对具有相同特征或者行为的事物的一个统称,是抽象的不能直接使用
指代多个事物
代码中类是由关键字class定义
对象:是由类创建出来的一个具体存在的事物,可以直接使用
指代一个具体事物
代码中使用类去创建(创建过程叫实列化)
6.1.1类的构成
(1)类名:多个事物起一个名字,满足标识符规则,见名知意,类名满足大驼峰命名法(所有单词的首字母大写)
(2)属性(事物的特征)
(3)方法(事物的行为)
6.1.2面向对象代码的步骤
(1)设计类(找类的三要素)
(2)定义类
(3)创建对象(实例化对象)
(4)由对象调用类中方法
6.1.3面向对象基本语法
(1)定义类
# 1定义类使用关键字class
class 类名:
# 在class的缩进中定义类 的属性和方法
def 方法名(self): # 方法本质是函数
pass
# 2创建对象(实例化对象)
"""
在代码中 类名()就是创建对象。一般使用变量将创建的对象保存起来
"""
变量 = 类名() # 一般将这个变量称为对象,本质:变量中保存的是对象的引用地址
# 3调用类中方法
# 由类创建的对象可以调用类中的方法
对象.方法名()
6.2属性和方法
6.2.1self参数
(1)从函数的语法来看,self是形参,名字可以是任意的变量名,只是习惯叫self
(2)特殊点:self是一个普通的参数,按照函数的语法,在调用的时候必须传递实参值,原因是python解释器自动将调用这个方法的对象作为参数传递给self。谁调用函数self就是谁。
所以self就是调用这个方法的对象。
class Cat:
def eat(self): # self是调用这个方法的对象
"""吃鱼的方法"""
print(f'self:{id(self)}')
print('小猫爱吃鱼')
# 创建对象
tom = Cat()
print(f"tom :{id(tom)}")
# 通过对象调用类中的方法
tom.eat() # tom调用,self就是tom
blue_cat =Cat()
print(f'blue:{id(blue_cat)}')
blue_cat.eat() # blue_cat调用,self就是blue_cat
# 运行输出
tom :2030543059904
self:2030543059904
小猫爱吃鱼
blue:2030543059856
self:2030543059856
小猫爱吃鱼
6.2.2属性的使用
属性:表示事物的特征,可以给对象添加属性或者获取对象的属性值
给对象添加属性值:
对象.属性名=属性值 # 添加或者修改
获取对象的属性值:
对象.属性名
在方法中操作属性(self是对象)
self.属性名=属性值
self.属性名
例如类外部添加类属性:
class Cat:
def eat(self): # self是调用这个方法的对象
"""吃鱼的方法"""
print(f'self:{id(self)}')
print('小猫爱吃鱼')
print(f"小猫{self.name}爱吃鱼...")
# 创建对象
tom = Cat()
# 通过对象调用类中的方法
print(f"tom :{id(tom)}")
# 给Tom对象添加name属性
tom.name = '汤姆'
print(tom.name)
tom.eat()
blue_cat =Cat()
print(f'blue:{id(blue_cat)}')
blue_cat.name = '蓝猫'
blue_cat.eat()
6.2.3魔法方法
类内部添加属性:
在python中存在一类方法,以两个下划线开头,两个下划线结尾,在满足某个条件的情况下,会自动调用,这一类方法称为魔法方法---因为会自动调用
魔法方法:
(1)什么情况下会自动调用(自动调用的时机)?
(2)应用场景?
(3)注意事项?
6.2.3.1初始化方法__init__
(1)调用时机:在创建对象之后,会自动调用yinyon
(2)应用场景:初始化对象,给对象添加属性
(3)注意事项:
不要写错
如果属性是会变化的,则可以将这个属性的值作为参数传递,在创建对象的时候,必须传递实参值

#name属性不变:
class Cat:
def __init__(self):
print('我是init方法,我被调用了') # 断言
self.name = '汤姆'
def eat(self):
print(f"小猫{self.name}爱吃鱼...")
# init方法创建对象之后会自动调用
#blue = Cat()
blue_cat = Cat()
blue_cat.eat()
black_cat = Cat()
black_cat.eat()
------------------------
我是init方法,我被调用了
小猫汤姆爱吃鱼...
我是init方法,我被调用了
小猫汤姆爱吃鱼...
# name属性值变化就参数化
class Cat:
def __init__(self,name):
print('我是init方法,我被调用了') # 断言
self.name = name
def eat(self):
print(f"小猫{self.name}爱吃鱼...")
# init方法创建对象之后会自动调用
#blue = Cat()
blue_cat = Cat('蓝猫')
blue_cat.eat()
black_cat = Cat('黑猫')
black_cat.eat()
---------------------------
我是init方法,我被调用了
小猫蓝猫爱吃鱼...
我是init方法,我被调用了
小猫黑猫爱吃鱼...
6.2.3.2__str__方法
(1)调用时机:
使用print(对象) 打印对象的时候,会自动调用
如果没有定义__str__方法,默认打印的是对象的引用地址
如果定义__str__方法,打印的是方法的返回值
(2)应用场景
使用print(对象) 打印输出对象的属性信息
(3)注意事项
必须返回一个字符串
"""
定义Cat类,包含属性name和age,打印对象的时候,可以输出对象的姓名和年龄
类名:Cat
属性:name,age
方法:__str__,__init__
"""
class Cat:
def __init__(self,name,age):
self.name =name # 添加name属性
self.age = age # 添加age属性
def __str__(self): # 一般不使用print,直接return返回
return f"姓名:{self.name},年龄:{self.age}"
# 创建对象
tom = Cat('汤姆',3)
print(tom)
-----------------------------
姓名:汤姆,年龄:3
6.3面向对象三大特征
(1)封装:根据需求将属性和方法封装到一个抽象的类中。
(2)继承:实现代码的重用,相同的代码不需要反复的编写
(3)多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
6.3.1封装-登录模拟举例
需求:进入某web项目登录页面,输入用户名、密码、验证码之后登录系统
类的设计:
类名:LoginPage
属性:用户名username、密码password、验证码verify_code
方法:login
class LoginPage:
"""登录页面"""
def __init__(self,username,password,code):
self.username = username # 用户名
self.password = password # 密码
self.verify_code = code # 验证码
def login(self):
print(f"1.输入用户名:{self.username}")
print(f"2.输入密码:{self.password}")
print(f"3.输入验证码:{self.verify_code}")
print(f"4.点击登录")
if __name__ == '__main__':
admin = LoginPage('admin','123456','8888')
admin.login()
--------------------------------
1.输入用户名:admin
2.输入密码:123456
3.输入验证码:8888
4.点击登录
6.3.2继承
说明:如果多个类中存在相同的代码逻辑,则可以考虑将相同逻辑的代码抽取封装到父类中,再通过继承关系,直接实例化子类对象并调用父类中的方法使用即可,进而可以避免反复编写相同逻辑 的代码
注:在继承关系中,子类可以拥有父类的所有方法和属性

# 语法
# class 类A(object)
# class 类A
class 类A: # 默认继承object类,object类是python中最原始的类
pass
class 类B(类A): # 就是继承,类B继承类A
pass
# 类A:父类 或 基类
# 类B:子类 或 派生类
# 子类继承父类后,子类对象可以直接使用父类中的属性和方法
继承具有传递性:C继承B,B继承A,C可以使用A中的属性和方法
对象调用方法的顺序:对象.方法名()
注:会先在自己的类中查找,找到直接使用;没有找到就去父类中查找,找到直接使用,没有找到就一直在父类的父类中查找找到直接使用,找不到就一直找直到object类中查找,找到直接使用找不到就报错!
"""
1.定义动物类,动物类有姓名和年龄属性,具有吃和睡的行为
2.定义猫类,猫类具有动物类的所有属性和方法,并且具有抓老鼠的特殊行为
3.定义狗类,狗类具有动物类的所有属性和方法,并且具有看门的特殊行为
4.定义哮天犬类,哮天犬类具有狗类的所有属性和方法,并且具有飞的特殊行为
"""
class Animal:
"""动物类"""
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
"""吃"""
print(f"{self.name}:吃东西")
def sleep(self):
"""睡"""
print(f"{self.name}:睡觉")
class Cat(Animal):
"""猫类"""
def catch(self):
print(f"{self.name}:会抓老鼠...")
class Dog(Animal):
"""狗类"""
def look_the_door(self):
"""看门"""
print(f"{self.name}:正在看家...")
class XTQ(Dog):
"""哮天犬类"""
def fly(self):
"""飞"""
print(f"{self.name}:在南天门飞...")
if __name__ == '__main__':
ani = Animal('佩奇',2)
ani.eat()
ani.sleep()
cat = Cat('汤姆',4)
cat.eat() # 调用父类Animal中的方法
cat.sleep() # 调用父类Animal中的方法
cat.catch() # 调用自己类中的方法
dog = Dog('来福',6)
dog.eat()
dog.sleep()
dog.look_the_door()
xtq = XTQ('哮天犬',1000)
xtq.eat()
xtq.sleep()
xtq.look_the_door()
xtq.fly()
----------------------------------
佩奇:吃东西
佩奇:睡觉
汤姆:吃东西
汤姆:睡觉
汤姆:会抓老鼠...
来福:吃东西
来福:睡觉
来福:正在看家...
哮天犬:吃东西
哮天犬:睡觉
哮天犬:正在看家...
哮天犬:在南天门飞...
6.3.2.1重写(override)
1.什么是重写?
重写就是在子类中定义和父类中名字一样的方法
2.重写的原因?为什么重写?
父类中的代码不能满足子类对象的需要
3.重写的方式
(1)覆盖式重写
(2)扩展式重写
覆盖式:父类中的功能全部不要,直接在子类中定义和父类一样的方法接口,直接书写新的代码
扩展式:父类中的功能还需要,只是添加了新的功能
(1)先在子类中定义和父类中名字一样的方法
(2)在子类代码中使用super().方法名()调用父类中的代码
(3)书写新的功能
6.3.3多态
多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
"""
案例:
1.在Dog类中封装方法game,行为:普通狗只是简单玩耍
2.定义哮天犬XiaoTianDog继承Dog,并重写game方法,行为:哮天犬需要在天上玩耍
3.定义person类,并且封装一个和狗玩耍的方法,在方法内部直接让狗对象调用game方法
"""
class Dog:
def game(self):
print('普通狗简单的玩耍...')
class XTQ(Dog):
def game(self):
print('哮天犬在天上玩耍...')
class Person:
def play_with_dog(self,dog):
"""参数dog是狗类或者其子类的对象"""
print('人和狗在玩耍...',end='')
dog.game()
if __name__ == '__main__':
dog1 = Dog()
xtq = XTQ()
jack = Person()
jack.play_with_dog(dog1)
jack.play_with_dog(xtq)
------------------------------------------
人和狗在玩耍...普通狗简单的玩耍...
人和狗在玩耍...哮天犬在天上玩耍...
6.4属性和方法的分类
6.4.1私有和公有
在python中,定义类的时候,可以给属性和方法设置访问权限,即规定在什么地方可以使用
(1)公有权限:直接定义的属性和方法就是公有的
特点:可以在任何地方访问和使用,只要有对象就可以访问使用
(2)私有权限:只能在类内部定义(class关键字的缩进中),只需要在属性名或者方法名前边加上两个下划线,这个方法或者属性就变成私有
特点:私有只能在当前类的内部使用,不能在类外部和子类直接使用
应用场景:一般来说,定义的属性和方法都为公有,当某个属性不想在外部直接使用定义为私有,当某个方法是内部的方法(不想在外部使用)定义为私有。
"""
案例:
定义人类,name属性,age属性(私有)
"""
class Person:
def __init__(self,name,age):
self.name =name
self.__age = age # 私有属性
def __str__(self): #公有方法,下划线是自带的
return f"{self.name},{self.__age}"
def set_age(self,age):
"""定义公有方法修改私有属性"""
if age <0 or age >120:
print('提供年龄信息不符合')
return
self.__age = age
if __name__ == '__main__':
jack = Person('杰克',18)
print(jack)
jack.set_age(100)
print(f"调用公有方法修改私有属性age:{jack}")
---------------------------
杰克,18
调用公有方法修改私有属性age:杰克,100
6.4.2对象划分
python中一切皆对象。
类对象:就是类,就是使用class定义的类
在代码执行的时候,解释器会自动的创建
作用:使用类对象创建实例对象,存储一些类的特征值(类属性)
实例对象:
(1)创建对象也称为实例化,所以由类对象(类)创建的对象称为实例对象简称实例
(2)一般来说没有特殊强调,所说的对象都是指实例对象(实例)
(3)实例对象可以保证实例的特征值(实例属性)
(4)实例就是使用 类名() 创建的对象
6.4.3属性的划分
1.实例属性
概念:是每个实例对象具有的特征(属性),每个实例对象的特征
定义:一般都是在init方法中,使用self.属性名=属性值 来定义
特征(内存):每个实例对象都会保存自己的实例属性,即内存中存在多份
访问和修改:
# 可以认为通过self,因为self就是实例对象
实例对象.属性=属性值 # 修改
实例对象.属性 # 调用
2.类属性
概念:是类对象具有的特征,是整个类的特征
定义:一般在类的内部(class缩进中),方法的外部(def的缩进外部)定义的变量
特征(内存):只有类对象保存一份,即在内存中只有一个
访问和修改:
# 即通过类名
类对象.属性=属性值 # 修改
类对象.属性 # 调用
应用场景:
代码中使用的属性基本上都是实例属性,即通过self定义
当某个属性值描述的信息是整个类的特征(这个值变动,所有的这个类的对象这个特征都会发声变化)
举例:比如定义很多个狗类对象有普通狗、哮天犬等某一天发现不属于犬科了那么所有对象都要变化。比如普通狗的名字发声变化了是不影响哮天犬的。所以就是实例。
6.4.4方法的划分
1.实例方法
使用时机:如果方法中需要使用实例属性,则这个方法必须定义为实例方法
定义:
# 直接定义的方法就是实例方法
class 类名:
def 方法名(self):
pass
参数:参数一般写作self,表示的是实例对象
调用:实例对象.方法名()
2.类方方法
使用时机:如果方法中不需要使用实例属性但需要使用类属性,则这个方法可以定义为类方法
定义:
# 定义类方法需要在方法名上方书写@classmethod,即使用@classmethod装饰器装饰
@classmethod
class 类名:
def 方法名(cls):
pass
参数:一般写作cls表示类对象即类名,同样不需要手动传递,python解释器会自动传递
调用:类名.方法名() 或者 实例对象.方法名()
3.静态方法
使用时机:方法中即不需要使用实例属性也不需要使用类属性,可以将这个方法定义为静态方法
定义:
# 定义静态方法,需要使用装饰器@staticmethod装饰方法
class 类名:
@staticmethod
def 方法名():
pass
参数:静态方法对参数没有要求,一般没有不需要写
调用:类名.方法名() 或者 实例对象.方法名()
综合案例:
需求:
1.设计一个Game类
2.属性:
定义一个rop_score类属性----记录游戏的历史最高分
定义一个player_name实例属性----记录当前游戏的玩家姓名
3.方法:
静态方法show_help()----显示游戏帮助信息
类方法show_top_score()----显示历史最高分
实例方法start_game()----开始当前玩家的游戏
(1)使用随机数生成1-100之间数字作为本次游戏的得分
(2)打印本次玩家的游戏得分
(3)当前玩家分数和历史最高分比较,如果比历史最高分高就修改历史最高分。没有就不动历史最高分
4.主程序:main
(1)查看帮助信息
(2)查看历史最高分
(3)创建游戏对象开始游戏
(4)再一次开始游戏
import random
class Game:
# 定义类属性,保存历史最高分
top_score = 0
def __init__(self,name):
self.play_name = name # 实例属性
# 静态方法
@staticmethod
def show_help():
print('这是游戏的帮助信息')
# 类方法
@classmethod
def show_top_score(cls):
print(f"历史最高分为:{cls.top_score}")
# 实例方法
def start_game(self):
print(f"玩家{self.play_name}开始游戏...")
score = random.randint(1,100) # 本次游戏得分
print(f"玩家{self.play_name}本次游戏得分为{score}")
if score > Game.top_score:
Game.top_score = score
if __name__ == '__main__':
Game.show_help()
Game.show_top_score()
player = Game('鲁班')
player.start_game()
Game.show_top_score()
player.start_game()
Game.show_top_score()
--------------------------------------
这是游戏的帮助信息
历史最高分为:0
玩家鲁班开始游戏...
玩家鲁班本次游戏得分为90
历史最高分为:90
玩家鲁班开始游戏...
玩家鲁班本次游戏得分为17
历史最高分为:90
七、文件操作
7.1文件基本操作
7.1.1打开和关闭文件
文件的操作步骤:
(1)打开文件
(2)读写文件
(3)关闭文件(保存)
1.打开文件open()
open()函数常用参数解释:
open(file,mode='r',encoding=None) # 将硬盘中的文件加载到内存中
参数file:表示要操作的文件的名字,可以使用相对路径和绝对路径
绝对路劲:从根目录开始书写如C:/
相对路径:从当前目录开始书写的路径如./
参数mode:打开文件的方式
r 只读打开 read 如果文件不存在会报错
w 只写打开 write 如果文件存在会覆盖原文件
a 追加打开 append 在文件的尾部写入新的内容
参数encoding:编码格式
utf-8将一个汉字转换为3个字节的二进制
gbk将一个汉字转换为2个字节的二进制
返回值:文件对象
2.关闭文件close()
文件对象.close() # 关闭文件,如果是写文件会自动保存即将内存中的数据同步到硬盘
3.读文件read()
变量 = 文件对象.read()
返回值:返回读取到的文件内容。类型是字符串
"""
with open(file,mode,encoding) as 变量:
pass
# 变量就是文件对象
使用这种方式打开文件,会自动进行关闭,不用手动书写关闭的代码。
出了with的缩进之后,文件就会自动关闭。
"""
with open('a.txt',encoding='utf-8') as f:
buf = f.read()
print(f"buf ={buf}")
# 普通写法
f = open('a.txt',encoding='utf-8')
data = f.read()
print(f"data={data}")
f.close()
4.写文件write()
文件对象.write()
参数:写入文件的内容。类型字符串
返回值:写入文件中的字符数,字符串的长度
# 1.打开文件
f = open('a.txt','w',encoding='utf-8')
# 2.写文件
f.write('hello python')
# 3.关闭文件
f.close()
# 追加写入
with open('a.txt','a',encoding='utf-8') as f:
f.write('我是追加写入内容\n')
7.2json文件操作
7.2.1按行读取文件readline()
文件对象.readline() # 一次读取一行的内容,返回读取到的内容
read()和readline()如果读到文件末尾,返回的都是空字符串
with open('a.txt',encoding='utf-8') as f:
buf = f.readline()
print(f"buf={buf}")
7.2.2模拟读取大文件
需求:文件里面有未知的很多行内容,现需一次按行全部读取出来
with open('a.txt',encoding='utf-8') as f:
while True:
buf = f.readline()
if buf == "":
break
else:
print(buf,end='')
# 代码优化
with open('a.txt',encoding='utf-8') as f:
while True:
buf = f.readline() # 文件内容读完了,返回空字符串
if buf: # 空字符串就是 False
print(buf,end='')
else:
break
7.2.3Json语法
1.json中的数据类型
对象{}----python中字典
数组[]----python中列表
字符串,必须使用英文双引号----str
数字类型----int,float
bool类型----True False
空值----None
2.json文件,是一个对象或者是数组,对象和数组可以相互嵌套
3.json中的对象是由键值对组成的,键必须是字符串类型
4.json中的数据直接使用逗号隔开,最后一个数据后边不能加逗号
{
"name": "鲁班",
"age": 18,
"isMan": true,
"school": null,
"link": ["听歌","看书","打野"],
"address": {
"country": "China",
"city": "深圳"
}
7.2.4读取json文件
(1)导包import json
(2)json.load(文件对象)----得到的是列表或者字典
import json
with open('person_info.json',encoding='utf-8') as f:
buf = json.load(f)
print(type(buf))
print(buf)
# 姓名
print(buf.get('name'))
# 城市
print(buf.get('address').get('city'))
# 看书
print(buf.get('link')[1])
-----------------------------------
<class 'dict'>
{'name': '鲁班', 'age': 18, 'isMan': True, 'school': None, 'link': ['听歌', '看书', '打野'], 'address': {'country': 'China', 'city': '深圳'}}
鲁班
深圳
看书
7.2.5json文件的写入
(1)将python中列表或字典转换为json文件
(2)导包 import json
(3)使用json.dump(python中数据,文件对象) # 转储转存
import json
info = {'name':'鲁班','age':18,'sex':'男'}
"""
ensure_ascii=False 直接显示中文
indent=2 写入json文件缩进2字符
"""
with open("luban_info.json",'w',encoding='utf-8')as f:
json.dump(info,f,ensure_ascii=False,indent=2)
注:若看到某个方法中出现*那么星后面所有的参数必须使用关键字传参

八、异常处理
8.1捕获异常
异常概念:程序运行时,如果python解释器遇到一个错误,则会停止程序的执行,并且提示一些错误信息,这就是异常。
程序停止执行并且提示错误信息这个动作称为抛出异常
异常类型:错误信息描述
8.1.1捕获异常语法
try:
pass # 尝试执行的代码
except:
pass # 出现异常时执行的代码
说明:
try尝试,下方编写要尝试的代码,不确定是否能够正常执行的代码
except如果有异常捕获,下方编写捕获到异常,处理失败的代码
# 1.获取用户从键盘输入的数据
num = input("请输入数字:")
try:
# 2.转换数据类型为整数
num = int(num)
# 3.数据转换类型正确时,输出数据内容
print(f"[INFO]{num}")
except:
# 4.数据转换类型错误时,提示输入正确数据
print("[INFO]请输入正确的数据")
8.1.2捕获指定类型的异常
发生的异常可能存在多种,针对不同类型的异常解决处理的方案不一样
try:
pass # 可能发生异常的代码
except 异常类型1:
pass # 发生异常类型1,执行的代码
except 异常类型2:
pass # 发生异常类型2,执行的代码
except 异常类型n:
pass # 发生异常类型n,执行的代码
如何直到异常类型是什么类型?
例如:需求输入一个数那么久输入一个字母运行就可以看到报错类型


8.1.3捕获未知类型的异常(使用最多)
语法:
try:
pass # 可能发生异常的代码
except Exception as e:# Exception常见异常类的父类,变量e属于异常对象,print()可以打印异常信息
pass # 发生异常执行的代码
try:
num = int(input('请输入一个整数数字:'))
except Exception as e:# Exception常见异常类的父类,变量e属于异常对象,print()可以打印异常信息
print(f'发生异常,{e}') # 发生异常执行的代码

8.1.4异常捕获的完整结构
"""异常捕获的完整结构"""
try:
pass #可能发生异常的代码
except 异常类型:
pass #发生了指定类型的异常执行的代码
except Exception as e:
pass #发生了其他类型的异常执行的代码
else:
pass #没有发生异常,会执行的代码
finally:
pass #不管是否发生异常,都会执行的代码
8.1.5异常的传递
1.异常的传递是python中已经实现好的功能,不需要自己重新写代码实现
2.异常传递是指:在函数的嵌套调用过程中,如果发生了异常,没有进行捕获,会将这个异常传递到函数调用的地方,直到被捕获为止,如果一直没有捕获,才会报错终止执行

# 1.定义函数demo1()提示用户输入一个整数并返回
def demo1():
num = int(input('请输入一个整数:'))
return num
# 2.定义函数demo2()调用demo1()
def demo2():
demo1()
# 3.在主程序中调用demo2()
if __name__ == '__main__':
demo2()
-------------------------
请输入一个整数:a
Traceback (most recent call last):
File "D:\study\PythonProject\TestDemo\异常传递.py", line 10, in <module>
demo2()
File "D:\study\PythonProject\TestDemo\异常传递.py", line 7, in demo2
demo1()
File "D:\study\PythonProject\TestDemo\异常传递.py", line 3, in demo1
num = int(input('请输入一个整数:'))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'a'
例如:当输入一个字符a后运行报错:
本来是第3行报错,但报错传到第7行,又传到第10行仍没有异常处理才报错结束程序
为了简洁代码可以在最外层主函数捕获异常处理:
# 1.定义函数demo1()提示用户输入一个整数并返回
def demo1():
num = int(input('请输入一个整数:'))
return num
# 2.定义函数demo2()调用demo1()
def demo2():
demo1()
# 3.在主程序中调用demo2()
if __name__ == '__main__':
try:
demo2()
except Exception as e:
print(e)
------------------------------------------
请输入一个整数:a
invalid literal for int() with base 10: 'a'
进程已结束,退出代码为 0
6万+

被折叠的 条评论
为什么被折叠?



