一、python基础
1.变量及变量类型
概念
1.计算机的作用是计算,编程的目的为了更方便的计算,计算的对象是数据
2.变量是程序在运行过程中临时用于储存数据的东西
变量类型
- 数组number
- 布尔类型boolean
- 列表 list
- 元组 tuple
- 字典 dict
变量名命名规范 - 变量名应简短而有意义
- 单词使用小写字母,多个单词用下划线分割
2.标识符和关键字
标识符
标识符就是程序中用来标识变量,函数,类,或其他对象的名字
标识符命名规则
- 只能包含字母、数字、下划线不能以数字开头
- 区分大小写
- 不能是python关键字
3.输入和输出
# 常见的输出
print("我爱中国")
# 换行输出 \n 后的内容会在下一行打印
print("我爱\n中国")
# 拼接多个值
slogan = "我是纯爱战神"
print(slogan)
print("我的slogan是", slogan)
# 常见的获取键盘输入
# 可以使用input() 函数等待病获取用户键盘上的输入,用户回车结束输入,输入内容被认为
a = input()
password = input("请输入密码:")
print("用户密码为:", a)
# 关于函数
# 函数可以是别人或自己写的,可以直接使用,不用关心内部实现
# 函数有type(),print(),input()
first_number = input("请输入第一个数字:")
second_number = input("请输入第一个数字:")
result = int(first_number) + int(second_number)
print("计算结果为:", result)
'''
常用的类型转换
int() 转换为整数
float() 转换为浮点数
str() 转换为字符串
bool() 转换为布尔类型
'''
4.运算符
4.1算数运算符
注意混合运算时的优先级:** 高于 * / // % 高于 + -,最好的方法就是使用()处理优先级
不同类型数字运算时,整数会转换成浮点数进行运算
4.2 赋值运算符
4.3 关系运算符
4.4 逻辑运算符
5. 判断语句
'''
if else
if 条件:
满足条件执行
else:
不满足条件执行
'''
# age = 17
age = 19
if age > 18:
print("可以上网")
else:
print("不能上网")
'''
if 条件1:
事件1
elif 条件2:
事件2
elif 条件3:
事件3
else:
事情4
'''
score = 77
if 90 <= score <= 100:
print("A")
elif 80 <= score < 90:
print("B")
elif 70 <= score < 80:
print("C")
else:
print("D")
# if嵌套
a = "高"
b = "富"
c = "穷"
if a == "高":
if b == "富":
if c == "帅":
print("高富帅")
# match...case...,python3.10以上版本的新特性,也属于分支结构的一种
x = 1
match x:
case 1:
print("x is 1")
case 2:
print("x is 2")
case 3:
print("x is 3")
6.循环语句
三大控制结构
顺序
分支
循环
用于控制代码的执行顺序
顺序:从上而下,顺序执行代码
分支:根据条件判断,确定执行哪个分支
循环:让特定代码块中的代码重复执行
6.1 while循环
基本语法
"""格式:
条件(满足时):
执行内容
"""
while True:
print("123")
# 上面代码缺少条件限制,导致死循环
i = 0
while i < 5:
print("hello")
i = i + 1
while 嵌套
和 if嵌套类似,while嵌套就是while里面还有while,审核或中华表盘上的时分秒针的运动就是循环嵌套的场景
- 语法格式
'''
while 条件1:
事件1
while 条件2:
事件2
'''
day = 1
while day <= 7:
print("今天是第", day, "天")
problem = 1
while problem <= 3:
print("做了", problem, "道题")
problem += 1
day += 1
6.2for循环
可以遍历任何可迭代对象,如:字符串,列表,元组,字典
- 语法格式
for 临时变量 in 可迭代对象:
满足条件时执行的代码
6.3 break和continue
break
break作用是终止当前循环,并跳出循环体外,并继续执行循环之后的代码
i = 1
while i <= 5:
print(i)
if i == 3:
break
i += 1
continue
continue的作用是跳过本次循环中的剩余代码,直接进入下次循环
i = 1
while i <= 5:
i += 1
if i == 3:
continue
print(i)
注意点
- break 和 continue 只能用在循环中,除此之外不能单独使用
- break 和 continue在嵌套循环中,只能对最近的一层循环起作用
面试题
Python中如何跳出循环[2]
- break,用于结束循环
- continue,用于跳出本次循环,直接进入下一次循环
二、高级数据类型
1.字符串
双引号或单引号中的数据就是字符串
a = "abc"
b = "1234221"
############################
name = "张三"
age = 18
print("你好", name, ",祝你", age, "岁生日快乐!")
# 字符串格式化
# 就是把字符串嵌入到字符串中,推荐 字符串,format()
print("你好{},祝你{}岁生日快乐!".format(name, age))
# 自定义名片
name = input("请输入你的名字:")
position = input("请输入你的职位:")
company_name = input("请输入你的公司名字:")
print("-" * 30)
print("姓名:{}".format(name))
print("职位:")
print("公司名称")
print("-" * 30)
# 字符串下标
# 下标从0开始
# 下标从左往右,从0开始
s = "ABC"
print(s[0])
# 下标从右往左 从-1开始
print(s[-1])
# 字符串切片:截取其中一部分,字符串/元组/列表都支持切片
# 语法:[起始下标:结束下标:步长]
print(s[:]) # 取所有,默认步长为1
print(s[::2]) # 取所有,默认步长为2
print(s[:3]) # 取前三位
print(s[5:]) # 取第五位以后得内容
print(s[1:5]) # 取第2 3 4 5位的内容
print(s[1:5:2]) # 取第2 4位的内容
print(s[1:-1]) # 取第2到倒数第2位的内容
print(s[5:1:-1]) # 步长是负数,表示反向(从右往左),取第六位和第四位
# 字符串常见操作
# len(),可以获取字符串的长度
s = "听君一些话,如同一席话"
print(len(s))
# find() 和 index(),检测字符串中是否包含某个子串,如果包含某个子串
# 如果包含,则返回第一个找到的字串的初始下标
s = "听君一些话,如同一席话"
print(s.find(","))
print(s.index(","))
# 区别在于,如果找不到,find返回-1,index则抛出异常
# [了解] s.find(sub,start,end)
# star 表示搜索的起始位置,默认0[可选]
# star 表示搜索的结束始位置,默认字符串的长度[可选]
# index()也支持这种写法
print(s.find("一席话", 0, 11))
# replace()替换字符串中的某些子串,可以控制替换次数
print(s.replace("一", "二"))
print(s.replace("一", "二", 1)) # 替换一次
# count() 返回字符串中某个子串出现的次数
print(s.count("一席话"))
print(s.count("一席话", 6, 11))
# split() 以某字符为分隔符进行切片
print(s.split(","))
print(s.split("一"))
# startwith() 和endwith()检查字符串是否以某子串为开始或结束
print(s.startswith("听"))
print(s.endswith("话"))
# lower()和upper(),可以把字符串中的字符转为大写或小写
c = "Hello World"
print(c.lower())
print(c.upper())
# isalpha() isdigit() 和 isalnum(),判断字符串中所有字符都是 字母,数字,字母或者数字
s1 = "helloworld"
s2 = "123"
s3 = "helloworld123"
print(s1.isalpha())
print(s1.isdigit())
print(s1.isalnum())
# join(),格式为 分隔符.join(数据),数据可以是字符串,列表,字典,返回值是字符串
print("~".join(s))
l = ["广东省", "广州市", "天河区"]
print("".join(l))
面试题
1. 如何实现字符串的反转[2]
实现字符串反转的方法很多,比如切片,内置函数,循环等
- 切片方式最为方便,只需要设置步长为-1即可
- 内置函数的方法思路是先用reversed函数反转,在用join函数进行拼接
- 循环的方法思路是遍历字符串的每个字符,循环拼接时,用新字符+就字符就可以
s = "听君一席话,如同一席话"
# 切片
print(s[::-1])
# 内置函数 reversed()返回逆序迭代器
print("".join(reversed(s)))
# 循环
print()
ss = "" # 定义一个空字符串
for c in s:
ss = c + ss # 每次循环拿出的字符c,排在前面
print(ss)
2.列表
什么是列表
列表是python中使用非常频繁的数据类型,在其他语音中常叫作数据组
语法上用[]来定义一个列表,数据之间用逗号分隔
# 什么是列表
# 列表是python中使用非常频繁的数据类型,在其他语音中常叫作数据组
# 语法上用[]来定义一个列表,数据之间用逗号分隔,例如
name_list = ["张三", "李四", "王五"]
# 列表的索引从0开始(索引就是下标),引出超过索引范围会报错
# 列表可以储存不用类型的数据
l = ["张三", 100, [1, 2]]
print(l[0])
# 列表的遍历
# for
for name in name_list:
print(name)
# while
i = 0
while i < len(name_list):
print(name_list[i])
i += 1
# 列表 常见地增删改查
# 增:append ,extend, insert
# append
l = [1, 2]
l.append(3)
l.append(True)
l.append([5, 6])
print(l)
# extend 可以把一个可迭代类型数据中的元素逐一加到列表中
a = [1, 2]
b = [3, 4]
c = "abc"
a.extend(b)
print(a)
# insert,可以在指定位置钱插入数据
l = [1, 2, 3, 4]
l.insert(2, "a")
print(l)
# print(l)
# 删:pop ,remove
# pop 根据索引删除列表中的数据,默认删除列表中的最后一个数据
l = [1, 2, 3, 4]
l.pop()
l.pop(2)
print(l)
# remove() 根据值从列表中删除数据
l = [1, 2, 3, 4]
l.remove(3)
ll = ["张三", "李四", "王五"]
ll.remove("李四")
print(l)
# 改,修改列表中数据有很多方法,需灵活使用,最常见的是根据下标进行数据的修改
l = [1, 2, 3, 4]
l[1] = 3
print(l)
# in和not in 用于判断列表中是否存在某条数据,成功为true,失败为false
if 1 in l:
print("存在")
if 5 not in l:
print("不存在")
# index 和 count
print(l.index(1)) # 返回下标
print(l.count(1)) #
# 排序 sort
# sort方法是可以将列表按顺序从新排列,默认为是从小到大,参数reverse = True是从大到小的
l = [1, 3, 4, 2]
l.sort()
print(l)
l.sort(reverse=True)
print(l)
# 注意:列表中的数据是同一类型时才可以排序,如果同时出现数字跟字符串则不能进行排序
# [了解] 列表生成式,帮我们生成列表
# 生成0-9的10个数
a = [x for x in range(10)]
print(a)
# 生成1-10
b = [x for x in range(1, 11)]
print(b)
# 生成10以内的奇数/偶数
c = [x for x in range(1, 11) if x % 2 == 1]
print(c)
d = [x for x in range(1, 11) if x % 2 == 0]
print(d)
面试题
列表中的数据如何拼接成字符串[1]
- 想把列表中元素拼接成一个字符串有很多方法
- 其一,我们可以使用join方法,用空字符串做分隔符来连接列表中的元素
- 其二,我们可以使用+运算符,循环向空字符串中逐一添加列表中的元素
name_list1 = ["张三", "李四", "王五"]
# 1.使用+运算的方法
s = ""
name_list1 = ["张三", "李四", "王五"]
for name in name_list1:
s += name
print(s)
# 2.使用join,用于将列表中的数据以某个分隔符进行连接,返回字符串
result = "".join(name_list1)
print(result)
3.元组
元组tuple 是与列表类似,语法上用()来定义一个元组
# 什么是元组
# 元组tuple 是与列表类似,语法上用()来定义一个元组
# 元组的常见操作,元组的数据不能修改
l = [1, 2, 3]
t = (1, 2, 3)
l[1] = 4
print(l)
# 对元组内的数据操作只支持查询类操作,如index,count
t = (1,2,3,4,5)
print(t.index(3))
print(t.count(4))
面试题
python中列表和元组的区别[2]
- 列表是动态的,列表中数据支持增删改查的操作
- 元组是静态的,元组中的数据只支持查询操作,可以理解为元组就是一个只读的列表
- 从定义的角度说,列表需要中括号,元组用小括号来定义
- 从设计的角度说,列表用于储存一系列动态变化的数据,如:坐标,日期等
- 元组用于储存不变的数据,比如星期几
- 从性能的角度来说,元组的性能优于列表(这和内存分配机制有关)
如果通过切片获取一个数据,倒数的三个元素[1]?
- 首先很多数据类型都支持切片的操作,比如字符串,列表,元组
- 切片的语法是用起始位,结束位和步长来控制
- 如果想要回去倒数的三个元素只需要设置起始位为负三即可(形式为:变量名[-3,])
4.集合
集合 set 和列表,元组都很像
# 什么是集合
# 集合 set 和列表,元组都很像
# 区别:集合的用途保存不重复的数据
# 语法上:使用{} 或者set()
collection = {1, 2, 3, 4}
print(type(collection))
# [推荐] 使用set()函数创建集合,最只要的作用就是去重
l = [1, 2, 3, 3]
t = (1, 2, 3, 3)
c1 = set(l)
c2 = set(l)
print(c1, type(c1))
print(c2, type(c2))
# 集合也是可变的数据类型,可以有增删改查等各种操作
面试题
怎么实现列表去重?[2]
列表去重的实现方法有很多,比如可以利用集合类型的特性,也可以通过循环遍历的方式进行去重
- 使用集合的特性去重
- 先使用set函数把需要的去重的列表转换为集合类型,就完成了去重,但此时结果的集合类型
- 如果西药列表类型,再使用list函数把数据类型转换回去即可
- 使用循环遍历的方法去去重
- 首先定义结果为一个空列表
- 然后循环遍历原列表的元素,如果元素不存在空列表中,则通过append方法把元素添加进去
l = [1, 2, 3, 3]
# 使用集合去重
print(list(set(l)))
# 使用循环遍历的方式去重
res = []
for i in l:
if i not in res:
res.append(i)
print(res)
5.字典
什么是字典
字典 dict 语法上用{} 来定义字典,数据之间用","分隔
每个数据都是键值对的形式,包含,键名(key)和键值(value)两个部分
# 什么是字典
# 字典 dict 语法上用{} 来定义字典,数据之间用","分隔
# 每个数据都是键值对的形式,包含,键名(key)和键值(value)两个部分
d = {"":"","":""}
t_info = {"name":"小吨","sex":"男","年龄":18,"地址":"广州","hobby":["看电影","追剧"]}
# 在字典中找到数据不是根据下标来找的,是根据key
print(t_info["name"])
print(t_info["hobby"])
# 字典的常见操作
# 增加,使用 变量名["key"] = value 时,如果key在字典中不存在,就会新增这个数量
t_info["score"] = 10
print(t_info)
# 删除 pop 和clear 方法
t_info.pop("age")
print(t_info)
t_info.clear()
print(t_info)
# 改 和新增一样没使用变量名["key"] = value ,如果key在字典中存在,就会修改这个数据
t_info["age"] = 28
print(t_info)
# 查询 某个key对应的value
print(t_info["name"]) # 不存在时就会报错
print(t_info.get("name")) #不存在时会返回空值
# 查询字典中的key列表,value列表,键值对的列表(以前返回列表,新版本python不再返回列表类型,但可以当做列表来使用后)
print(t_info.keys())
print(t_info.values())
print(t_info.items())
# 遍历
for key in t_info.keys():
print(key)
for value in t_info.values():
print(value)
for item in t_info.items():
print(item)
for key,value in t_info.items():
print(key,value)
面试题
1.python中有哪些数据类型,其中可变和不可变的数据类型有什么[3]
- 常见的数据类型有整数 int,浮点型float,布尔bool,字符串string,列表list,元组tuple,集合set,字典dictionary
- 其中可变类型有:列表,集合,字典
- 不可变数据类型有:数字,布尔,字符串,元组
2.python中的字典怎么遍历[2]
- 字典类型有很多内置方法可以使用,如:变量名.key() 获取键列表,变量名.values()获取值列表,变量名.items() 获取包含了键和值的元组的列表
- 有了这些可迭代的列表数据,就可以通过for循环遍历了
6.小结
容器是可以存储多个元素的一种数据类型,在python中包括了字符串,列表,元组,集合,字典
# 容器
# 容器是可以存储多个元素的一种数据类型,在python中包括了字符串,列表,元组,集合,字典
# 解包: 指将容器中的元素,分别赋值给多个变量的过程(容器类型的数据都支持解包)
# 列表解包
a, b, c = [1, 2, 3]
# 元组解包
a, b, c = (1, 2, 3)
# 换位
a, b = b, a
# 操作容器的内置函数
s = "123"
l = [1, 2, 3]
t = (1, 2, 3)
c = {1, 2, 3}
d = {"a": 1, "b": 2, "c": 3}
# len(),可以计算容器中的元素个数
print(len(s))
print(len(l))
print(len(t))
print(len(d))
# max() ,min()分别返回容器中元素的最大值或最小值
max(max(s)) # 除了字典之外的类型,直接返回值
max(min(s))
max(max(d)) # 字典类型,返回的是值所对应的key
max(min(d))
# del 和垃圾回收机制有关,del可以删除变量(的引用,引用次数计数器为0时,垃圾回收机制自动释放内存)
# 有两种用法:
# del + 空格
# del()
# 对与不可变数据类型,是可以删变量,不能删除元素
del l[0]
del l
del d["a"]
del d
# 集合比较特殊,集合虽然可变,但无序,不能使用下边,这笔能删除变量
# 多维列表/元组的访问
l = [[1, 2], [3, 4]]
print(l[0])
print(l[0][0])
print(l[1][1])
三、函数
1.函数介绍
函数的含义:可以被重复使用的代码块
- 函数的使用步骤:
- 1.定义函数,封装独立的功能,
- 定义函数的语法, def 是define的缩写
# 函数的含义:可以被重复使用的代码块
# 函数的使用步骤:
# 1.定义函数,封装独立的功能,
# 定义函数的语法, def 是define的缩写
# 定义过程,只定义,不执行
# def 函数():
# 代码
# 2.调用函数,使用封装好的功能
# 调用函数的语法,调用函数时会实际执行
# 函数名()
def fozu():
print("我是佛祖")
fozu()
# 查看函数的使用文档,使用help()
print(help(len))
2.函数的参数
def add_2num():
x = 1
y = 2
print(x + y)
add_2num()
# 这个函数只能把固定的两个数相加,怎样让这个函数适用于可变的两个数相加,答案就是参数
def add(x, y):
print(x + y)
add(2, 3)
# 参数的基本含义
# 形参:在定义时使用,用于在调用时接收变量值的形式参数(如,上述代码中的x和y)
# 实参:在调用时传入的实际参数值(如,上述代码中的2和3)
# 注意,在调用函数时,参数的位置和数量要保持一致
def add(x, y):
print(x + y)
# add(2, 3,2) 参数数量不一致会报错
# add(y = 1,x = 2) 如果位置需要变动,则需要以 变量名 = 参数值 的形式传参
# 参数的默认值(缺省值)
# 参数的默认值(缺省值),需要保证带有默认值的参数在末尾 def add(x=1,y)
def add(x, y=1):
print(x + y)
add(2, 2)
add(1)
# 参数[拓展]
# def len(*args,**kwargs):在这个定义中*args和**kwargs是什么?
# 用于参数不确定的情况
# *args 用于接收不确定的个数的参数,它将传入的参数打包成一个元组
# **kwargs 用于接收不确定个数的关键字参数(键 = 值) ,并打包成一个字典
# 说明
# args和kwargs 是可改变名字的,但不推荐
# 参数定义是有顺序的:必选参数,默认参数,可变参数
def demo(a, b, c=1, *args, **kwargs):
print(a)
print(b)
print(c)
print(args)
print(kwargs)
面试题
python的函数怎么传入可变参数或传参时的*
和* *
是什么意思[1]
- 设计函数时,如果不确定参数的个数,这个时候我们就需要传入可变参数
*
用于接收不确定格式的参数,并打包成一个元组,定义形参时通常用*args
**
用于接收不切定格式的关键词参数,并打包成一个字典,定义形参时通常用**kwargs
3.函数的返回值
# 什么是返回值
# 在程序开发中,有时候会希望一个函数执行结束后,
# 告诉调用者一个结果,这个结果就是返回值
# 在语法上,使用 return关键字来返回结果
def add(x, y):
print(x + y)
a = add(1, 2)
print(a) # 结果是none
def add(x, y):
return x + y
print(add(1, 2))
def demo():
print(1)
print(2)
return 0
print(3) #无法到达
print(demo())
4.函数的执行过程
# 函数中三大结构和嵌套调用的时候的执行过程
def demo1():
print(1)
print(2)
print(3)
demo1()
print(100)
def demo2():
print(1)
if True:
print(2)
print(3)
demo2()
print(100)
def demo3():
print(1)
for i in range(3):
print(2)
print(3)
demo3()
print(100)
5.局部变量和全局变量
局部变量和全部变量
-
从含义上说,局部变量定义在函数内部,全部变量定义在函数外部
-
对于作用域的角度来说,局部变量只能在函数内部使用,函数执行之后,变量会被回收,不同函数会有同名的局部变量
- 全局变量可以在全局使用(不论函数内外),但如果全局变量太多肯呢个导致不好维护
- 局部变量是在函数内部定义的变量,只能在函数内部使用
-
注意
- 局部变量和全局变量是相对的概念,局部是函数内部,全局是文件全局
未来会接触到更大的变量
- 局部变量和全局变量是相对的概念,局部是函数内部,全局是文件全局
6.匿名函数
匿名函数的定定义语法是lambda 参数:表达式
匿名函数中不能使用print 表达是就是返回值(无需写retur
四、面向对象编程OOP
1.基本理解
两种思想的区别
- 面向过程:强调的是步骤和过程,每一步都是自己亲自去实现,用怎么做的思想来解决
- 面向对象:找个对象,让对象来实现(专业的人干专业的时儿),用谁来做的思想来解决问题
- 面向对象是基于面向过程的
面向对象编程的优点
- 面向过程: 根据业务逻辑从上到下写代码(之前的函数式编程都是面向过程的)
- 面向对象:减少了重复代码,高度封装,易扩展
2.类和对象
面向对象编程的两个非常重要的概念:类和对象
2.1 类和对象的关系
类
类时抽象的
对象
对象是一个具体的事情
类和对象的关系
总结
- 类就是创建对象的模板,程序开发中,应现有类,再有对象
一个类可以有多个对象
2.1代码演示
2.3 类的构成
类是一群具有相同的特征或者行为的事务的统称
- 特征是属性
- 行为是方法
如何体现对象和对象之间的区别?
通过属性和方法来体现同一个类的不太用对象的区别
类由3个部分构成
- 类的名称:类名
- 类的属性:拥有的特征(名词)
- 类的方法:拥有的能力(动词)
注意
在程序开发过程中,只关注需求中涉及的属性和方法
2.4 类的设计
3.基础语法
3.1 定义类和创建对象
定义类
定义一个类,格式如下:
class 类名
属性
方法
定义一个类
class Hero:
hp = 1000
def info(self):
print("我是一个英雄")
说明
- 类名的命名规则按照"大驼峰命名法" 每个单词的首字母,单词和单词之间没有下划线
创建对象
创建对象的格式为:
对象名1 = 类()
对象名2 = 类()
如:创建Hero类的对象
class Hero:
hp = 1000
def info(self):
print("我是一个英雄")
an_qi_la = Hero()
print(an_qi_la.hp)
print(an_qi_la.info())
3.2 类中的方法
魔术方法
有些特殊方法,在python 代码执行时可以自动调用,这些方法被称为魔术方法
- 魔术方法名有两侧各有2个下划线
- 常用的魔术方法有
__init__
,__str__
,__del__
- 软件测试人员最常用的是
__init__
方法,用来完成属性的初始化,他在创建对象时默认执行
class Hero:
hp = 1000
def __init__(self):
self.name = None
self.sex = None
self.hp = 0
self.attack = 0
def info(self):
print("英雄")
anqila = Hero()
chengyaojin = Hero()
print(anqila.name)
print(anqila.sex)
print(anqila.hp)
print(anqila.attack)
类属性和实例属性
class 类名:
# 类属性,表示的是类的共性,如汽车,共性的内容有,轮子,座椅,有方向盘,有挡风玻璃
类属性名 = 值1
类属性名 = 值2
#实例属性,表示的是对象(实例) 的个性,轮子数量,轮毂样式,座椅数量,是不是敞篷
def __int__(self,参数1,参数2):
self.实例属性名1 = 参数1
self.实例属性名2 = 参数2
实例方法
特点
- 实例方法是每个对象化独有的
- 实例方法需要带
self
参数 - 主要用于处理实例属性,也可以访问其他实例方法
语法
def 实例方法名(self,参数):
pass
调用
对象.实例方法名(参数)
类方法
特点
- 类方法是针对类定义对的方法
- 类方法需带
cls
参数 - 主要用于处理类属性,也可以访问其他类方法
语法
@classmethod
def 类方法名(cls):
pass
类方法需要用装饰器 @classmethod来标识,告诉python解释器这是一个类方法
调用
类名.类方法名()
静态方法
特点
- 如果想在类中封装一个方法,既不需要访问**实例属性和类属性*,也不需要访问实例方法和类方法*
- 这个时候,就可以把这个方法封装成一个静态方法
语法
@staticmethod
def 静态方法名():
pass
静态方法需要用装饰器
@staticmethod
来标识,告诉python解释器这是一个静态方法
调用
类名.静态方法名()
小结
- 实例方法方法内部需要访问
self.属性名
的实例属性,也可以访问类名.属性
的类属性 - 类方法方法内部只需要访问类属性
- 静态方法,方法内部不需要访问任何属性
4.面向对象三大特征
4.1封装
说明
- 封装是面向对象编程的第一步,将属性和方法,封装到一个类中
- 对封装的进阶理解就是属性的私有化
私有化
- 属性和方法都可以私有化,不让外部直接访问,可以提高数据的安全性
- 私有化方法,在属性或者方法名前面加双下划线
__
- 私有化,也可以考虑设置入口,供外部访问
- 方法1:对私有化的属性设置get和set方法,想外部访问时,调用get和set 方法即可
- 方法2:python内置了一些访问方法
4.2 继承
什么是继承
class A:
money = 10
def study(self):
print("学习好")
class B(A):
pass
print(A.money)
print(B.money)
b = B()
b.study()
说明:
在程序中,继承描述的是多个类之间的所属关系
继承就是子类拥有父类的所有属性和方法
继承的好处
相同的代码不需要重复编写
此时如果需要定义一个eat方法,只需要定义在父类中,则其他子类会继承这个方法
单继承
语法
class 子类名(父类名)
pass
说明:子类只需要封装自己特有的属性和方法
如果子类从父类继承来的方法不好用,怎么办
解决方案就是重写
class A:
money = 10
def study(self):
print("学习好")
class B(A):
def study(self):
print("学习更好")
a = A()
b = B()
a.study()
b.study()
class B(A):
pass
print(B._A__money) #有办法能够访问父类中的私有属性或方法,但一样不大
多继承
现实中的多继承
孩子会继承父母的特性
程序中的多继承
子类可以拥有多个父类,并具有所有父类的属性和方法
语法
class 子类名(父类名1, 父类名2)
pass
实例
class A:
def eat(self):
pass
class B:
def sleep(self):
pass
class C(A, B):
pass
c = C()
c.eat()
c.sleep()
多继承使用时的注意事项
如果不同的父类存在同名的属性或方法时,子类在调用时,调用的是哪个父类中的队形属性和方法呢?
开发时,应尽量避免发生这种容易混淆的情况
4.3 多态
概念
多态就是不同对象调用同名方法,产生不同的执行结果
- 以继承和重写父类方法为前提
class Animal:
def speak(self):
print("嚎叫")
class Dog(Animal):
def speak(self):
print("汪汪")
class Cat(Animal):
def speak(self):
print("喵喵")
animal = Animal()
dog = Dog()
cat = Cat()
def speak(x):
x.speak()
speak(animal)
speak(dog)
speak(cat)
作用
可以增加代码的灵活度
五、文件操作
1.文件操作的基本介绍
文件的认知
- 计算机的文件,本质上就是长期存储设备上的一段数据(长期存储设备包括光盘/u盘/硬盘,但不包括内存)
- 在计算机中,文件是以二进制的方式存储在硬盘上的
- 文本文件,本质上依然是二进制文件(字符编码),只不过是查看的时候进行了解码,让二进制重新转为自然语言
文件的基本操作
- 基本操作包括的范围,打开文件/读写文件/关闭文件
- 读写的理解
- 读,将文件按内容读入内存,可以理解为查看文件内容
- 写, 将内存中的内容写入文件,可以理解为增/删/改文件内容并保存
- 打开文件open和关闭文件close
- open(文件名,访问模式) 用于打开一个文件,返回这个文件按对象,访问模式如下
- r 只读的方式打开(默认访问模式)
- w 打开文件用于写入,会覆盖写入,如文件不存在则创建
- a 打开文件用于写入,会追加写入,如文件不存在则创建
- b 二进制模式,使用时结合其他模式,
rb,wb,ab
- 使用
read(n)
方法可以从文件读取n个字符的数据
说明: 其实文件操作存在一个叫做文件指针的概念,类似光标,他标记操作
注意
- 编码问题,如:文件内容包含汉字时,读文件时容易出现编码错误
- 文件内容较多时,可以逐行读取
f = open("test.txt", "r", encoding="utf-8")
for readline in f.readlines():
print(readline, end="") # 以什么结尾
f.close()
# 如果总是忘记close 怎么办[拓展]
# with语句可以优雅的处理资源管理问题
with open("test.txt", "r", encoding="utf-8") as f:
print(f.read())
# 其实`with open("test.txt", "r", encoding="utf-8") as f:`
# 相当于 `f = open("test.txt", "r", encoding="utf-8")` 加上f.close()
2.文件按的相关操作
- 除了对文件的读写等之外,对文件还有重命名,删除文件以及对文件夹的操作
- 这些功能都在python的OS模块中
- 学习相关操作之前,需要先了解模块和包
- 什么是模块 什么是包
- 把功能相关的函数和类,放在一个独立的py文件中,就形成了一个模块
- 把功能相关的模块整理放到一个独立的文件夹中,就形成了一个包
- 一个模块就是一个py文件,一个包就是一个包含了
__init__.py
文件的文件
# 如何导入封装好的模块,包
# 从结构上认清我们要导入的内容
# 项目1
# 包1
# 模块1
# 类1,方法1,函数1,变量1
# 模块2
# 包2
# 使用import 来导入模块和模块中定义的类/方法/函数/变量
import math
print(math.pi) # π
print(math.sqrt(2)) # 平方根函数
# 如果想直接使用模块中的成员,不想以模块,成员的方式来使用
# from math import pi,sqrt
from math import *
print(pi)
print(sqrt(4))
# 给导入的对象取一个别名
from math import pi as PI
print(PI) # 此时只能通过别名使用
import time as t
t.sleep(3)
语法小结
import 模块名
from 模块名 import 成员名
from 包名.模块名 import 成员名
# os模块的文件相关操作
import os
# 文件重命名
os.rename("test.txt", "test1.txt")
# 删除文件
os.remove("test1.txt")
# 获取当前目录
print(os.getcwd())
# 删除目录
os.rmdir()
六、异常
概念
程序在运行时,如果python解释器遇到了一个错误,会停止程序的运行,并提示错误信息,这些错误信息就是异常
提示信息的动作就是抛出异常(也叫提示信息或报错)
- 正常的认识异常
- 异常并不可怕,软件是给用户群体使用的,所谓异常,是很普通的用户场景
# 捕获异常 - 处理异常
# 当我们不确定某些能不能执行成功时,可以使用以下语法来避免程序的停止运行
# try:
# 尝试执行的代码
# except:
# 出错的处理代码
try:
open("111.txt")
except:
print(1)
print(2)
# 如果希望展示异常的信息,如何处理
try:
open("111.txt")
except FileNotFoundError as e:
print(e)
print(1)
print(2)
try:
# 让用户输入密码
except 密码为空的错误类型 as e:
print(e)
except 密码错误的异常类型 as e:
print(e)
except BaseException as e:
print(e)
else:
# 没有异常才会执行的代码
finally:
# 无论是否有异常,都会执行
# 实践
try:
num = int(input("请输入一个整数:"))
result = 8 / num
print(result)
except ZeroDivisionError as e:
print(e)
print("0不能做除数")
except ValueError as e:
print(e)
print("需要输入整数")
except BaseException as e:
print(e)
print("未知错误")
else:
print("正常执行")
finally:
print("怎样都会走")
手动抛出异常
vx_list = ["张三", "李四", "王五", "情敌"]
for vx in vx_list:
print(vx)
if vx == "情敌":
raise Exception("我很生气")
# 自定义异常类
class VeryAngryException(BaseException):
pass
vx_list = ["张三", "李四", "王五", "情敌"]
for vx in vx_list:
print(vx)
if vx == "情敌":
raise VeryAngryException("我很生气")
面试题
如何捕捉一个异常[1]
使用try…catch…语法来捕捉异常,如果后续有需要执行的代码可以放在finally代码块中
七、拓展
1.深拷贝和浅拷贝
python赋值原理
- 变量并不直接存储翠香,而是存储对象的引用(即对象在内存中的地址)
# 将一个变量赋值给另一个变量时复制的是什么,二者实际上指向的是同一个对象
# 问题:这意味着如果修改对象的值,两者都会受到影响
# 为了避免变量之间共享地址带来的问题,就有了浅拷贝,需要复制对象的值
# 浅拷贝
import copy
# 对于不可变的数据类型
a = 1
b = copy.copy(a)
print("a", id(a))
print("b", id(b))
# 对于可变数据类型复制的是值
l1 = [1, 2, 3]
l2 = copy.copy(l1)
print(id(l2))
print(id(l1))
l1[0] = 4
print(l1)
print(l2)
# 对于较复杂的数据,可变数据类型在内外层表现不同
l3 = [1, [2, 3]]
l4 = copy.copy(l3)
l3[0] = 4
l3[1][0] = 3
print(l3)
print(l4)
# 浅拷贝对对于不可变的数据类型,复制"引用"
# 浅拷贝对于可变数据
# 可变数据类型在外层时,复制的是"值"
# 可变数据类型在外层时,复制的是"引用"
# 深拷贝
l3 = [1, [2, 3]]
l4 = copy.deepcopy(l3)
print(id(l3))
print(id(l4))
print(id(l3[1]))
print(id(l4[1]))
# 深拷贝对于不可变数据类型复制的是引用
# 对于可变的数据类型复制的都是值
面试题
浅拷贝和深拷贝的区别[3]
- 浅拷贝和深拷贝的出现源于变量赋值只赋予变量对数据对象的引用,当多个和变量引用同一个数据时,数据一旦修改,这些变量都会受影响
- 浅拷贝和深拷贝在实现上都用到了copy模块,浅拷贝用的copy()函数,浅拷贝用的是deepcopy()函数
- 对与不可变类型的数据处理,浅拷贝和深拷贝都是一样的,都是复制对数据的"引用",病会不会开辟新的地址
- 对与可变类型的处理
- 浅拷贝的处理方式是,外层的数据复制"值", 内层的数据只复制引用
- 深拷贝的处理方式是,不论内外层都开辟新的内存地址,把值复制过来
2.冒泡排序
什么是冒泡排序
冒泡排序是经典的排序算法之一
# 基本思路:从小到大排序,冒泡结果是大数冒上来
def bubble_sort(x):
for i in range(1, len(x)):
for j in range(len(x) - i):
if x[j] > x[j + 1]:
x[j], x[j + 1] = x[j + 1], x[j]
return x
l = [12,3,23,54,1,2,4]
print("待排序:", l)
print("待排序:", bubble_sort(l))
面试题
用python如何实现冒泡排序[3]
冒泡排序的核心是两层嵌套循环来实现
- 外层控制循环的论次,每一轮找出当前最符合的元素,并冒泡
- 内存控制每个元素两两比较的次数,以及元素位置的交换