本篇文章内容基于
Python 3.10.6
版本解释器
_
注释核心作用:
单行注释:Python中单行注释以 #
开头
# 这是一个单行注释
多行注释:多行注释可以用多个 #
号,还有 '''
和 """
# 这是第一行注释
# 这是第二行注释
'''
这是多行注释
第一行
第二行
'''
"""
这是多行注释
第一行
第二行
"""
列表和元组可以存放Python中任意的数据类型
不可变数据类型
:Number(数字)、String(字符串)、Tuple(元组);可变数据类型
:List(列表)、Dictionary(字典)、Set(集合)容器类型
:字符串,列表,元组,字典,集合数字类型
:整型,浮点型,布尔类型# 整型(int)
number = 666
print(type(number)) # <class 'int'>
# 浮点型(float)
number = 3.14
print(type(number)) # <class 'float'>
布尔类型特点:
True
和 False
# bool(布尔类型)
bool1 = True
bool2 = False
print(type(bool1)) # <class 'bool'>
print(type(bool2)) # <class 'bool'>
注意
:在Python中,所有非零的数字和非空的字符串、列表、元组等数据类型都被视为 True,只有 0、空字符串、空列表、空元组等被视为 False。因此,在进行布尔类型转换时,需要注意数据类型的真假性
Python中的字符串用单引号 ''
或双引号 ""
或三引号 ''''''
括起来
# str(字符串)
str1 = '666'
str2 = "张三"
str3 = '''李四'''
print(type(str1)) # <class 'str'>
print(type(str2)) # <class 'str'>
print(type(str3)) # <class 'str'>
列表:[]
表示列表。列表当中可以存放Python中任意的数据类型
# list(列表)
list1 = [1, "张三", 3.14, True]
print(type(list1)) # <class 'list'>
元组:元组写在小括号()
里,元素之间用逗号隔开。元组与列表类似,不同之处在于元组的元素不能修改
元组的括号可以省略
# tuple(元组)
tuple1 = (1, 2, "张三", 3.14, [1, 3])
print(type(tuple1)) # <class 'tuple'>
tuple2 = 1, 2, "张三", 3.14, [1, 3]
print(type(tuple2)) # <class 'tuple'>
集合是一种无序、可变的数据类型,用于存储唯一的元素
集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作
特性:默认去重(集合里面不存在重复的数据)
集合无法存在列表和字典
# set(集合)
set1 = {1, 3.14, "张三", True, (1, 4)}
print(type(set1)) # <class 'set'>
注意
:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取
字典是一种映射类型,字典用 { }
标识,它是一个无序的 键(key) : 值(value) 的集合
键(key)必须使用不可变类型
在同一个字典中,键(key)必须是唯一的
# dict(字典)
dict1 = {"name": "张三", "age": 18, "sex": "男"}
print(type(dict1)) # <class 'dict'>
接收用户输入的数据可以调用内建函数:input()
实现数据获取
一般输入的数据会保存到变量中,默认情况获取的所有用户输入的内容都是字符串
当程序执行的时候遇到input
内建函数,程序会挂起(如果不输入回车)那么代码不会继续往下执行
username = input("请输入用户名")
password = input("请输入密码")
print(f"您输入的用户名是:{username},密码是:{password}")
方式一(不常用,了解即可):
使用占位符号 %
实现格式化输出
需要根据变量值的不同数据类型进行不同参数的占位
%s
占位%d
占位%f
占位name = "张三"
age = 18
height = 1.98
print("我的名字是:%s" % name) # 格式化输出字符串
print("我的年龄是:%d" % age) # 格式化输出整数
# 浮点数格式化输出时默认保留6位小数
# 如果需要保留指定的小数位,需要进行修改,那么在f前面加上.2f(保留2为小数)
print("我的身高是:%f米" % height) # 格式化输出浮点数
print("我的身高是:%.2f米" % height)
多个格式化输出的语法格式
name = "张三"
age = 18
height = 1.98
# 多个格式化输出的语法格式
print("我的名字是:%s,我的年龄是:%d,我的身高是:%.2f米" % (name, age, height))
方式二(不常用,了解即可):
{}
进行格式化输出name = "张三"
age = 18
height = 1.98
# 简写模式
print(f"我的名字是:{name},我的年龄是:{age},我的身高是:{height}米")
print(F"我的名字是:{name},我的年龄是:{age},我的身高是:{height}米")
# 完整模式
print("我的名字是:{},我的年龄是:{},我的身高是:{}米".format(name, age, height))
数据类型转换的内建函数
函数 | 作用 |
---|---|
int() | 转换为整数数据类型 |
float() | 转换为浮点数数据类型 |
str() | 转换为字符串数据类型 |
eval() | 用来计算在字符串中的有效Python表达式,并返回一个对象(将字符串原生的数据类型转化为原本的类型) |
int():转换为整数数据类型
str1 = "666"
print(type(str1)) # <class 'str'>
# int()函数——将字符串的原生整数类型进行转化
print(type(int(str1))) # <class 'int'>
float():转换为浮点数数据类型
str2 = "666"
# float()函数——将字符串的原生浮点类型进行转化
print(type(str2)) # <class 'str'>
print(type(float(str2))) # <class 'float'>
str():转换为字符串数据类型(万物皆可字符串:任何数据类型都可以加上引号变成字符串)
number = 666
print(type(number)) # <class 'int'>
# str()函数——将原生的数据类型转化为字符串
print(type(str(number))) # <class 'str'>
eval():将字符串原生的数据类型转化为原本的类型
str3 = "[1,2,3]"
print(type(str3)) # <class 'str'>
print(type(eval(str3))) # <class 'list'>
str4 = "(1,2,3)"
print(type(str4)) # <class 'str'>
print(type(eval(str4))) # <class 'tuple'>
str5 = "{1,2,3}"
print(type(str5)) # <class 'str'>
print(type(eval(str5))) # <class 'set'>
str6 = '{"name": "张三", "age": "18"}'
print(type(str6)) # <class 'str'>
print(type(eval(str6))) # <class 'dict'>
str7 = "666"
print(type(str7)) # <class 'str'>
print(type(eval(str7))) # <class 'int'>
以下假设变量 a=5,变量 b=2
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | a + b 输出结果 7 |
- | 减 | a - b 输出结果 3 |
* | 乘 | a * b 输出结果 10 |
/ | 除 | a / b 输出结果 2.5 |
% | 取模(返回除法的余数) | a % b 输出结果 1 |
** | 幂 | a ** b 输出结果 25 |
// | 取整除 | a // b 输出结果 2 |
以下假设变量 a=5,变量 b=2
运算符 | 描述 | 实例 |
---|---|---|
== | 等于 | (a == b) 返回 False |
!= | 不等于 | (a != b) 返回 True |
> | 大于 | (a > b) 返回 True |
< | 小于 | (a < b) 返回 False |
>= | 大于等于 | (a >= b) 返回 True |
<= | 小于等于 | (a <= b) 返回 False |
注意
:比较运算符返回的结果类型是布尔值。要么是True
,要么是False
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符 | |
+= | 加法赋值运算符 | |
-= | 减法赋值运算符 | |
*= | 乘法赋值运算符 | |
/= | 除法赋值运算符 | |
%= | 取模赋值运算符 | |
**= | 幂赋值运算符 | |
//= | 取整除赋值运算符 | |
:= | 海象运算符 |
and
:两个条件必须同时满足最终结果为真or
:两个条件只要一个为真,最终结果为真not
:取反,假变真,真变假运算符 | 描述 | 实例 |
---|---|---|
and | 布尔"与" | |
or | 布尔"或" | |
not | 布尔"非" |
运算符 | 描述 | 实例 |
---|---|---|
& | 与运算符 | |
| | 或运算符 | |
^ | 异或运算符 | |
~ | 取反运算符 | |
<< | 左移动运算符 | |
>> | 右移动运算符 |
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值返回 True,否则返回 False。 | |
not in | 如果在指定的序列中没有找到值返回 True,否则返回 False。 |
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用自一个对象 | |
is not | is not 是判断两个标识符是不是引用自不同对象 |
以下表格列出了从最高到最低优先级的所有运算符, 相同单元格内的运算符具有相同优先级。 运算符均指二元运算,除非特别指出。 相同单元格内的运算符从左至右分组(除了幂运算是从右至左分组):
运算符 | 描述 |
---|---|
(expressions…), [expressions…], {key: value…}, {expressions…} | 圆括号的表达式 |
x[index], x[index:index], x(arguments…), x.attribute | 读取,切片,调用,属性引用 |
await x | await 表达式 |
** | 乘方(指数) |
+x, -x, ~x | 正,负,按位非 NOT |
*, @, /, //, % | 乘,矩阵乘,除,整除,取余 |
+, - | 加和减 |
<<, >> | 移位 |
& | 按位与 AND |
^ | 按位异或 XOR |
| | 按位或 OR |
in,not in, is,is not, <, <=, >, >=, !=, == | 比较运算,包括成员检测和标识号检测 |
not x | 逻辑非 NOT |
and | 逻辑与 AND |
or | 逻辑或 OR |
if – else | 条件表达式 |
lambda | lambda 表达式 |
:= | 赋值表达式 |
字符串的索引及切片
索引
从左到右默认从0
开始
从右到左默认从-1
开始
str1 = "今天又是充满希望的的一天"
# 可以通过字符串的索引值取字符的实际值
print(str1[1]) # 天
print(str1[-2]) # 一
切片
切片是指对被操作的字符串对象的内容取一部分值,列表,元组都是支持切片操作
切片的语法格式:[起始:结束:步长]
str1 = "今天又是充满希望的的一天"
# 只写开始,不写结束:默认到最后(默认包含开始索引值的内容)
print(str1[6:]) # 希望的的一天
# 有开始也有结束:包含开始的索引值,不包含结束的索引值
# 切片的操作是一个左闭右开的区间
print(str1[6:9]) # 希望的
# 只写结束,不写开始:默认从0(索引)开始
print(str1[:9]) # 今天又是充满希望的
# 开始结束都不写
print(str1[:]) # 今天又是充满希望的的一天
# 对字符串切片操作是可以通过负数索引进行切片操作
print(str1[6:-4]) # 希望
# 当开始和结束的索引值没有交集的时候会取不到实际值
print(str1[-1:6])
# 步长,不写开始不写结束,步长为2
print(str1[::2]) # 今又充希的一
查找字符串中具体某个元素
find()
str1 = "今天又是充满希望的的一天"
# 如果该字符串有该元素那么返回元素的索引值
print(str1.find("希")) # 6
# 如果该字符串没有该元素那么返回的索引值是-1(表示没有该元素)
print(str1.find("快")) # -1
index()
str1 = "今天又是充满希望的的一天"
# 如果该字符串有该元素那么返回元素的索引值
print(str1.index("希")) # 6
# 如果该字符串没有该元素那么程序会报错
print(str1.index("快")) # 报错
count()
统计元素在整个字符串当中出现的次数
str1 = "今天又是充满希望的的一天"
# 会返回该元素在整个字符串当中出现的次数
print(str1.count("天")) # 2
replace()
替换字符串中的元素值
str1 = "今天又是充满希望的的一天"
# 替换字符串中的元素值
print(str1.replace("今", "明"))
使用split()
对字符串进行切片
str1 = "今天又是充满希望的的一天"
# split对字符串进行切片的方法,返回的数据类型是列表,可以设置参数切几次,切好的数据是字符串类型
print(str1.split("天", 1)) # ['今', '又是充满希望的的一', '']
capitalize()
首字母大写,其余全部小写
# capitalize()将整个字符串第一个元素(不管是大小写全部做大写处理)之后的内容里面的所有大写字母转化成小写字母
str2 = "abcdABCD"
print(str2.capitalize()) # Abcdabcd
title()
根据字符串的空格将每个空格之后的首字母大写
str3 = "abcd zxcv qwer"
# 根据字符串的空格将每个空格之后的首字母大写(前提是空着之后是字母)
print(str3.title()) # Abcd Zxcv Qwer
startswith()
检测字符串是否以指定元素开头
str4 = "good good stady day day up"
# 检测字符串是否以指定元素开头
print(str4.startswith("g")) # True
print(str4.startswith("b")) # False
print(str4.startswith("good")) # True
lower()
将整个字符串当中的所有大写字母转化为小写
str5 = "I Love You"
# 将整个字符串当中的所有大写字母转化为小写
print(str5.lower()) # i love you
去除自字符串前面或后面的空格元素
lstrip()
rstrip()
strip()
# 去除自字符串前面或后面的空格元素
str6 = " I Love You "
# 去除后面空格元素
print(str6.rstrip()) # " I Love You"
# 去除前面空格元素
print(str6.lstrip()) # "I Love You "
# 去除前后空格元素
print(str6.strip()) # I Love You
isdigit()
判断字符串所有的元素是否由纯数字组成
str7 = "12345qwer"
# 判断字符串所有的元素是否由纯数字组成
print(str7.isdigit()) # False
使用固定的字符隔开字符串当中的所有元素
str8 = "abcd1234"
# 字符串的拼接操作:使用固定的字符隔开字符串当中的所有元素
print("*".join(str8)) # a*b*c*d*1*2*3*4
print("-".join(str8)) # a-b-c-d-1-2-3-4
print("0".join(str8)) # a0b0c0d01020304
列表中增加数据
第一种方式:append()
添加数据(默认是追加到列表末尾)
name_list = ["宝总", "爷叔", "小江西", "蔡司令"]
# 第一种方式:append()添加数据(后默认是追加到列表末尾)
name_list.append("汪小姐")
print(name_list) # ['宝总', '爷叔', '小江西', '蔡司令', '汪小姐']
第二种方式:append()
插入数据
name_list = ["宝总", "爷叔", "小江西", "蔡司令"]
# 第二种方式:append()插入数据
# 插入到元素下标为1的位置
name_list.insert(1, "李李")
print(name_list) # ['宝总', '李李', '爷叔', '小江西', '蔡司令']
第三种方式:extend()
将容器类型数据拆分开来再添加
name_list = ["宝总", "爷叔", "小江西", "蔡司令"]
# 第三种方式:extend()将容器类型数据拆分开来再添加
name_list.extend(["李李", "汪小姐"])
print(name_list) # ['宝总', '爷叔', '小江西', '蔡司令', '李李', '汪小姐']
列表中查询数据
列表可以通过索引取值(元素),也支持切片操作
list1 = ["a", "b", "c", "d", "e"]
print(list1[3]) # d
print(list1[1:4]) # ['b', 'c', 'd']
print(list1[::2]) # ['a', 'c', 'e']
如果列表的切片步长为-1那么可以将列表反转
list1 = ["a", "b", "c", "d", "e"]
print(list1[::-1]) # ['e', 'd', 'c', 'b', 'a']
列表中修改数据
通过索引修改数据:先获取具体要修改的索引值内容然后再赋值
list1 = ["a", "b", "c", "d", "e"]
# 通过索引修改数据:先获取具体要修改的索引值内容然后再赋值
list1[1] = "张三"
print(list1) # ['a', '张三', 'c', 'd', 'e']
列表中删除数据(当数据被删除的时候,因为列表是有序的序列,那么现存的数据索引会发生变化)
使用pop()
方法删除
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
# 使用pop()方法删除
name_list1.pop(2)
print(name_list1) # ['宝总', '爷叔', '蔡司令', '李李', '汪小姐']
使用remove()
方法删除
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
# 使用remove()方法删除
name_list1.remove("蔡司令")
print(name_list1) # ['宝总', '爷叔', '小江西', '李李', '汪小姐']
使用clear()
清除列表中所有的数据
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
# 使用clear()清除列表中所有的数据
name_list1.clear()
print(name_list1) # []
使用特殊关键字del
删除具体某个数据(通过索引获取)
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
# 使用特殊关键字del删除具体某个数据(通过索引获取)
del name_list1[2]
print(name_list1) # ['宝总', '爷叔', '蔡司令', '李李', '汪小姐']
reverse()
列表反转
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
# 列表反转
name_list1.reverse()
print(name_list1) # ['汪小姐', '李李', '蔡司令', '小江西', '爷叔', '宝总']
count()
统计元素在整个列表当中出现的次数
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
print(name_list1.count("爷叔")) # 1
index()
查询列表当中某个元素的索引值
name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
print(name_list1.index("宝总")) # 0
sort()
将列表中的数据进行排序
从小到大排序
list2 = [3, 5, 1, 7, 16, 12, 20, 2]
# sort()将列表中的数据进行排序(从小到大排序)
list2.sort()
print(list2) # [1, 2, 3, 5, 7, 12, 16, 20]
从大到小排序
list2 = [3, 5, 1, 7, 16, 12, 20, 2]
# 从大到小进行排序
list2.sort(reverse=True)
print(list2) # [20, 16, 12, 7, 5, 3, 2, 1]
元组和列表是一样,都是有序的容器类型的数据,但是区别是元组的数据不能被修改,当数据一旦被定义那么就是固定值,元组只支持查询数据功能。
t1 = (1, 2, 3, 4, 5, 6)
# 可以通过索引取值
print(t1[3])
# 可以支持切片操作
print(t1[0:2])
# index,count
print(t1.count(3)) # 1
print(t1.index(2)) # 1
字典的特性:
字典的快速创建键值对
dict2 = dict(a=1, b=2, c=3)
print(dict2) # {'a': 1, 'b': 2, 'c': 3}
字典中查询数据
通过字典的键取值
dict1 = {"name": "张三", "age": 18, "sex": "男"}
# 字典取值:通过字典的键取值
print(dict1["name"]) # 张三
查看字典中所有的键
dict1 = {"name": "张三", "age": 18, "sex": "男"}
# 查看字典中所有的键
print(dict1.keys()) # dict_keys(['name', 'age', 'sex'])
查看指点中所有的值
dict1 = {"name": "张三", "age": 18, "sex": "男"}
# 查看指点中所有的值
print(dict1.values()) # dict_values(['张三', 18, '男'])
获取字典的所有键值对
dict1 = {"name": "张三", "age": 18, "sex": "男"}
# 获取字典的所有键值对
print(dict1.items()) # dict_items([('name', '张三'), ('age', 18), ('sex', '男')])
字典中增加数据
字典中的键一定是唯一的,值随意,当字典中有当前的键值对的时候,那么会通过键覆盖值
update()
给字典添加数据:支持单个键值对添加和多个键值对添加
dict3 = {'a': 1, 'b': 2, 'c': 3}
dict3.update({"d": 4, "e": 5})
print(dict3) # {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
setdefault()
添加字典中没有键的键值对数据
dict3 = {'a': 1, 'b': 2, 'c': 3}
dict3.setdefault("d", 4)
print(dict3)
字典中修改数据
通过字典的键去修改值
dict4 = {'a': 1, 'b': 2, 'c': 3}
dict4["a"] = 11
print(dict4) # {'a': 11, 'b': 2, 'c': 3}
字典中删除数据
del
关键字删除值(键获取,最终是将整个键值对全部删除)dict5 = {'a': 1, 'b': 2, 'c': 3}
del dict5["a"]
print(dict5) # {'b': 2, 'c': 3}
pop()
方法删除,通过键删除键值对dict5 = {'a': 1, 'b': 2, 'c': 3}
dict5.pop("a")
print(dict5) # {'b': 2, 'c': 3}
clear()
清空字典dict5 = {'a': 1, 'b': 2, 'c': 3}
dict5.clear()
print(dict5) # {}
集合的特性就是去重,集合里面不存在重复的数据,集合的数据(元素)都是唯一的
集合默认是无序的序列,不能进行索引取值和切片,因为集合中的元素是没有前后顺序的
集合中新增数据
set1 = {1, 2, 3, 4, 5}
# 集合可以添加数据,前提是集合中没有这个数据才能添加成功
set1.add(6)
print(set1) # {1, 2, 3, 4, 5, 6}
集合中删除数据
set2 = {"a", 1, "张三", 2}
set2.remove("a")
print(set2) # {1, 2, '张三'}
列表转元组
list1 = [1, 2, 3, 3, 4, 5, 6, 7]
# 列表转元组
tuple1 = tuple(list1)
print(tuple1) # (1, 2, 3, 3, 4, 5, 6, 7)
print(type(tuple1)) # <class 'tuple'>
元组转集合
tuple2 = (1, 2, 3, 3, 4, 5, 6, 7)
# 元组转集合
set1 = set(tuple2)
print(set1) # {1, 2, 3, 4, 5, 6, 7}
print(type(set1)) # <class 'set'>
列表转集合
list1 = [1, 2, 3, 3, 4, 5, 6, 7]
# 列表转集合
set2 = set(list1)
print(set2) # {1, 2, 3, 4, 5, 6, 7}
print(type(set2)) # <class 'set'>
如果列表和元组中的数据需要去重,那么可以直接转集合,再转回去
# 如果列表和元组中的数据需要去重,那么可以直接转集合,再转回去
# 集合变元组或者列表:去重案例
list1 = [1, 2, 3, 3, 4, 5, 6, 7]
print(list(set(list1))) # [1, 2, 3, 4, 5, 6, 7]
print(tuple(set(list1))) # (1, 2, 3, 4, 5, 6, 7)
可变数据类型:当数据类型变量的值发生变化,内存地址值不变,那么该数据类型就是可变数据类型(内存地址值是唯一的)
不可变数据类型:当数据类型变量的值发生变化,内存地址值改变,那么该数据类型就是不可变数据类型
注意
:字典的键一定是不可变的数据类型。字典,列表,集合不能当做字典的键。字典的值没有数据类型的要求
注意
:集合中的元素只能放不可变的数据类型
浅拷贝:针对不可变的数据类型进行拷贝
浅拷贝:复制一份数据,重新分配一块内存空间(引用原来数据值的内存地址),新的数据里面的值指向还是原来值的内存地址
引用:不同的变量里面保存的值是一样的时候,会在内存里面引用同一个内存地址值
浅拷贝可以通过赋值 = 来实现
浅拷贝:copy可以复制一份数据,但是引用地址还是原来数据的内存地址
浅拷贝只针对不可变的数据类型有效:数字类型,字符串,元组
针对不可变的数据类型,如果原数据被删除,只要内存地址在,那么被拷贝数据照常使用
# 从指定的模块中导入指定的对象或函数,并将其命名为copy,之后就可以直接使用copy来调用该对象(第一个copy代表模块名,第二个copy代表模块中的对象或者函数名)
from copy import copy
str1 = "今天又是充满希望的一天!"
str2 = copy(str1)
print(id(str1))
print(id(str2))
案例:使用浅拷贝对可变数据类型进行拷贝
from copy import copy
list1 = ["张三"]
list2 = []
copy_list1 = copy(list2)
new_list1 = list2.extend(["李四", list1])
copy_list2 = copy(list2)
new_list2 = list2.extend(["李四", list1])
list1.append("王五")
print(list2) # ['李四', ['张三', '王五'], '李四', ['张三', '王五']]
print(copy_list1) # []
print(copy_list2) # ['李四', ['张三', '王五']]
注意
:可变的数据类型不建议使用浅拷贝,因为当拷贝完之后,对原来数据进行修改,所有被拷贝好的数据也会发生变化
深拷贝:针对可变的数据类型进行拷贝
深拷贝可以对可变的数据类型进行拷贝,拷贝好的数据发生变化都是相互独立的不会受到影响
from copy import deepcopy
list1 = ["张三"]
list2 = []
copy_list1 = deepcopy(list2)
new_list1 = list2.extend(["李四", list1])
copy_list2 = deepcopy(list2)
new_list2 = list2.extend(["李四", list1])
list1.append("王五")
print(list2) # ['李四', ['张三', '王五'], '李四', ['张三', '王五']]
print(copy_list1) # []
print(copy_list2) # ['李四', ['张三']]
注意
:可变和不可变的数据类型都可以进行深拷贝,不可变的数据类型不建议使用深拷贝,比较占用内存
1
使用浅拷贝拷贝可变的数据类型:源数据变化,被拷贝的数据也会变化
使用深拷贝拷贝可变的数据类型:源数据变化,被拷贝的数据不会变化
不可变的数据类型建议使用浅拷贝
可变的数据类型一定要使用深拷贝
不可变的数据类型使用方法操作完之后都是全新的数据,跟原来数据没有任何关系
可变的数据类型使用方法操作完之后都是对原来的数据进行修改,跟原来的数据有密切的关系
数据的内容发生变化,都是在同一块内存地址值,内存地址值不会发生任何变化
if分支语句
age = int(input("请输入您的年龄"))
if age >= 18:
print("您已成年,可以上网")
else:
print("您未成年,禁止上网")
分支语句-多条件判断
score = int(input("请输入成绩1-100"))
if score >= 90:
print("优秀")
elif score >= 80 and score < 90:
print("良好")
elif score >= 60 and score < 80:
print("及格")
else:
print("不及格")
if语句后面跟随的判断条件是通过布尔值判断的
Python中所有的数据类型,都可以转化为布尔值
if -1:
print("真的")
else:
print("假的")
在Python3.10环境更新之后新增了2个匹配的关键字match
,case
可以用来代替多种情况
name = input("请输入您的姓氏")
match name:
case "王":
print("排名第一")
case "张":
print("排名第二")
case "李":
print("排名第三")
case "刘":
print("排名第四")
简写的if语句:比较两个数的大小
import random
a = int(input("请输入一个1-10的整数"))
b = random.randint(1,10)
print(f"您输入的数字是:{a},随机生成的数字是:{b},两个数最大的值是:{a if a > b else b}")
for循环一般情况会结合range()
内建函数一起使用构建循环体
# range(1,100)左闭右开天,1-99不包含100
for i in range(1, 100):
print(i)
# range(10)循环10次,从0开始9结束
for i in range(10):
print(i)
# range(10)循环10次,从0开始9结束
for i in range(10):
print(i)
else:
print("for循环结束会执行else后面的代码")
for循环可以遍历所有容器类型的数据
str1 = "今天又是充满希望的一天!"
index = 0
for i in str1:
print(f"当前元素的下标是:{index},元素具体值是:{i}")
index += 1
list1 = [1, 2, 3, 4, "张三", "李四"]
index = 0
for i in list1:
print(f"当前元素的下标是:{index},元素具体值是:{i}")
index += 1
dict1 = {"name": "张三", "age": "18", "sex": "男"}
# dict1.values()获取字典中的值
for i in dict1.values():
print(i)
# dict1.items()获取字典中的键值对
for i in dict1.items():
print(i)
while循环和if语句类似,区别在于if语句条件成立只执行一次,while条件只要成立就一直执行,直到条件不成立
i = 0
while i < 100:
print(i)
i += 1
死循环
while True:
print("死循环无限执行!!!")
break
:退出当前整个循环
for i in range(10):
if i == 5:
break
print(i,end=" ")
else:
# 循环正常结束才会执行下面的代码
# 当循环中没有出现break终止循环那么else里面的代码就会执行
print("准备就绪")
i = 0
while i <= 10:
i += 1
if i == 8:
break
print(i, end=" ")
else:
# 循环正常结束才会执行下面的代码
# 当循环中没有出现break终止循环那么else里面的代码就会执行
print("准备就绪")
continue
:跳出当次循环,继续下一次循环
for i in range(10):
if i == 5:
continue
print(i,end=" ")
else:
# 循环正常结束才会执行下面的代码
# 当循环中没有出现break终止循环那么else里面的代码就会执行
print("循环结束")
i = 0
while i <= 10:
i += 1
if i == 8:
continue
# break
print(i, end=" ")
else:
# 循环正常结束才会执行下面的代码
# 当循环中没有出现break终止循环那么else里面的代码就会执行
print("循环结束")
什么是函数:函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
函数的核心作用:提高应用的模块性,和代码的重复利用率
函数一般分为两种类型:
函数定义好了之后并不会执行,需要手动的调用才会执行。不管是内建函数还是自定义函数使用的时候都是通过函数名()
进行使用
函数的三大要素
函数语法:
def 函数名(参数列表):
函数体
定义函数使用def
关键字,调用函数:函数名(实参)
# 定义函数
def sum(x, y):
result = x + y
# 返回值return:return会结束当前函数的执行,当功能结束之后需要返回到函数外部的内容
return result
# 调用函数
number = sum(10, 20)
print(number) # 30
位置参数:有几个形参就传递几个实参, 不能多也不能少
如果对函数的形参(返回值)进行指定类型,在调用函数的时候会有说明
# 指定形参的类型,返回值的类型
def celc(number1: int, number2: int, arithmetical: str) -> float:
if arithmetical == "+":
return number1 + number2
elif arithmetical == "-":
return number1 - number2
elif arithmetical == "*":
return number1 * number2
elif arithmetical == "/":
return number1 / number2
else:
print("对不起,您输入的是不支持的运算符")
# 位置参数:有几个形参就传递几个实参, 不能多也不能少
print(celc(10, 20, "+"))
注意
:如果指定了类型,那么不一定要求规定类型也可以正常使用
关键字参数:通过关键字,来决定参数,指定传参
知道形参的前提下,可以指定形参传递实参值,实参通过关键字(形参)指定传过去
def function(a, b, c):
print(a)
print(b)
print(c)
function(c=2, a=3, b=5)
关键字传参一般结合位置参数一起使用
def function(a, b, c):
print(a)
print(b)
print(c)
function(777, c=4, b=5)
注意
:如果结合位置参数一起使用那么关键字参数要在位置参数后面
如果使用默认形参,那么必须放到所有参数的最后面
如果形参有默认值,调用函数的时候可以不传递实参。如果传递了实参那么直接覆盖默认值。如果不传递实参,那么就使用默认值。
def function(a, c, b=20):
print(a)
print(b)
print(c)
function(a=10, c=30)
不定长位置参数用*args
表示,如果函数使用不定长形参,那么可以接收任意的实参,而且是以元组的数据类型进行存储(加了一个星号 * 的参数会以元组(tuple)的形式导入)
不定长参数可以让函数接受不确定长度的实参,可以是0到任意个参数
def function(*args):
print(args)
function("张三",20,3.14)
一般情况不定长的形参会结合位置参数一起使用(当位置形参结合不定长参数一起使用的时候,需要把位置参数放到不定长形参的前面)
# 不定长参数
def function(a, b, *args):
print(a)
print(b)
print(args)
function(10, 20, "张三", 30)
**kwargs
(加了两个星号**
的参数会以字典的形式导入)def function(**kwargs):
print(kwargs)
function(name="张三", age=18, sex="男") # {'name': '张三', 'age': 18, 'sex': '男'}
在函数中,当全局变量和局部变量重名时,默认优先使用局部变量
# 全局变量
# 作用域:可以在函数内部使用,整个py文件也可以使用
number = 888
def function():
# number变量在函数内部叫做局部变量
# 作用域:仅仅是在function函数里面进行使用,函数外部不能进行使用
number = 666
print(f"函数内部number的值是:{number}")
print(f"函数调用之前number的值是:{number}") # 888
function() # 666
print(f"函数调用之后number的值是:{number}") # 888
在函数中,当全局变量和局部变量重名时,默认优先使用局部变量。如果一定要使用全局变量,那么可以使用关键字global
进行声明,声明之后没有局部变量只会有全局变量
# 全局变量
# 作用域:可以在函数内部使用,整个py文件也可以使用
number = 888
def function():
# number变量在函数内部叫做局部变量
# 作用域:仅仅是在function函数里面进行使用,函数外部不能进行使用
global number # number = 888
number = 666 # number = 666
print(f"函数内部number的值是:{number}")
print(f"函数调用之前number的值是:{number}") # 888
function() # 666
print(f"函数调用之后number的值是:{number}") # 666
使用 lambda
来创建匿名函数
所谓匿名,意即不再使用 def
语句这样标准的形式定义一个函数
匿名函数的特点:
return
关键字也有返回值()
进行调用匿名函数的定义和使用:
# 匿名函数使用lambda关键字定义
# a,b:代表形参,a+b:代表函数内容(返回值)
# function代表匿名函数的名字(自定义)
function = lambda a, b: a + b
# 调用匿名函数
result = function(10, 20)
print(result) # 30
匿名函数简写:没有名字直接使用
print((lambda a, b: a + b)(20, 30)) # 50
闭包就是能够读取其他函数内部变量的函数,在本质上,闭包是将函数内部和函数外部连接起来的桥梁
闭包的定义:在函数的嵌套前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数的引用(内部函数的名字),核心点是内部函数使用外部函数的变量,我们把这个构造叫做闭包。
闭包的意义:函数被调用完,函数内的局部变量会被销毁,为了方便保存进行闭包操作
闭包的构成条件:
闭包的作用:
闭包语法结构的定义和使用
案例一:
def function(*args, **kwargs):
def sum(a, b):
return a + b
return sum
# 如何执行add函数?
# 方法一
result = function()(10, 30)
print(result) # 40
# 方法二
sum = function()
result1 = sum(20, 30)
print(result1) # 50
案例二:
def function_out(number1):
def function_inner(number2):
result = number1 + number2
print(f"外部函数的值是:{number1},内部函数的值是:{number2},两个值相加的结果是:{number1 + number2}")
return function_inner
f = function_out(10)
f(30) # 外部函数的值是:10,内部函数的值是:30,两个值相加的结果是:40
# 简写
function_out(10)(40) # 外部函数的值是:10,内部函数的值是:40,两个值相加的结果是:50
模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py
。模块可以被别的程序引入,以使用该模块中的函数等功能(简单来说一个py文件就是一个模块,模块中包含变量、函数、类等,Python中的模块和包可以被其他模块进行导入使用)
包就是一个py文件集合的项目包(包里面可以有很多的模块(py文件))
如何导包
方法一:
# 导入random模块,将random模块里面所有的内容进行导入(变量,函数,类)
import random
# 调用模块里面的randint方法。通过模块名.方法名()进行调用
print(random.randint(1, 10))
方法二:
# 指定功能导入(指定某一个变量,某一个函数,某一个类)
# 具体导入某一个模块的方法或者函数以及变量或者类的时候可以用逗号隔开,导入多个
from random import randint,randrange
# 如果是通过模块具体导入某个方法那么直接通过方法名()进行调用
print(randint(1, 10))
方法三:
# 导入random模块中的所有内容(* 代表被导入模块的所有内容)
from random import *
print(randint(1, 10))
方法四:
# 导入random模块,给random模块起别名为r
import random as r
# 使用模块别名.方法名()进行调用
print(r.randint(1, 10))
注意
:模块名和包名一定要符合标识符的命名规则
异常定义:就是不符合语法规则,就会出现异常信息(bug,程序错误信息提示)
异常信息如下:
Traceback (most recent call last):
File "D:\develop\PyCharm\workspace\pythonProjectSoftwareTest\30异常处理.py", line 1, in <module>
print(a)
NameError: name 'a' is not defined
异常信心的溯源
:File “D:\develop\PyCharm\workspace\pythonProjectSoftwareTest\30异常处理.py”, line 1, in <module>
异常代码的具体详细信息
: print(a)
异常的描述信息
:NameError: name ‘a’ is not defined
异常捕获
通过try
关键字来捕获异常,通过except
关键字进行异常出现后的处理方式
如果try中没有出现异常,那么except里面的代码不会执行
如果try中有异常,那么出现异常后会直接接执行except里面的代码,try中异常代码后面的代码不会继续执行
try:
print("捕获异常")
print(a)
print("捕获异常")
except:
print("捕获到了异常,开始执行某某程序")
else
,finally
关键字一起使用
else
:try当中没有出现异常,那么会执行else里面的代码finally
:不管try当中有没有出现异常,都会执行finally中的代码块try:
print("捕获异常")
print(a)
print("捕获异常")
except:
print("try当中出现了异常,那么会执行except里面的代码块")
else:
print("try当中没有出现异常,那么会执行else里面的代码")
finally:
print("不管try当中有没有出现异常,都会执行finally中的代码块")
注意
:try是可以进行嵌套使用的
文件就是在电脑当中进行持久化储存的内容,不同的文件有不同格式
./
代表当前目录../
代表上级目录./
和.//
都是可以无限使用的open()
:打开文件read()
:读取文件(一次性读取文件全部内容)write()
:写入内容到文件中close()
:关闭文件读取文件内容
read()
:一次性读取文件全部内容readline()
:读取一行readlines()
:读取全部内容,每次一行一行读取,返回的是一个集合,以一行为列表的每个元素# 如果需要读(r)一个文件,当文件不存在的时候程序会报错
# 打开文件open()
# "C:/Users/xiongjian/Desktop/test.txt"代表文件所在路径和文件名
# "r" 代表读,默认
# encoding="utf-8"代表文件的编码格式
file = open("C:/Users/xiongjian/Desktop/test.txt", "r", encoding="utf-8")
# read()读取文件全部内容
result = file.read()
#打印文件内容
print(result)
# close()关闭文件
file.close()
注意
:如果需要读一个文件,当文件不存在的时候程序会报错
写入内容到文件中
# 打开文件open()
# "C:/Users/xiongjian/Desktop/test.txt"代表文件所在路径和文件名
# "w" 代表写
# encoding="utf-8"代表文件的编码格式
file = open("C:/Users/xiongjian/Desktop/test.txt", "w", encoding="utf-8")
# write()写入内容
file.write("这是我写入的内容")
# close()关闭文件
file.close()
注意
:如果需要写文件,文件不存在的时候会自动生成一个文件并写入内容
w
:代表写入
r
:代表读取
mode='r'
a
:代表追加
注意
:以上三种读写模式一般都是用于普通文本(txt格式的文件)。
rb
:以二进制的格式打开一个文件,用于读wb
:以二进制的格式打开一个文件,用于写ab
:以二进制的格式打开一个文件,用于追加写入
注意
:如果是二进制的文件,那么不要指定编码格式,不然程序会报错
+
号r+
w+
a+
rb+
wb+
ab+
注意
:r+
、w+
、a+
、rb+
、wb+
、ab+
可以对打开的文件对象模式进行读和写(但是不能同时进行)
remove()
:删除文件(如果删除的文件不存在,程序会报错)
import os
# remove()删除文件,注意:如果删除的文件不存在,程序会报错
# r:当路径信息中有转义字符,可以消除转义
os.remove(r"C:\Users\xiongjian\Desktop\test.txt")
renames()
:重命名
import os
# renames()重命名,语法:renames("原文件名","新文件名")
# r:当路径信息中有转义字符,可以消除转义
# 如果新文件名前面没有路径信息,那么默认保存在当前项目中,相当于原文件移动到当先项目路径并改名(注意:如果文件与项目文件不再同一个磁盘下代码会报错)
os.renames(r"D:\test.txt", "tests.txt")
复制
getcwd()
:获取当前文件的绝对路径信息
import os
# 获取当前文件的绝对路径信息
print(os.getcwd())
mkdir()
:创建文件夹
import os
# mkdir()创建文件夹
os.mkdir("test")
rmdir()
:删除文件夹(注意:如果删除一个不存在的文件夹会报错,删除非空文件夹也会报错)
import os
# rmdir()删除文件夹,注意:如果删除一个不存在的文件夹会报错,删除非空文件夹也会报错
os.rmdir(r"C:\Users\xiongjian\Desktop\test")
listdir()
:获取文件夹内的文件及目录信息(返回的是一个列表)
import os
# listdir()获取文件夹内的文件及目录信息
print(os.listdir(r"C:\Users\xiongjian\Desktop\test"))
# 获取文件夹内的文件及目录个数
print(len(os.listdir(r"C:\Users\xiongjian\Desktop\test")))
import os
# 创建一个函数
def delete_folder(path):
# os.path.exists(path)判断返回路径是否存在。返回的是布尔值
if os.path.exists(path):
# 遍历文件夹下所有子目录和文件并删除
# os.walk():扫描某个指定目录下所包含的子目录和文件,返回的是一个迭代器
for root, dirs, files in os.walk(path, topdown=False):
for file in files:
# os.remove删除文件
# os.path.join(root, file)把目录和文件名合成一个路径
os.remove(os.path.join(root, file))
for dir in dirs:
# os.rmdir()删除文件夹
# os.path.join(root, 文件夹)把目录和文件名合成一个路径
os.rmdir(os.path.join(root, dir))
os.rmdir(path)
else:
print("Folder not found 找不到文件夹")
# 调用函数:
delete_folder(r"C:\Users\xiongjian\Desktop\test")
面向过程
:需要实现一个功能的时候,看中的是开发的步骤和过程,每一个步骤都是亲力亲为用代码去编写然后实现功能面向对象
:需要实现一个功能的时候,不看中开发的步骤和过程,核心是谁来帮我实现这个功能
封装
继承
多态
类(Class)
:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例方法
:类中定义的函数类变量
:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用数据成员
:类变量或者实例变量用于处理类及其实例对象的相关的数据方法重写
:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写局部变量
:定义在方法中的变量,只作用于当前实例的类实例变量
:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self
修饰的变量继承
:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。实例化
:创建一个类的实例,类的具体对象对象
:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法特征
:设置成类的实例属性行为
:设置成类的实例方法类的实例属性定义和实例方法定义
self
参数(没人加任何装饰器)# 定义一个人类
# 使用class关键字创建类:class关键字后面接类名(类名要符合标识符命名规则,并且一般推荐使用大驼峰命名法)
# 在不发生继承的情况下,类后面的括号可写可不写
class Person():
# 类有一个名为 __init__() 的特殊方法(构造方法,有的称之为魔法方法),该方法在类实例化时会自动调用
# 当对象一旦被创建,自动执行init构造方法里面的内容
def __init__(self):
# self代表对象本身
# 特征:设置成类的实例属性
# 对象的实例属性全部封装到init构造方法中
self.name = "张三"
self.age = 18
self.sex = "男"
# 行为:设置成类的实例方法
# 类当中的函数叫做方法:函数可以没有形参,而方法一定要有一个形参(对象本身self)
# 默认的self形参后面可以自定义任何类型的形参:位置参数,不定长参数,默认参数等等......
def sleep(self, time):
print(f"睡觉,睡了{time}小时")
def eat(self):
print("吃饭")
def play_games(self):
print("玩游戏")
# 如何创建一个对象(对象是通过类实例化的产物)
# 通过人类Person创建一个对象,person1代表对象
person1 = Person()
# 通过人类Person创建一个对象,person2代表对象
person2 = Person()
# 实际对象是谁,那么谁就是self
# 所有通过Person类创建的对象全部拥实例属性和实例方法
实例属性和实例方法的使用
# 定义一个人类
# 使用class关键字创建类:class关键字后面接类名(类名要符合标识符命名规则,并且一般推荐使用大驼峰命名法)
# 在不发生继承的情况下,类后面的括号可写可不写
class Person():
# 类有一个名为 __init__() 的特殊方法(构造方法,有的称之为魔法方法),该方法在类实例化时会自动调用
# 当对象一旦被创建,自动执行init构造方法里面的内容
def __init__(self):
# self代表对象本身
# 特征:设置成类的实例属性
# 对象的实例属性全部封装到init构造方法中
self.name = "张三"
self.age = 18
self.sex = "男"
# 行为:设置成类的实例方法
# 类当中的函数叫做方法:函数可以没有形参,而方法一定要有一个形参(对象本身self)
# 默认的self形参后面可以自定义任何类型的形参:位置参数,不定长参数,默认参数等等......
def sleep(self, time):
print(f"睡觉,睡了{time}小时")
def eat(self):
print("吃饭")
def play_games(self):
print("玩游戏")
# 如何创建一个对象(对象是通过类实例化的产物)
# 通过人类Person创建一个对象,person1代表对象
person1 = Person()
# 通过人类Person创建一个对象,person2代表对象
person2 = Person()
# 实际对象是谁,那么谁就是self
# 所有通过Person类创建的对象全部拥实例属性和实例方法
print(person1.name) # 张三
print(person1.age) # 18
print(person1.sex) # 男
# 通过对象调用实例方法
# 对象名.方法名()
person1.sleep(7) # 睡觉,睡了7小时
person1.eat() # 吃饭
person1.play_games() # 玩游戏
# 每一个对象都可以调用相同的实例方法(在内存里面是统一管理的区域)
print(person2.name) # 张三
print(person2.age) # 18
print(person2.sex) # 男
person2.sleep(8) # 睡觉,睡了8小时
person2.eat() # 吃饭
person2.play_games() # 玩游戏
在实例方法当中使用实例属性
class Person():
# 因为创建对象时会自动调用init构造方法,那么如果需要创建对象的时候传递实参,需在init构造方法中就应该定义形参
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def sleep(self, time):
print(f"睡觉,睡了{time}小时")
def eat(self):
print("吃饭")
def play_games(self):
print("玩游戏")
# 实例方法中可以使用实例属性
def show(self):
# 通过self.属性名进行使用
print(f"姓名:{self.name},年龄:{self.age},性别:{self.sex}")
person1 = Person("张三", 18, "男")
person1.show() # 姓名:张三,年龄:18,性别:男
person2 = Person("李四", 20, "女")
person2.show() # 姓名:李四,年龄:20,性别:女
类属性和类方法的定义
@classmethod
的方法叫做类方法class Person():
# 类里面定义的变量,就叫做类属性
# name就是类属性
name = "张三"
def __init__(self):
# 类里面并且在init构造方法里面定义的变量,叫做实例属性
self.name1 = "李四"
# 类方法的定义
# 加上装饰器:@classmethod
# 默认的第一个参数是cls:代表类名 Person = cls
@classmethod
def sleep(cls):
print("类方法sleep被调用了")
def eat(self):
print("实例方法eat被调用了")
类属性和类方法的使用
class Person():
name = "张三"
def __init__(self):
self.name1 = "李四"
@classmethod
def sleep(cls):
print("类方法sleep被调用了")
def eat(self):
print("实例方法eat被调用了")
# 类只能调用类属性和类方法,不能使用实例方法和实例属性
# 类属性和类方法的使用
# 通过类调用类属性:类名.属性名
print(Person.name) # 张三
# 通过类调用类方法:类名.方法名()
Person.sleep() # 类方法sleep被调用了
# 对象可以使用类属性和实例属性,类方法和实例方法
# 创建对象
person = Person();
# 对象调用类属性
print(person.name) # 张三
# 对象调用实例属性
print(person.name1) # 李四
# 对象调用类方法
person.sleep() # 类方法sleep被调用了
# 对象调用实例方法
person.eat() # 实例方法eat被调用了
总结:实例属性和实例方法跟类属性类方法的区别
类只能使用类属性和类方法
对象可以使用类属性和实例属性以及类方法和实例方法
类中除了实例方法和类方法还有静态方法
静态方法
:类中的函数,第一个参数不是self
也不是cls
而可以没有参数
类和对象都可以使用静态方法的使用
静态方法的定义及使用
class Person():
name = "张三"
def __init__(self):
self.name = "张三"
# 静态方法的定义
# 静态方法:使用@staticmethod装饰器
@staticmethod
def play_games():
print("我是play_games静态方法")
# 类方法
@classmethod
def sleep(cls):
print("类方法sleep被调用了")
# 实例方法
def eat(self):
print("实例方法eat被调用了")
# 类和对象都可以使用静态方法的使用
# 类调用静态方法play_games 类名.静态方法名()
Person.play_games() # 我是play_games静态方法
# 创建对象
person = Person()
# 对象调用静态方法play_games 对象名.静态方法名()
person.play_games() # 我是play_games静态方法
了解
:类当中的方法可以使用装饰器@property
变成属性
class Person():
hobby = "钓鱼"
def __init__(self):
self.name = "张三"
# 实例方法
def eat(self):
print("实例方法eat被调用了")
# 类方法
@classmethod
def sleep(cls):
print("类方法sleep被调用了")
# 静态方法
@staticmethod
def play_games():
print("静态方法play_games被调用了")
# Person2类继承了Person类(Person2是子类,Person是父类)
class Person2(Person):
pass
# 根据Person2类创建对象
p1 = Person2()
# 使用Person类当中的类属性
print(p1.hobby) # 钓鱼
# 使用Person类当中的实例属性
print(p1.name) # 张三
# 使用Person类当中的类方法
p1.sleep() # 类方法sleep被调用了
# 使用Person类当中的实例方法
p1.eat() # 实例方法eat被调用了
# 使用Person类当中的静态方法
p1.play_games() # 静态方法play_games被调用了
当父类有同名方法和同名属性(包括构造方法,魔法属性),会优先使用第一个继承的方法或者属性,不会重复执行也不会覆盖
使用魔法属性 __mro__
可以显示继承关系
class Person():
hobby = "钓鱼"
def __init__(self):
self.name = "张三"
# 实例方法
def eat(self):
print("实例方法eat被调用了")
# 类方法
@classmethod
def sleep(cls):
print("类方法sleep被调用了")
# 静态方法
@staticmethod
def play_games():
print("静态方法play_games被调用了")
class Person2():
age = 18
def __init__(self):
self.height = 180
# Person3类继承了Person类和Person2类
class Person3(Person, Person2):
pass
# 根据Person3类创建对象
p1 = Person3()
# 使用Person类当中的类属性
print(p1.hobby) # 钓鱼
# 使用Person类当中的实例属性
print(p1.name) # 张三
# 使用Person类当中的类方法
p1.sleep() # 类方法sleep被调用了
# 使用Person类当中的实例方法
p1.eat() # 实例方法eat被调用了
# 使用Person类当中的静态方法
p1.play_games() # 静态方法play_games被调用了
# 使用Person2类当中的类属性
print(p1.age) # 18
# 使用Person2类当中的实例属性
# 当父类有同名方法和同名属性(包括构造方法,魔法属性),会优先使用第一个继承的方法或者属性,不会重复执行也不会覆盖
# print(p1.height) # 执行报错 因为只会执行Person2类中的__init__构造方法,该方法中没有height实例属性
# 通过魔法属性__mro__显示继承关系
print(
Person3.__mro__) # (<class '__main__.Person3'>, <class '__main__.Person'>, <class '__main__.Person2'>, <class 'object'>)
总结
:当子类方法和属性跟父类冲突时(属性和方法重名),优先使用子类重名的属性或者方法
通过内建函数
super()
可以调用父类的同名方法和属性
class Person():
def eat(self):
print("Person类中的实例方法eat被调用了")
class Person2():
def eat(self):
print("Person2类中的实例方法eat被调用了")
# Person3类继承了Person类和Person2类
class Person3(Person, Person2):
def eat(self):
# 通过内建函数super()可以调用父类的同名方法(使用父类的eat()方法)
super().eat()
# 默认情况子类和父类属性方法同名优先使用子类属性和方法
p1 = Person3()
p1.eat() # Person类中的实例方法eat被调用了
在程序设计中,鸭子类型是动态类型的一种风格。
鸭子类型:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子
忽略对象的实际形态(状态),而是以胜任的方式去充当该类型。
多态的概念:多态是指一类事物有多种形态,忽略对象的实际形态(状态),而是以胜任的方式去充当该类型。
class Person():
def __init__(self):
self.name = "张三"
def play_games(self):
print("玩游戏")
# 创建一个person对象
person = Person()
# 创建一个function函数
def function():
person.play_games()
print(person.name)
# 调用function函数
function()
数据类装饰器:可以对类进行装饰的装饰器
自动为类创建很多特殊方法包括魔法方法,不需要手动的定义init
直接使用,实例属性的另外一种定义格式
数据类装饰器的使用:
dataclasses
模块@dataclasses.dataclass
import dataclasses # 该模块在Python3.7版本之后才能使用
# 数据类定义的变量可以被类方法和实例方法使用
@dataclasses.dataclass
class Person():
name = "张三"
# 实例属性的定义
age: int = 18
def show(self):
print(f"我的年龄是:{self.age}岁")
@classmethod
def show2(cls):
print(f"我的年龄是:{cls.age}岁")
# 当创建对象传递实参,当数据被实例属性使用的时候会用用实参传递过来的值,类属性使用的时候会使用默认值
person = Person(20)
person.show() # 我的年龄是:20岁
person.show2() # 我的年龄是:18岁
装饰器本身是一个函数
装饰器的返回值是一个函数的引用(函数名字)
装饰器只能必须一定是一个形参(形参:用来接收函数的引用(接收函数的名字))
核心的使用原则:装饰器是给已有的函数增加额外的功能,本质上是一个闭包函数
装饰器的功能特点:
# 场景:去某平台购物,先登录才能添加商品到购物车
def login(function):
def login_in():
print("进入登陆页面")
print("输入账号密码点击登陆")
print("正在进行登陆验证......")
print("登陆成功")
function() # function函数的引用: function = shopping ---> function() = shopping()
return login_in
def shopping():
print("买个iPhone15手机")
# 这里的shopping变量可以随便命名
shopping = login(shopping) # shopping = login_in
shopping() # shopping() = login_in()
代码执行流程
Python提供了装饰器的精简的书写方式:语法糖格式
@装饰器的名字,通过语法糖完成对已有函数的装饰
注意:装饰器要写在被装饰的函数定义的上面
# 场景:去某平台购物,先登录才能添加商品到购物车
def login(function):
def login_in():
print("进入登陆页面")
print("输入账号密码点击登陆")
print("正在进行登陆验证......")
print("登陆成功")
function()
return login_in
@login # @login等同于shopping = login(shopping)
def shopping():
print("买个iPhone15手机")
shopping()
解释器在执行代码的时候遇到装饰器会先加载装饰器代码并执行
# 会打印输出 "装饰器代码已经开始执行......"
def login(function):
def login_in():
print("登陆成功")
function()
print("装饰器代码已经开始执行......")
return login_in
@login
def shopping():
print("买个iPhone15手机")
统计一个函数的执行时间
输出日志信息
缓存处理
实现路由
统计一个函数的执行时间案例实现
import time
def get_time(function):
def inner():
begin = time.time()
function()
end = time.time()
print(f"当前模块代码执行的时间是:{end - begin}秒")
return inner
@get_time
def count():
for i in range(1, 2000000):
print(i)
count()
def operation(flag):
def out_funciton(fn):
def inner_function(number1, number2):
if flag == "+":
print("您输入的符号是加号,正在努力计算结果......")
elif flag == "-":
print("您输入的符号是减号,正在努力计算结果......")
elif flag == "*":
print("您输入的符号是乘号,正在努力计算结果......")
elif flag == "/":
print("您输入的符号是除号,正在努力计算结果......")
result = fn(number1, number2)
return result
return inner_function
return out_funciton
@operation("+")
def add(a, b):
return a + b
@operation("-")
def subtract(a, b):
return a - b
@operation("*")
def multiply(a, b):
return a * b
@operation("/")
def divide(a, b):
return a / b
print(add(12, 30))
print(subtract(40, 20))
print(multiply(2, 9))
print(divide(9, 3))
使用了 yield
的函数被称为生成器
yield
是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
当在生成器函数中使用 yield
语句时,函数的执行将会暂停,并将 yield
后面的表达式作为当前迭代的值返回。然后,每次调用生成器的 next()
方法或使用 for
循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield
语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果
生成器当中可以有一个或者多个 yield
关键字
调用一个生成器函数,返回的是一个迭代器对象
生成器的定义及使用
def function(number):
while number > 0:
yield number
number -= 1
# 创建生成器对象
fun = function(5)
# 通过迭代生成器获取值
print(next(fun)) # 输出: 5
print(next(fun)) # 输出: 4
print(next(fun)) # 输出: 3
# 使用 for 循环迭代生成器
for value in fun:
print(value) # 输出: 2 1
使用内建函数setattr()
class A():
def a(self):
print("这是a方法")
def b(self):
print("这是b方法")
def c(self):
print("这是c方法")
x = A()
# 给x对象设置一个动态实例方法
setattr(x, "d", print)
x.d("通过d方法输出内容")
setattr(x, "d", input)
result = x.d("通过d方法获取用户输入内容:")
print(result)
# 覆盖
setattr(x, "b", print)
x.b("这是通过反射覆盖b方法")
使用内建函delattr()
class A():
def a(self):
print("这是a方法")
def b(self):
print("这是b方法")
def c(self):
print("这是c方法")
x = A()
# 删除
delattr(x, "a")
使用内建函数hasattr()
class A():
def a(self):
print("这是a方法")
def b(self):
print("这是b方法")
def c(self):
print("这是c方法")
x = A()
print(hasattr(x, "a")) # True
print(hasattr(x, "d")) # False
使用内建函数getattr()
class A():
def a(self):
print("这是a方法")
def b(self):
print("这是b方法")
def c(self):
print("这是c方法")
x = A()
for i in ["a", "b", "c"]:
function = getattr(x, i)
function()
安装
pip install 第三方库的名字(包名)
卸载
pip uninstall 第三方库的名字(包名)
查看
#查看当前环境的包名字以及版本号
pip list
虚拟环境里面的项目包第三方库都是独立的,不会跟本地冲突也不会有任何印象