小牛 小牛壮士 的个人博客

python基础语法


前言#

语言:Python(python==3.9)

编译软件:VScode、PyCharm

环境:Anaconda

一、Python注释和输入输出#

注释分为单行注释,多行注释,被注释的代码不会运行,快捷键:选中代码+Ctrl+/

主要功能有:

1.对代码进行注释,方便进行理解

2.对代码进行禁用

1.单行注释#

# 单行注释
# 我是一个注释 不是运行的代码 写代码的时候:Ctrl+/
# print("hello")
print(123)

点击并拖拽以移动

**运行结果:**123

2.多行注释#

"""
三引号
引号内代码都注释
随便写多少行
"""
print("hello")

点击并拖拽以移动

**运行结果:**hello

3.输入和输出#

# 输出
print("打印文本")
print("打印数字:",123)
print("文本1","文本2","文本3",sep = "-")
print("文本1",end = "\n")
print("文本2",end = "123")
print("文本3",end = "\n")

点击并拖拽以移动

运行结果:

打印文本 打印数字: 123 文本1-文本2-文本3 文本1 文本2123文本3

# 输入
print(123)
x = input("打印到控制台,让程序暂停,等待用户输入")
print(x)
print(456)

点击并拖拽以移动

运行结果:

123 444(将在控制台显示“打印到控制台,让程序暂停,等待用户输入”,等到用户输入后再运行下面的程序,这里输入444,输出444) 456

二、变量#

什么是变量:用一个简短的名称来代替数据的使用

1.数值#

a = 100
print(a)
print(100)

点击并拖拽以移动

2.字符串#

b = "我是一个字符串"
# 声明了一个变量,名字叫b,后面程序运行时可以直接用b来表示
print(b)

点击并拖拽以移动

3.变量名称的要求#

一般场景下必须使用变量来保存数据,如果不需要使用到的数据需要接收,则用下划线“_”表示变量名

x = 123
y = "nihao"
_ = 200
print(x,y,_)

点击并拖拽以移动

变量名字必须是连续的字母,下划线,数字的组合。错误的命名方法:first name = "123"

firstname = "123123" #不会报错,但是不方便阅读

点击并拖拽以移动

数字不可以作为变量名的开头,变量名严格区分大小写Name和name是两个不同的变量

1app_version = "1.1.0"
print(1app_version)

点击并拖拽以移动

官方提供的关键字不可以作为变量名

True = 10

点击并拖拽以移动

中文作为变量名?可以,只要是Unicode编码符合的字符都可以作为变量名,一般约定用英文或者拼音字母而不用汉字

华清远见 = "华清远见成都分中心在西南交大地铁站旁"
print(华清远见)

点击并拖拽以移动

常把大写字母的变量名作为不改变的常量使用

PI = 3.14159

点击并拖拽以移动

4.变量名命名规则#

三种写法:

1.小驼峰:huaQingYuanJian

2.大驼峰:AppVersion

3.匈牙利命名法(比较常用):ai_first_class_1

三、变量的赋值与取值#

1.数据直接量#

x = 100
x_2 = "hello"
#取出变量中的数据并打印
print(x)

点击并拖拽以移动

2.表达式#

x_3 = x
print(x_3)

点击并拖拽以移动

3.多变量一起赋值#

a = b = c = 100
print(a,b,c)

点击并拖拽以移动

4.解构赋值#

w,m,n = 100,10,1
print(w,m,n)

点击并拖拽以移动

5.变量的取值#

x = 10
x = 1#此时x最后被更新为1
print(x)#必须要等打印出来过后才执行后续的代码

x1 = 10
x2 = 20
x3 = 30
c = 666,x1,x2,x3
print(c)
x1,a,b,c= 666,x1,x2,x3
print(x1,a,b,c)

# 交换两个数据的取值
x1 = 10
x2 = 20
x1,x2 = x2,x1#x1<--x2,x2<--x1同时发生,优先级:先取值后赋值  生成一个元祖(x2,x1)==>(20,10)==>(x1,x2)
print(x1,x2)

点击并拖拽以移动

四、字符串#

1.字符串的写法#

x_1 = "我是一个字符串"
x_2 = ""#空字符串
x_3 = " "#空格也是字符串
print(type(x_2))

点击并拖拽以移动

x1 = "hello"
x2 = "hi"
x3 = """三引号也可以是字符串
可以随意换行
自带换行符
"""
print(x3)

点击并拖拽以移动

运行结果:

三引号也可以是字符串 可以随意换行 自带换行符

2.转义字符#

x1 = "我爱我的祖国和我的家乡\"四川\""
print(x1)
x2 = '我爱我的祖国和我的家乡\'四川\''
print(x2)
x3 = "我爱我的祖国和我的家乡'四川'"
print(x3)
x4 = "你好:\n  欢迎你"
print(x4)
x5 = "abcd\\efg\\hi"
print(x5)
x6 = "abc\tdef\tghi"
print(x6)
x7 = r"D:\桌面\华清\3.8\code\06-字符串.ipynb"#在字符串之前加r,表示\不转义
print(x7)

点击并拖拽以移动

运行结果:

我爱我的祖国和我的家乡"四川" 我爱我的祖国和我的家乡'四川' 我爱我的祖国和我的家乡'四川' 你好: 欢迎你 abcd\efg\hi abc def ghi D:\桌面\华清\3.8\code\06-字符串.ipynb

3.字符串常用运算操作#

加号:

x1 = "华清远见"
x2 = "成都分中心"
str_1 = x1 + x2
print(str)

点击并拖拽以移动

x3 = "我的年龄是:"
x4 = "18"
str_2 = x3 + x4#只能字符串和字符串进行连接,两个变量的类型不匹配则不能拼接
print(str_2)

x5 = '华清''远见''666'#多个字符串靠在一起自动变成一个字符串
print(x5)

点击并拖拽以移动

乘号:

# 乘号
x6 = "abc"
str_3 = x6*3
print(str_3)

点击并拖拽以移动

运行结果:

华清远见成都分中心 我的年龄是:18 华清远见666 abcabcabc

等号:(严格区分大小写)

x1 = "abc"
x2 = "Abc"
print(x1==x2)

点击并拖拽以移动

运行结果:

False

4.访问子串#

x7 = "华清远见成都分中心"
xx_7 = x7[0]
print(xx_7)

xx_77 = x7[-1]
print(xx_77)

xx__77 = x7[2:10:2]#切片,左闭右开,第三个数字代表每两个选中
print(xx__77)

xx__78 = x7[::2]
print(xx__78)

xx__79 = x7[:6:2]
print(xx__79)

xx__70 = x7[-1:6:2]
print(xx__70)

xx__74 = x7[9:3:-1]
print(xx__74)

点击并拖拽以移动

运行结果:

华 心 远成分心 华远成分心 华远成

心中分都成

比较常用的三个:

xx__71 = x7[::-1]
print(xx__71)

xx__72 = x7[:-1]
print(xx__72)

xx__73 = x7[-1]
print(xx__73)

点击并拖拽以移动

运行结果:

心中分都成见远清华 华清远见成都分中 心

5.输入一个字符串,判断是否回文#

x1 = input("请输入字符串")# 这里输入:上海自来水来自海上
x2 = x1[::-1]
print(x1==x2)

点击并拖拽以移动

**运行结果:**True

6.判断一个字符串是否为另一个字符串的子串#

x1 = "abcdefg"
x2 = "ab"
x3 = "gh"
print(x1 in x2)
print(x3 in x1)
print(x3 not in x1)

点击并拖拽以移动

运行结果:

False False True

7.查看字符串字符数量(长度)#

x1 = "abc"
n = len(x1)
print(n)

点击并拖拽以移动

**运行结果:**3

8.常见占位符#

占位符和类型码

| 占位符和类型码 | 说明                                                         |
| :------------: | ------------------------------------------------------------ |
|       %s       | 转成字符串, 使用 str(x) 函数转换(常用)                       |
|       %d       | 转成十进制的整数(常用)                                       |
|       %o       | 转成八进制的整数                                             |
|     %x,%X      | 转成十六进制的整数                                           |
|     %e,%E      | 转成指数格式的浮点数                                         |
|     %f,%F      | 转成小数格式的浮点数(常用)                                   |
|     %g,%G      | 转成指数格式或小数格式的浮点数                               |
|       %%       | 转成一个%                                                    |
|     %m.nf      | m是指总宽度,默认右对齐,加个 - 表示左对齐,n 是指保留的小数点位数 |

点击并拖拽以移动

9.字符串格式化表达式#

常用来在训练自己的神经网络模型时,控制台查看数据情况

x1 = "我叫%s今年%d岁"%("jack",23)
print(x1)

# 保留小数位数
x2 = "精确度是%.2f"%(100)
print(x2)

# 总宽度
x3 = "精确度是%50.3f"%(100)
print(x3)

# 进制转换
x4 = "十六进制的值是%x"%(11)
print(x4)

# 科学计数法
x5 = "科学计数法表示为%g"%(1000000000)
print(x5)

点击并拖拽以移动

运行结果:

我叫jack今年23岁 精确度是100.00 精确度是 100.000 十六进制的值是b 科学计数法表示为1e+09

10.另外一种格式化字符串的方式#

r = 144
g = 127
b = 255
x1 = "rgb(144,127,255)"
x2 = f"rgb({r},{g},{b})"
print(x1)
print(x2)

点击并拖拽以移动

运行结果:

rgb(144,127,255) rgb(144,127,255)

11.字符串常用的一些API(别人写的一些函数,可以直接调用)#

# 将字母全部转换为小写
text = "HELLO world"
text2 = text.lower()
print(text2)

# 将字母全部转换为大写
text3 = text.upper()
print(text3)

# 首字母大写
text4 = text.capitalize()
print(text4)

# 去除两边空白字符
text = "  1825648  "
text5 = text.strip()
print(text5)

# 将字符串分割成列表(默认是空格)
text = "hello my name is jack"
text6 = text.split()
print(text6)
# 综合使用
text = "http://www.hqyj.com/index.html?user_id=123&user_name=jack&count=20"
text7 = text.split("?")[0]
print(text7)
text8 = text.split("?")[1].split("&")[1].split("=")[1]
print(text8)

# 连接字符串
text = ['hello', 'my', 'name', 'is', 'jack']
text9 = "-".join(text)
print(text9)

# 字符串替换
text = "你好,我叫李华"
text0 = text.replace("李华","李雷")
print(text0)

# 查找特定字符
text = "hello,my name is lihua"
text11 = text.find("lihua",19)#第二个参数代表起始下标,返回-1表示未查找到 
print(text11)

# 检查字符串是否以指定字符串开头
text = "std = 1"
text12 = text.startswith("std")
print(text12)

# 检查字符串是否以指定字符串结尾,返回布尔类型
text = "std = 1,name"
text13 = text.endswith("name")
print(text13)

# 是否全是数字
text = "1600"
text14 = text.isdigit()
print(text14)

# 是否只包含字母
text = "1600yuan"
text15 = text.isalpha()
print(text15)

# 是否只包含字母和数字字符
text = " price = 1600_yuan"
text16 = text.isalnum()
print(text16)

# 将字符串内每个单词首字母转变为大写
text17 = text.title()
print(text17)

# 将字符串首字母转变为大写
text18 = text.capitalize()
print(text18)

# 统计词频
text = "Hello, World! Hello, Python!"
text19 = text.count("Hello")
print(text19)

# 格式化字符串
name = "jack"
age = 18
text20 = f"my name is {name}, i am {age} year old"
print(text20)

点击并拖拽以移动

运行结果:

hello world HELLO WORLD Hello world 1825648 ['hello', 'my', 'name', 'is', 'jack'] http://www.hqyj.com/index.html jack hello-my-name-is-jack 你好,我叫李雷 -1 True False True False False Price = 1600_Yuan price = 1600_yuan 2 my name is jack, i am 18 year old False

五、数值型#

1.进制#

十进制

x = 10

点击并拖拽以移动

八进制,打印默认转化为十进制数

y = 0o100
print(y)

点击并拖拽以移动

十六进制

z = 0xD1BfD
print(z)

点击并拖拽以移动

二进制

m = 0b1010001
print(m)

点击并拖拽以移动

运行结果:

64 859133 81

2.浮点数与科学计数法#

x = 1.0
y = 2.
z = .6

# 科学计数法
x = 1e6
y = 2e03#0没有任何作用
z = 3e-3
import math
PI = math.pi
PI

点击并拖拽以移动

3.数字类型转换#

x = 6
x1 = bin(x)
x2 = oct(x)
x3 = hex(x)
x4 = float(x)
x5 = complex(x)
x = 3.0
x6 = int(x)
print(x1,x2,x3,x4,x5,x6)

点击并拖拽以移动

math.ceil(x)函数返回大于或等于x的最小整数。 math.floor(x)函数返回小于或等于x的最大整数。

print(math.ceil(3.14))
print(math.floor(3.94))

点击并拖拽以移动

运行结果:

0b110 0o6 0x6 6.0 (6+0j) 3 4 3

4.布尔类型#

x = 0
print(bool(x))
y = ""
print(bool(y))
z = "0"
print(bool(z))
# 空的集合,列表,字符串都是True
print(10<20)

点击并拖拽以移动

运行结果:

False False True True

5.字节串和空值#

# 字节串
text = b"hello"
print(type(text))

# 空值
x = None#表示没有
print(x)

点击并拖拽以移动

六、列表#

1.字面量#

x = []
print(type(x))
x = [1, 2, 3, 4, 5]
print(x)
x = [1, 2, [3,4]]
print(x)

点击并拖拽以移动

2.通过构造函数来创建列表#

x = list()
print(x)

点击并拖拽以移动

3.list函数可以传入一个可迭代对象用于创建列表中数据#

x = list("hello")
print(x)
# 或者
x = list(range(10))
print(x)

点击并拖拽以移动

4.列表的运算#

y = [4,5,6]
num = 5
z = x + y
print(z)
# 不能列表乘以列表,不能列表乘以浮点数
print(z)
z = x * num

点击并拖拽以移动

5.in / not in#

x = ["a","b","c"]
print("a" in x)
print("b" not in x)

点击并拖拽以移动

6.列表切片#

lst = [1,5,6,9,8,10]

# lst[起始下标:终止下标:步长]

# 取出一个元素

Lst_1 = lst[2]

# 取出多个元素

lst_2 = lst[2:5:2]

# 列表翻转

lst_3 = lst[::-1]

print(Lst_1,lst_2,lst_3)

点击并拖拽以移动

运行结果:

6 [6, 8] [10, 8, 9, 6, 5, 1]

7.列表的操作#

x = [10, 20, 30]
re = x.append(40)# 直接修改列表,在列表末尾添加一行新数据
print(x,re)

x.insert(2,666)# 在索引为2的地方插入666
print(x)

# 可以传入一个可迭代对象
x.extend([9,99,999])
print(x)

# id函数可以查看一个变量保存的数据的地址
x_1 = [1,2,3]
print(id(x_1))
x_2 = [1,2,3]
x_3 = x_1 + x_2
x_1.extend(x_2)
print(id(x_1))
print(id(x_2))#不改变id地址
print(id(x_3))

# 修改,删除数据
x = [1,2,3,5,6,8,9,7,1,2]
x[2] = 666
print(x)
# 切片可以越界
print(x[2:100])
# 传入元素
x.remove(666)
print(x)
# 传入下标
x.pop(1)
print(x)
x.clear()
print(x)

# 删除变量,变量名不在支持被引用
x = [1,2,3,5,6,8,9,7,1,2]
del x
# print(x)报错

x = [1,2,3,5,6,8,9,7,1,2]
# 寻找第一个出现元素的下标
print(x.index(1))
print(x.index(max(x)))

点击并拖拽以移动

运行结果:

[10, 20, 30, 40] None [10, 20, 666, 30, 40] [10, 20, 666, 30, 40, 9, 99, 999] 2303722066048 2303722066048 2303722068160 2303722005568 [1, 2, 666, 5, 6, 8, 9, 7, 1, 2] [666, 5, 6, 8, 9, 7, 1, 2] [1, 2, 5, 6, 8, 9, 7, 1, 2] [1, 5, 6, 8, 9, 7, 1, 2] []

0 6

七、元组#

元组和列表一样是保存数据的容器

1.创建元组#

x = ()
x = (1,2,3,5,6,8,5,4,2,5)
print(x)
print(x[1])
print(x[2:5])#得到一个新元组

# 只有一个数据,在后面打逗号
x = (10)
y = (10,)
print(type(x))
print(type(y))

x = 10,"hello",True
print(type(x))

x = tuple(range(5))
print(x)

点击并拖拽以移动

运行结果:

(1, 2, 3, 5, 6, 8, 5, 4, 2, 5) 2 (3, 5, 6) <class 'int'> <class 'tuple'> <class 'tuple'> (0, 1, 2, 3, 4)

2.元组的操作#

x = (1,"name","jack",6,5)
# 删除变量
# del x
print((x[1]))

点击并拖拽以移动

3.解构赋值#

解构赋值必须左右的结构一致

x1,x2 = (10,20)
print(x1,x2)

点击并拖拽以移动

4.元组的运算#

x = (10,20)
y = (30,40)
print(x+y)
print(x * 3)

点击并拖拽以移动

5.将其他数据类型转换为元组#

x_1 = [1,2,5,6]
x_2 = "nihao","yes","no"
print(tuple(x_1),tuple(x_2))

count = x_2.count("no")
print(count)

点击并拖拽以移动

八、字典#

1.创建空字典#

字典的元素没有下标,只有键和值

d = {}
print(d)
d = dict([("name","xiaowang"),("age",18)])
print(d)
d = dict(a = 1, b = 2, c = 3)
print(d)
# 字典的键不可以重复,否则后一个会覆盖前一个
title = {"name":"jack","age":"18","age":"10"}
print(title["age"])
# 并且需要是不可变类型,以此来访问数据,字典的键不存在会报错
title = {"name":"jack","age":"18","home":"beijing"}
print(title)
d = {(1,2,3):"id_num","age":18}
print(d)

点击并拖拽以移动

运行结果:

{} {'name': 'xiaowang', 'age': 18} {'a': 1, 'b': 2, 'c': 3} 10 {'name': 'jack', 'age': '18', 'home': 'beijing'} {(1, 2, 3): 'id_num', 'age': 18}

2.字典的操作#

# 添加和修改和访问
title = {"name":"jack","age":18,"home":"beijing"}
title["age"] = 20
print(title)
title["school"]="swust"
print(title)
print(title["home"])

点击并拖拽以移动

运行结果:

{'name': 'jack', 'age': 20, 'home': 'beijing'} {'name': 'jack', 'age': 20, 'home': 'beijing', 'school': 'swust'} beijing

3.in/not in#

只能用来判断键

title = {"name":"jack","age":18,"home":"beijing"}
print("name" in title)
print("jack" in title)

点击并拖拽以移动

运行结果:

True False

4.删除字典#

title = {"name":"jack","age":18,"home":"beijing"}
del title["name"]
print(title)
title.clear()
print(title)
del title

点击并拖拽以移动

运行结果:

{'age': 18, 'home': 'beijing'} {}

5.常见API#

title = {"name":"jack","age":18,"home":"beijing"}
print(len(title))
print(type(title))

点击并拖拽以移动

运行结果: 3 <class 'dict'>

把字典的字面量变成字符串,网络传输的时候,常常会把这种格式的字符串进行传输(JSON)

str1 = str(title)
print(str1,type(str1))

点击并拖拽以移动

运行结果: {'name': 'jack', 'age': 18, 'home': 'beijing'} <class 'str'>

6.字典的一些方法#

title = {"name":"jack","age":18,"home":"beijing"}
# 清空字典
title.clear()
print(title)

# 浅复制,存储地址不一样
# 因此更改其中一个不会对另外一个产生任何影响
title = {"name":"jack","age":18,"home":"beijing"}
str1 = title.copy()
print(str1)
print(id(title),id(str1))
str1["name"] = "mary"
print(str1,title)

# 获取字典中的数据
str2 = title.get("age")
print(str2)
str2 = title["age"]
print(str2)

# 若访问的键不存在,直接返回default的值
str2 = title.get("nn","None")
print(str2)

# 以可迭代对象来返回视图对象
items = title.items()
print(type(items))
for key,value in items:
    print(key,value)

# 返回键名
keys = title.keys()
for key in keys:
    print(key)

# 返回键值
values = title.values()
for value in values:
    print(value)

title_1 = {"name":"jack","age":18,"home":"beijing"}
title_2 = {"food":"vegetable"}
# 将title_2添加到title_1中
title_1.update(title_2)
print(title_1)

# 删除字典的某个键
title.pop("name")
# 也可以将age的值置空,但是键仍然占用空间
title["age"] = None
print(title)

点击并拖拽以移动

运行结果:

{} {'name': 'jack', 'age': 18, 'home': 'beijing'} 2594022048448 2594031191872 {'name': 'mary', 'age': 18, 'home': 'beijing'} {'name': 'jack', 'age': 18, 'home': 'beijing'} 18 18 None <class 'dict_items'> name jack age 18 home beijing name age home jack 18 beijing {'name': 'jack', 'age': 18, 'home': 'beijing', 'food': 'vegetable'} {'age': None, 'home': 'beijing'}

九、集合#

1.创建集合#

s1 = set()
print(s1)

# 传入数据是可迭代对象
# 自动排序
s2 = set([1,2,3,8,5])
print(s2)
s2 = set(range(5))
print(s2)

s3 = {10,20,30}
print(s3)

点击并拖拽以移动

集合中不存在相同元素并且元素需要是不可变类型

s4 = {10,20,(2,3),10,1}
print(s4)

点击并拖拽以移动

易混点

s5 = {(10)}

print(s5)

s6 = {(10,),(10,),}

print(s6)

点击并拖拽以移动

运行结果:

{10}

{(10,)}

只有在python中相等,比较的是元素的值而不是地址

x = (10,20)
y = (10,20)
print(x==y)
print(id(x)==id(y))

点击并拖拽以移动

2.案例#

假设有一万个数字,每一个数字代表张图片的类别,用集合来查看到底有多少种类别

x = [0,0,0,0,1,1,1,1,2,2,4,4,4,4,4,4,2,2,1,1,1,1,0,0,0,0,3,3,3,3,3,5,1,2,2,1]

print(set(x))

点击并拖拽以移动

3.固定集合#

不可以更改元素

s1 = frozenset([1,2,3,4,5,5,6])

print(s1)

点击并拖拽以移动

4.eval()函数#

常出现在企业级别的项目中,向项目中添加代码

str1 = "10+20"

eval(str1)

lst = [1, 5, 6, 4, 5, 2, 3]

str2 = "+".join(map(str, lst))  # 将整数转换为字符串

print(eval(str2))

点击并拖拽以移动

十、运算符#

1.逻辑运算符#

A and B

A是一个表达式,B也是一个表达式

如果bool(A)为False,那么B不运行,否则整个表达式的结果为B的结果

x1 = 100
x2 = 200
x3 = 0
x = x1 and x2
print(x)

x = x3 and x2
print(x)

点击并拖拽以移动

运行结果:

200 0

A or B

如果bool(A)为True,那么B不运行,否则整个表达式的结果为B的结果

x = x1 or x2
print(x)
x = x3 or x2
print(x)

点击并拖拽以移动

运行结果:

100 200

not A

如果bool(A)为True,那么not A的结果为False,否则not A的结果为True

x = not x1
print(x)
x = not x3
print(x)

点击并拖拽以移动

运行结果:

False True

2.位运算符#

x1 = 0b1010

x2 = 0b1100

# 默认输出十进制数

print(x1 & x2)#按位与

print(x1 | x2)#按位或

print(x1 ^ x2)#按位异或

print(~x1)#按位取反

点击并拖拽以移动

运行结果:

8

14

6

-11

x1 = x1^x2

x2 = x1^x2

x1 = x1^x2

print(x1,x2)

点击并拖拽以移动

运行结果:

12 10

左移运算符

左移运算符是将一个数字的二进制位全部左移若干位,高位丢弃,低位补0。

x1 = 0b1010

x2 = 2

print(x1 << x2)#左移运算符

点击并拖拽以移动

右移运算符是将一个数字的二进制位全部右移若干位,低位丢弃,高位补0。

右移运算符

x1 = 0b1010

x2 = 2

print(x1 >> x2)#右移运算符

点击并拖拽以移动

运行结果:

40

2

3.身份运算符#

a = 10
b = 10
print(a is b)  # True
print(a is not b)  # False

点击并拖拽以移动

4.成员运算符#

a = [1, 2, 3, 4, 5]
b = 3
print(b in a)  # True
print(b not in a)  # False

点击并拖拽以移动

5.三元运算符#

a = 10
b = 20
result = a if a > b else b
print(result)

点击并拖拽以移动

运行结果:

20

十一、表达式#

\1. 算术表达式

\2. 逻辑表达式

\3. 关系表达式

\4. 赋值表达式

\5. 条件表达式

\6. 位运算表达式

\7. 成员运算表达式

\8. 身份运算表达式

十二、语句#

标准的语句写法是每一个语句结束以后 用分号结尾

例如x = 10;,但是python不需要分号

语句分为单行语句和多行语句

1.if语句#

if 1 == 1:
    print("1 == 1")
else:
    print("1 != 1")

if 1 == 1:
    print("1 == 1")
elif 1 == 2:
    print("1 == 2")
else:
    print("1 != 1")

点击并拖拽以移动

2.循环语句#

# for循环
for i in range(2, 10,2):
    print(i)

# while循环
i = 1
while i <= 10:
    print(i)
    i += 1
else:
    print("循环结束")

# 死循环
# while True:
#     print("永远不会结束")

点击并拖拽以移动

3.break和continue语句#

# break语句
# break语句用于终止当前循环,并跳出循环体。
# python代码示例:

# 1. 无限循环
i = 0
while True:
    print(i)
    i += 1
    if i == 5:
        break

# 2. 条件循环
for i in range(10):
    if i == 5:   # 当i等于5时,跳出循环
        break
    print(i)
# continue语句
# continue语句用于跳过当前循环的剩余语句,直接开始下一轮循环。
# python代码示例:

for i in range(10):
    if i == 5:   # 当i等于5时,跳过当前循环的剩余语句,直接开始下一轮循环
        continue
    print(i)

点击并拖拽以移动

4.推导式#

# 列表推导式
x2 = [i**2 for i in range(1, 11) if i%2 == 0]
print(x2)
# 元组推导式
x3 = tuple(i**2 for i in range(1, 11))
print(x3)

# 字典推导式
key = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
x4 = {key[i]: i**2 for i in range(1, 11)}
print(x4)

# 集合推导式
x5 = {i**2 for i in range(1, 11)}
print(x5)

点击并拖拽以移动

运行结果:

[4, 16, 36, 64, 100] (1, 4, 9, 16, 25, 36, 49, 64, 81, 100) {'b': 1, 'c': 4, 'd': 9, 'e': 16, 'f': 25, 'g': 36, 'h': 49, 'i': 64, 'j': 81, 'k': 100} {64, 1, 4, 36, 100, 9, 16, 49, 81, 25}

5.with语句#

# with语句
with open("test.txt","r") as f:
  print(f)
  for line in f:
    print(line)
# with自动关闭文件


f = open("test.txt","r")
print(f)
for line in f:
  print(line)
f.close()# 手动关闭文件

点击并拖拽以移动

十三、函数#

1.声明函数#

def f1():
  print("f1运行")
f1()

def f2(x1,x2):
  print(x1+x2)
f2(5,6)

点击并拖拽以移动

return会让函数停止执行并返回结果

def f2(x1,x2):
  return x1+x2
a = f2(6,6)
print(a)

点击并拖拽以移动

运行结果:

f1运行 11 12

2.参数的数量和位置#

# 参数数量和位置一致
def add(a, b):
    # return a + b
    return b + a

print(add(2, 3)) # 5

# 参数数量不一致
# def add(a, b):
#     return a + b + c
# print(add(2, 3)) # 语法错误,缺少参数c

点击并拖拽以移动

3.关键字参数#

先定义默认值,然后再调用时传入关键字参数

def my_func(a, b, c=0, d=0):
    return a + b + c + d

print(my_func(1, 2, 3, 4)) # 10
print(my_func(1, 2, d=4)) # 6

点击并拖拽以移动

4.元组解包参数#

def fn(a,b,c,*args):
  print(a,b,c)
  print(args,type(args))
fn(1,2,3)
fn(5,3,6,8,9,5,4,8)

def fn(*args):
  # 任意传几个参数
  print(*args)

fn(5,6,8)

点击并拖拽以移动

运行结果:

1 2 3 () <class 'tuple'> 5 3 6 (8, 9, 5, 4, 8) <class 'tuple'> 5 6 8

5.字典解包参数#

def fn(a,b,**args):
  print(a,b)
  print(args,type(args))

fn(20,30)
fn(10,20,name="jack",age = "18")

点击并拖拽以移动

运行结果:

20 30 {} <class 'dict'> 10 20 {'name': 'jack', 'age': '18'} <class 'dict'>

**args 与 *kwargs一起使用,可以接收任意数量的位置参数和关键字参数。

def my_func(*args, **kwargs):
    print(args)
    print(kwargs)

my_func(1, 2, 3, a=4, b=5)  

点击并拖拽以移动

运行结果:

(1, 2, 3) {'a': 4, 'b': 5}

只要是有下标的参数都可以解包

# 列表也可以解包
my_list = [1, 2, 3]
my_func(*my_list)  # 解包
# 也可以用字典解包
my_dict = {'a': 1, 'b': 2, 'c': 3}
my_func(**my_dict)  # 解包
# 元组也可以解包
my_tuple = (1, 2, 3)
my_func(*my_tuple)  # 解包
# 字符串也可以解包
my_str = '123'
my_func(*my_str)  # 解包

点击并拖拽以移动

6.占位符#

def my_func(x, *, y):
  # *是一个占位符,他后面的参数必须是关键字参数
  print(x, y)
# my_func(1,2)报错,缺少关键字参数y
my_func(1, y=2)

点击并拖拽以移动

7.匿名函数lambda#

fn=lambda x,y:x+y
print(fn(2,3))

fn = lambda x:"奇数" if x%2==1 else "偶数"
print(fn(11))
print(fn(2))

点击并拖拽以移动

案例1:判断是否是闰年

def is_leap(year):
  if (year%4)==0 and (year%100)!=0:
    return True
  elif (year%400)==0:
    return True
  else:
    return False
print(is_leap(2024))

点击并拖拽以移动

案例2:按比例划分数据集

def train_test_split(data,train_size = 0.8):
    train_data = data[:int(len(data)*train_size)]
    test_data = data[int(len(data)*train_size):]
    return train_data,test_data
#测试
data = [1,2,3,4,5,6,7,8,9,10]
train_data,test_data = train_test_split(data,0.8)
print(train_data)
print(test_data)

点击并拖拽以移动

运行结果:

[1, 2, 3, 4, 5, 6, 7, 8] [9, 10]

函数分为三种:

官方内置函数,第三方函数,自己写的函数

8.官方内置函数#

# all传入的参数全部为True就返回True
x = [-10,0,30,-2]
re = all(x)
print(re)
# any只要有一个为True就返回True
print(any(x))
# sum(x)对x求和
print(sum(x))
# sorted(x)排序,key = fn表示按照函数返回值排序
def fn(x):
  return x**2
print(sorted(x,key = fn))
# reverse(x)反转,返回一个可迭代对象
print([i for i in reversed(x)])
# callable(x)检测x标识符是不是能够当函数调用
fn = 100
print(callable(fn))
fn = lambda x,y:x+y
print(callable(fn))
# zip(x,y)将x,y两个数据容器组合成一个可迭代对象,打包成元组
x = [10,20,30,40,50]
y = [40,50,60]
print([i for i in zip(x,y)])
# exec()将传入的字符串中的代码执行
exec("print('hello')")

点击并拖拽以移动

运行结果:

False True 18 [0, -2, -10, 30] [-2, 30, 0, -10] False True [(10, 40), (20, 50), (30, 60)] hello

9.globals和locals()#

globals()返回值是一个字典,字典的key就是当前python环境全局变量的名字

x = 10
y = 20
print(globals())

点击并拖拽以移动

运行结果是一大串字典

locals()返回值是一个字典,字典的key就是当前函数的局部变量的名字

def fn(x,y):
  print(locals())
fn(1,2)

点击并拖拽以移动

运行结果:

{'x': 1, 'y': 2}

10.filter函数#

filter(函数,可迭代对象),传入两个参数:函数和可迭代对象,返回一个经过函数筛选后的可迭代对象

x = [1,2,2,3,5,6,4,8,5,2]
x2 = filter(lambda el:el%2==1,x)
print(list(x2))

点击并拖拽以移动

实现:

def myfilter(fn,x):
  x2 = []
  for i in x:
    if fn(i) ==True:
      x2.append(i)
    else:
      continue
  return x2
def fn(x):
  if x%2==0:
    return True
  else:
    return False
re = myfilter(fn,[1,2,2,3,5,6,4,8,5,2])
print(re)

点击并拖拽以移动

运行结果:

[2, 2, 6, 4, 8, 2]

11.map函数#

map(函数,可迭代对象),与filter不同的是不需要进行筛选,直接经过函数映射到可迭代对象中

x = [1,2,2,3,5,6,4,8,5,2]
def fn(x):
  return x**2
print(list(map(fn,x)))

点击并拖拽以移动

实现

def mymap(fn,x):
  x2 = []
  for i in x:
    x2.append(fn(i))
  return x2
def fn(x):
  return x**2
re = mymap(fn,[1,2,2,3,5,6,4,8,5,2])
print(re)

点击并拖拽以移动

运行结果:

[1, 4, 4, 9, 25, 36, 16, 64, 25, 4]

12.reduce函数#

reduce(函数,可迭代对象,初始值)

reduce()函数会对可迭代对象中的元素进行累积操作,并将结果作为第一个参数传递给函数,然后再将结果和第二个参数传递给函数,以此类推,直到可迭代对象中的所有元素都被处理完。最后,reduce()函数返回累积结果。

from functools import reduce
x = [1,2,4,3,5,6,4,8,5,2]
def fn(x1,x2):
  print(x1,x2,"=====")
  return x1+x2

reduce(fn,x)

点击并拖拽以移动

实现:

def myreduce(fn,x,start):
  x1 = fn(start,x[0])
  for i in range(len(x)-1):
    x1 = fn(x1,x[i+1])
  return x1
  # 简洁版 
  # def myreduce(fn,x,start):
  # re = start
  # for i in x:
  #   re = fn(re,i)
  # return re

def fn(x1,x2):
  print(x1,x2,"=====")
  return x1+x2
x = [1,2,4,3,5,6,4,8,5,2]
myreduce(fn,x,0)

点击并拖拽以移动

运行结果:

0 1 ===== 1 2 ===== 3 4 ===== 7 3 ===== 10 5 ===== 15 6 ===== 21 4 ===== 25 8 ===== 33 5 ===== 38 2 =====

13.作用域#

作用域只针对函数,函数内部可以访问函数内部和外部的变量,但是函数外部不能访问函数内部的变量

a = 100
def fn():
  q = 10
  a = 20#内层有a,访问内层作用域的a,外层没有,就去外层的外层,如果都没有就报错
  print(a)
  print(q)
  return a+q
print(fn())# 每次调用函数内部都会产生一个作用域,调用完毕后,内部创建数据使用的内存销毁
print(a)
# print(q)报错

点击并拖拽以移动

运行结果:

20 10 30 100

b = [1,2,3,4,5,lambda x:x+1]
print(b[5](5))

点击并拖拽以移动

运行结果:

6

函数调用在A作用域 定义在B作用域,函数无论在哪个作用域中执行,一定是他定义的作用域下执行代码

a = 100
def fm():
  print(a)

def fn():
  a = 200
  fm()

fn()

点击并拖拽以移动

运行结果:

100

函数也是一种数据

def f1():

  a = 100

  def f2():

    print(a)

  return f2

a = 200

re = f1()

re()# 执行函数

点击并拖拽以移动

作用域案例:

def fun(n = None,o = None):
  print(o)
  return {"fun":lambda m:fun(m,n)}

a = fun(0)
a["fun"](1)
a["fun"](2)
a["fun"](3)

b = fun(0)["fun"](1)["fun"](2)["fun"](3)

c = fun(0)["fun"](1)
c["fun"](2)
c["fun"](3)

点击并拖拽以移动

运行结果:

None 0 0 0 None 0 1 2 None 0 1 1

14.修改变量值#

# def fn():
#   print(a)
#   a = 2
# fn()报错

a = 10
def fn():
  global a#声明全局变量
  print(a)
  a = 20#会访问全局变量a的值
fn()
print(a)


a = 10
def fn():
  global a
  a = 20
  def fm():
    global a
    print(a)#访问和修改全局作用域“a = 10”这个a
    a = 30
  fm()
fn()


a = 10
def fn():
  a = 20
  def fm():
    nonlocal a#访问和修改外层作用域“a = 20”这个a
    print(a)
    a = 30
  fm()
fn()

点击并拖拽以移动

运行结果:

10 20 20 20

15.内建作用域#

print(__name__)

点击并拖拽以移动

运行结果:

main

16.递归#

def f(a):
  if a > 5:
    return a
  else:
    return f(a+1)

r = f(0)
print(r)

点击并拖拽以移动

运行结果:

6

函数返回值是一种数据,函数也是一种数据

def fn():
  return 1+1
print(type(fn))
print(type(fn()))

点击并拖拽以移动

运行结果:

<class 'function'> <class 'int'>

16.回调函数 callback#

把一个函数传入另外一个函数,传入的函数就是回调函数

定义一个工具函数,传入两个数和一个函数,调用传入的函数并返回结果

a,b可以是数据也可以是字符串,func必须是函数

# 定义两个函数
def add(a,b):
  return a+b
def sub(a,b):
  return a-b
def calculate(a,b,func):
  return func(a,b)

# 传进去的add就是回调函数
print(calculate(5,3,add)) # 8
print(calculate(5,3,sub)) # 2

点击并拖拽以移动

回调函数怎么体现:

遍历:把一个数据容器中的数据全部拿出来调用

设计一个工具函数:遍历列表中的所有元素,找出奇数拿来使用,但是这个工具自己并不适用

而是交给业务函数(回调)使用

def find_odd(arr,cb):
  for el in arr:
    if el%2==1:
      cb(el)

x = [2,5,6,8,9,7]
def print_odd(el):
  print("找到一个奇数:",el)
find_odd(x,print_odd)
find_odd(x,lambda m:print(m**2))

点击并拖拽以移动

运行结果:

找到一个奇数: 5 找到一个奇数: 9 找到一个奇数: 7 25 81 49

17.闭包函数 block#

函数内部有函数,内部的那个函数就是闭包函数

1.由于函数有作用域,而且多个函数的作用域是相互独立的

使用闭包函数把函数的值单独保存,让变量不要相互污染

2.由于函数调用和定义的作用域可以不是同一个,并且函数调用时是在定义的作用域中执行的

因此闭包函数可以在函数外部访问函数内部的变量

def alipay():
  money_in = 100
  def tool():
    money_in = 300
    print(money_in)
  return tool
re = alipay()
re()
money_out = 200
print(money_out)
# print(money_in) 报错并没有更改程序内部的money,而是外部变量的money

点击并拖拽以移动

案例

# 案例
def alipay():
  money1 = 200
  def tool(pwd,new_money):
    nonlocal money1
    if pwd == 123:
      money1 = new_money
    print(money1)

  def withdraw(pwd,amount):
    # 取钱
    nonlocal money1
    if pwd == 123:
      money1 -= amount
    print(money1)

  return tool,withdraw


def meituan():
  tool,withdraw = alipay()
  tool(123,666)
  # fn(321,777)

  withdraw(123,50)
meituan()

点击并拖拽以移动

运行结果:

666 616

十四、装饰器#

参考:一文搞懂Python装饰器(通俗易懂) - 知乎

装饰器相当于一个闭包的调用,但是不同的是相较于Alipay的案例,不需要多余构建re变量,直接用@装饰器名字的方式来调用,相当于一种方便的写法

装饰器本质是回调函数和闭包函数的结合

装饰器本身是一个函数,把装饰的函数作为参数输入,然后吧调用封装在内部的闭包中,返回值那个闭包

不带参数的装饰器

def fn():
  print("fn函数的业务是答应一句话:未来业务可能有很多行代码")


# 设计一个装饰器

def decorator(cb):
  def block1():
    print("装饰器执行的代码:怎么装饰由业务决定")
    cb()
    print("装饰器可以继续装饰:怎么装饰由业务决定")
  return block1

@decorator
def fn2():
  print("fn2函数的业务是打印一句话:未来就是具体业务代码")

fn2()

点击并拖拽以移动

运行结果:

装饰器执行的代码:怎么装饰由业务决定 fn2函数的业务打印是一句话:未来就是具体业务代码 装饰器可以继续装饰:怎么装饰由业务决定

带参数的装饰器:

# 带参数的装饰器
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before calling the function")
        func(*args, **kwargs)
        print("After calling the function")
    return wrapper

@my_decorator
def my_function(x, y):
    print("The sum of", x, "and", y, "is", x+y)
    return x + y

my_function(2, 3) # Output: 5  

点击并拖拽以移动

运行结果:

Before calling the function The sum of 2 and 3 is 5 After calling the function

作用:

  1. *日志记录*:在函数执行前后自动添加日志记录,方便调试和监控程序行为。
  2. *性能测试*:装饰器可以用来测量函数的执行时间,帮助识别性能瓶颈。
  3. *权限验证*:在Web开发中,装饰器可以用于检查用户是否有权访问某个资源或执行特定操作。
  4. *缓存*(Memoization):通过装饰器实现函数结果的缓存,避免重复计算相同的输入值,从而提高效率。

十五、面向对象#

1.类和对象的语法#

定义一个类

class Person:
  name = "张三"
  age = 18
  life = 1

  def fn(self,num):
    print("类中的函数叫做方法,参数是",num)

print(Person,type(Person))

点击并拖拽以移动

用这个类创造对象

p1 = Person()
print(p1,type(p1))

点击并拖拽以移动

对象内部保存了很多数据,想要访问需要通过成员名

语法:对象名.成员名

print(p1.name,p1.age,p1.life)

p1.fn(1)


p2 = Person()
p2.fn(2)

点击并拖拽以移动

运行结果:

<class '__main__.Person'> <class 'type'> <__main__.Person object at 0x00000187F9C19940> <class '__main__.Person'> 张三 18 1 类中的函数叫做方法,参数是 1 类中的函数叫做方法,参数是 2

2.init#

实用类创建对象时,可以初始化对象的成员的值

但是在Python当中__init__并不是构造函数,__new__才是

__init__是一个魔术方法,是一个特殊的函数,会在创建对象时调用

class Teacher:
  # 类名(10,20)的10和20会传给__init__函数的参数
  def __init__(self,name,age):
    print("__init__ name:",name,"年龄:",age)
    self.n = name# 给t1对象添加一个属性,属性名是n,属性中保存的值是:“xiaoming”,相当于赋值
    self.a = age
    

  def fn(self,name,age):
    print("fn name:",name,"年龄:",age)

t1 = Teacher("xiaoming",18)
t1.fn("xiaoming",18)
t1.a

点击并拖拽以移动

运行结果:

init name: xiaoming 年龄: 18 fn name: xiaoming 年龄: 18

类每次创建对象时,创建对象有同样的属性和方法,而有一部分是创建的时候赋的值,有一部分创建的时候值一样

class Game_person:
  life = 1
  def __init__(self,name,rank):
    self.name = name#前一个name是self的属性,后一个name是函数内部的一个变量
    self.rank = rank

# 可以创建很多个
g1 = Game_person("boss",2000)
g2 = Game_person("npc",100)
print(g1.name,g1.rank)
print(g2.name,g2.rank)

点击并拖拽以移动

运行结果:

boss 2000 npc 100

3.对象语法#

class Box:
  x = 100
  def __init__(self,y):
    self.y = 200
  
  def change_y(self,new_y):
    print("调用函数前",self.y )
    self.y = new_y
    print("调用函数后",self.y )

b1 = Box(99)
b1.x = 200
print(b1.x)#只修改了b1的x值

b2 = Box(98)
print(b2.x)#b1的x值不变

b3 = Box(97)
print(b3.y)#这里y还是200

# 修改y的值,这里只修改b3的值,b1,b2不受影响,但是b1,b2也可以调用这个方法来修改值
# 第一种直接修改:
b3.y = 1
print("直接修改后",b3.y)
# 第二种常见一个修改y的函数来修改self.y:
b3.change_y(2)
print(b3.y)

点击并拖拽以移动

运行结果:

200 100 200 直接修改后 1 调用函数前 1 调用函数后 2 2

4.对象的方法内部可以操作这个对象的属性和方法#

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hello(self):
        print("Hello, my name is {} and I am {} years old.".format(self.name, self.age))

p1 = Person("Alice", 25)
p1.say_hello()

点击并拖拽以移动

运行结果:

Hello, my name is Alice and I am 25 years old.

5.对象的方法可以传入参数,也可以返回值。#

class Box:
  count = 100
  def __init__(self,m):
    self.m = m
  def cal_total(self,price):
    return self.count*self.m*price
  
b1 = Box(45)
re = b1.cal_total(108)
print(re)

点击并拖拽以移动

运行结果:

486000

案例1

假设有一个ATM类 用这个类创建出来的对象就是一个取款机对象

atm对象有一个属性 是一个列表 里面装了很多对象,每一个对象就是一个Person类型的对象

有一个属性 是一个数字 保存了余额

有一个方法可以往ATM里面添加Person对象

class Person:
  def __init__(self,name,card_num,phone_num):
    self.name = name
    self.card_num = card_num
    self.phone_num = phone_num

class ATM:
  money = 5000
  persons = []
  def add_person(self,person):
    if person not in self.persons:
      self.persons.append(person)
      print("添加成功")
    else:
      print("该卡号已存在")

atm = ATM()
person1 = Person("张三","123456","13800138000")
person2 = Person("李四","654321","13800138001")
atm.add_person(person1)
atm.add_person(person2)
print(atm.persons[0].name)
print(atm.persons[0].card_num)
print(atm.persons[0].phone_num)

点击并拖拽以移动

运行结果:

添加成功 添加成功 张三 123456 13800138000

案例2:

公司员工管理系统

设计一个公司员工管理系统,包含以下内容:

\1. 定义一个 Employee 类,包含以下属性:

- name(姓名)

- position(职位)

- salary(薪水)

\2. 定义一个 Company 类,包含以下内容:

- 一个列表属性,用于存储 Employee 对象。

- 一个方法 hire_employee,用于招聘新员工。

- 一个方法 fire_employee,根据员工的姓名,解雇该员工。

- 一个方法 list_employees,用于列出公司中所有员工的信息。

- 一个方法 total_salary,计算公司所有员工的总薪水。

\3. 测试代码:

- 创建一个 Company 对象。

- 招聘几个员工。

- 列出所有员工。

- 解雇一个员工。

- 再次列出所有员工。

- 打印公司总薪水。

class Employee:
  def __init__(self,name,position,salary):
    self.name = name
    self.position = position
    self.salary = salary

class Company:
  Employee_lst = []

  def hire_employee(self,Employee):
    if Employee not in self.Employee_lst:
      self.Employee_lst.append(Employee)
    else:
      print("已经添加该员工")

  def list_employees(self):
    for Employee in self.Employee_lst:
      print("name:",Employee.name,"position:",Employee.position,"salary:",Employee.salary)

  
  def total_salary(self):
    salary_total = []
    for Employee in self.Employee_lst:
      salary_total.append(int(Employee.salary))
    return sum(salary_total)

person1 = Employee("张三","经理","5000")
person2 = Employee("李四","客服","3000")
person3 = Employee("王五","地推","1000")

ali = Company()
ali.hire_employee(person1)
ali.hire_employee(person2)
ali.hire_employee(person3)

ali.list_employees()

salary = ali.total_salary()
print(salary)

点击并拖拽以移动

运行结果:

name: 张三 position: 经理 salary: 5000 name: 李四 position: 客服 salary: 3000 name: 王五 position: 地推 salary: 1000 9000

6.类属性和类方法#

class qox:
  x = 100#他是一个类属性,这个类创建出来的实例也能访问
  def fn(self):
    print(qox.x)

# 两种调用方式
print(qox.x)
b1 = qox()
print(b1.x)

b1.x = 500
print(b1.x)#被更改
print(qox.x)#没有被更改,说明类自己本身也是一种数据容器
b1.fn()

点击并拖拽以移动

运行结果:

100 100 500 100 100

7.类属性和类方法#

它接收类本身作为第一个参数(通常命名为 cls),而不是实例(self)。

类方法可以访问类的属性和方法,但不能访问实例的属性

类变量是在类的定义中直接定义的变量,而不是在类的 init 方法或其他实例方法中定义的。

类变量属于类本身,而不是属于类的某个实例

class qox:
  x = 100#他是一个类属性,这个类创建出来的实例也能访问
  def fn(self):
    print(qox.x)

# 两种调用方式
print(qox.x)
b1 = qox()
print(b1.x)

b1.x = 500
print(b1.x)#被更改
print(qox.x)#没有被更改,说明类自己本身也是一种数据容器
b1.fn()

点击并拖拽以移动

显式的指定类方法

class Box:
  x = 100
  def __init__(self,y):
    self.y = y
  def fn(self):
    print(self.x)
  
  @classmethod
  def fm(cls):
    print("fm被调用")
    print(cls.x)

b1 = Box(100)
# b1对象可以使用的成员:x,y属性,y方法 fn方法,fm方法
print(b1.x)
print(b1.y)
b1.fn()
b1.fm()

# Box可以直接访问fm
Box.fm()

点击并拖拽以移动

案例:类方法常可以作为工厂方法

class single:
  instance = None
  
  # 类方法:
  @classmethod
  def share_instance(cls):
    if cls.instance is None:
      cls.instance = single() 
      return cls.instance
    else:
      return cls.instance
    
s1 = single.share_instance()
s2 = single.share_instance()
# 两个是一样的
print(s1)
print(s2)

o1 = single()
o2 = single()
# 两个是不同的
print(id(o1))
print(id(o2))

点击并拖拽以移动

批量创建对象

class student:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  
  @classmethod
  def create_students(cls,num):
    arr = []
    for i in range(num):
      arr.append(cls(f"student{i}", i))
    return arr

# 直接创建两个学生对象
s1 = student("Alice", 20)
s2 = student("Bob", 21)
print(s1.name, s1.age)
print(s2.name, s2.age)

# 先初始化好学生数量,再去更改学生的属性
students = student.create_students(10)
students[0].name = "jack"
students[0].age = 22
print(students[0].name, students[0].age)

点击并拖拽以移动

8.静态方法#

静态方法通常用于实现一些与类无关的工具函数,这些函数不需要访问类或实例的属性。

它们可以被类或实例调用,但不会影响类或实例的状态。

class Box:
  count = 0
  def fn(self):
    print("fn普通方法")
  @classmethod
  def fm(cls):
    print("fm类方法")
  @staticmethod
  def fz():
    print("fn静态方法")
  @staticmethod
  def sigmod(x):
    return 1.0/(1.0+math.exp(-x))

Box.fm()
Box.fz()

b1 = Box()
b1.fz()

re = Box.sigmod(10)
print(re)

点击并拖拽以移动

9.构造方法#

静态方法__new__ 方法负责创建并返回类的新实例,而 init 方法则用于初始化实例。

class Box:
  def __new__(self):
    print(self)
    return super().__new__(self)
  def __init__(self):
    self.width = 0

b1 = Box()
print(b1.width)
print(b1,Box)

点击并拖拽以移动

10.魔术方法#

class Person:
  # 初始化方法
  def __init__(self, name, age):
    self.name = name
    self.age = age

  # 打印方法
  # 打印对象时,会调用该方法
  # 该方法返回一个字符串,表示对象的信息
  def __str__(self):
    return f"Person(name={self.name}, age={self.age})"
  
  # 
  def __repr__(self):
    # 该方法返回一个字符串,表示对象的信息
    # 该字符串可以被eval()函数解析,得到一个与该对象相同的对象
    # 该方法的作用是方便调试
    return f"Person(name={self.name}, age={self.age})"
  
  def __delitem__(self):
    # 删除对象时,会调用该方法
    print("删除对象")
    del self.name

  def __add__(self, other):
    # 实现两个对象相加,可以自己定义对象与对象的相加规则
    # 该方法返回一个新的对象
    return Person(f"{self.name}+{other.name}", self.age + other.age)
  
  def __sub__(self, other):
    # 实现两个对象相减,可以自己定义对象与对象的相减规则
    # 该方法返回一个新的对象
    return self.age - other.age
  
  def __iter__(self):
    # 实现对象可迭代,可以用for循环遍历对象
    # 该方法返回一个迭代器对象
    return iter([self.name, self.age])

# 创建对象
p = Person("Alice", 25)

# 打印对象
print(p)

# 调用__repr__方法
print(repr(p))

# 调用__delitem__方法
# del p.name
# 再次打印对象  
# print(p) 'Person' object has no attribute 'name'

# 调用__add__方法
p2 = Person("Bob", 30)
p3 = p + p2#这里的+号调用的是__add__方法
print(p3)

# 调用__sub__方法
print(p2 - p)

# 调用__iter__方法
print(type(p))
for item in p:
  print(item)

点击并拖拽以移动

11.比较常用的魔术方法#

class Images:

  def __init__(self,path):
    self.path = path
    self.arr = ["6.jpg","5.jpg","4.jpg","3.jpg","2.jpg","1.jpg"]

  def __len__(self):
    return len(self.arr)#由自己决定的返回

  def __getitem__(self,index):
    print(index)
    return self.arr[index]#利用传入的下标进行操作
  
  def __setitem__(self,index,value):
    print(index,value)

  def __call__(self, *args, **kwargs):
    print("调用了__call__方法",args,kwargs)

  
  
  
imgs = Images("./imgs")
count = len(imgs)
print(count)#自动调用__len__

# 调用__getitem__
# print(imgs[100]) 报错,arr越界了
print(imgs[2])

# 调用__setitem__
print("===========")
imgs[1] = 2
print("===========")
print("__setitem__",imgs[1])

# 调用__call__
imgs(1,2,3,a=1,b=2)

点击并拖拽以移动

12.继承#

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(f"{self.name}今年{self.age}岁,正在吃饭")
  
p1 = Person("张三", 20)
p1.eat()

class Student(Person):
    # 子类构造函数中必须调用父类构造函数
    # 否则无法调用父类属性
    def __init__(self, name, age, school):
        # 调用父类构造函数
        # 必须在子类构造函数的第一行调用
        super().__init__(name, age)
        self.school = school

s1 = Student("李四", 21, "清华大学")
s1.eat()
print(s1.school)

点击并拖拽以移动

运行结果:

张三今年20岁,正在吃饭 李四今年21岁,正在吃饭 清华大学

13.覆盖-重写#

父类已经定义了一个方法,子类要将这个方法重新修改,就叫重写

class Animal:
  def __init__(self,name):
    self.name = name
  
  def eat(self):
    print("Animal的eat方法,{} is eating".format(self.name))

  def sleep(self):
    print("Animal的sleep方法,{} is sleeping".format(self.name))

class Dog(Animal):
  def __init__(self, name,age):
    super().__init__(name)
    self.age = age

  def say(self):
    print("Dog的say方法,{} is barking".format(self.name))

  def eat(self):
    print("Dog重写了Animal的eat方法,{} is eating".format(self.name))

dog = Dog("旺财", 3)
print(dog.name)
print(dog.age)
dog.sleep()
dog.say()
dog.eat()

点击并拖拽以移动

14.多台#

class Animal:
    def eat(self):
        print("动物会吃东西")

class Dog(Animal):
    def eat(self):
        print("狗会吃骨头")

class Cat(Animal):
    def eat(self):
        print("猫会吃鱼")

def eat(animal):
    animal.eat()# 体现了多态

dog = Dog()
cat = Cat()

eat(dog) 
eat(cat)

# 看dog是否是Dog或他的父类的实例
print(isinstance(dog, Animal))
print(isinstance(dog, Dog))

点击并拖拽以移动

15.私有属性#

不同于类属性,在属性前面加__表示只能在类中调用这个属性

class Person:
    __name = 'jack'
    def __init__(self, __age):
        self.__age = __age
    def fn(self):
        print("私有属性只能在类内部访问")
        print("私有属性:", self.__name)
        print("私有属性:", self.__age)

p = Person(25)
# print(p.__name)  # 报错
# print(p.__age)  # 报错
p.fn()  # 通过实例化对象调用私有方法,可以在类内部访问私有属性和方法

点击并拖拽以移动

16.重载魔术方法#

下面重新定义了Python中的加减乘除,实质就是改写了底层的魔术方法

class Box:
  def __init__(self, width, height):
    self.width = width
    self.height = height

  def __add__(self, other):
    return self.width + self.height + other.width + other.height
  
  def __sub__(self, other):
    return self.width - self.height - other.width - other.height
  
  def __mul__(self, other):
    return self.width * self.height * other.width * other.height
  
  def __truediv__(self, other):
    return self.width / self.height / other.width / other.height
  
  def __floordiv__(self, other):
    return self.width // self.height // other.width // other.height
  

b1 = Box(2, 3)
b2 = Box(4, 5)

print(b1 + b2)
print(b1 - b2)
print(b1 * b2)
print(b1 / b2)
print(b1 // b2)

点击并拖拽以移动

17.super()方法#

class Box:
  x = 5
  def fn(self):
      print("这是Box类的fn方法")

  def fm(self):
      print("这是Box类的fm方法")

class Box2(Box):
  # 重写父类的fn方法 
  x = 10
  def fn(self):
      super().fn()
      print("这是Box2类的fn方法")
      super().fm()
      print("这是Box2类的fm方法")

b = Box2()
b.x = 400
super(Box2, b).fn()  # 这是b对象调用父类的fn方法
# 总结:执行Box2父类的fn()函数 把b2作为第一个参数self传入进去
super(Box2, b).x

点击并拖拽以移动

十六、迭代器和生成器#

1.迭代器iter#

全局函数iter 可以把一个可迭代对象转换成一个迭代器,全局函数next 他可以迭代下一次迭代器中的数据,for 循环可以连续调用next

arr = [10,20,30,40,50]
iterator = iter(arr)
re1 = next(iterator)
print(re1)

re2 = next(iterator)
print(re2)

re3 = next(iterator)
print(re3)

for el in iterator:
  # 接着re3迭代
  print(el,"====================")

# re4 = next(iterator)
# print(re4)#报错,re3已经迭代完了

点击并拖拽以移动

案例:

实现数据加载器的底层核心源代码,有一个数据容器,里面有1000条数据,封装一个可迭代对象,这个对象迭代一次就取出这个列表的n条数据,n = 8

class myData:
    def __init__(self,data):
        self.data = data
        self.index = -1
    def __iter__(self):
        return self
    def __next__(self):
        while self.index < len(self.data)//8:
          self.index += 1
          return self.data[self.index * 8:(self.index+1) * 8]

data = myData(["a", "b", "c", "d", "e", "f", "g", 
        "h", "i", "j", "k", "l", "m", "n",
        "o", "p", "q", "r", "s", "t", "u", 
        "v", "w", "x", "y", "z"])


data_loader = iter(data)
re = next(data_loader)
print(re)
re = next(data_loader)
print(re)
re = next(data_loader)
print(re)

点击并拖拽以移动

2.生成器yield#

yield关键字在函数内部 会让函数暂时生成结果,但是函数还没有运行完毕,并且这个函数调用的代码的后面的代码会正常执行

def my_gen():
    print("start")
    yield 1
    print("middle")
    yield 2
    print("end")
    yield 3

re = my_gen()
print(next(re),"===========") 
# re = my_gen()
print(next(re),"===========")
# re = my_gen()
print(next(re),"===========")
# 结束迭代
# re = my_gen()
# print(next(re),"===========")

点击并拖拽以移动

案例:

实现range函数源代码

def myrange(start,end,step):
    i = start - step
    while True:
      i += step
      if i >= end:
        # raise StopIteration
        break
      yield i

for el in myrange(0,11,2):
   print(el)

点击并拖拽以移动

十七、异常处理#

try:
    arr = [100,20]
    x = arr[100]
    print(x)

except ValueError:
    print("数组类型错误",ValueError)

except IndexError as e:
    print("数组越界",e)

else:
    print("没有异常")

finally:
    print("不管有没有报错都执行finally")

print("后面的代码")

点击并拖拽以移动

运行结果:

数组越界 list index out of range 不管有没有报错都执行finally 后面的代码

常见的几种except选项:

| ZeroDivisionError | 除(或取模)零 (所有数据类型)  |
| ----------------- | ---------------------------- |
| ValueError        | 传入无效的参数               |
| AssertionError    | 断言语句失败                 |
| StopIteration     | 迭代器没有更多的值           |
| IndexError        | 序列中没有此索引(index)      |
| IndentationError  | 缩进错误                     |
| OSError           | 输入/输出操作失败            |
| ImportError       | 导入模块/对象失败            |
| NameError         | 未声明/初始化对象 (没有属性) |
| AttributeError    | 对象没有这个属性             |

点击并拖拽以移动

或者直接不写这个错误类型

try:
    print(3 / 0)
except:
    print("报错")
else:
    print("没错")

点击并拖拽以移动

运行结果:

报错

主动抛出错误:

def fn():
    x = 10
    if 5<x<6:
        print(x)
    else:
        raise ValueError("x不在范围内")
try:
    fn()
except ValueError as e:
    print(e)
print("后续代码")

点击并拖拽以移动

运行结果:

x不在范围内 后续代码

十八、模块与包#

import model1 as m1
from model2 import area
from model2 import perimeter as peri

print(m1.is_prime(7))
print(m1.is_palindrome("racecar"))

print(area(5, 6))
print(peri(5, 6))

点击并拖拽以移动

1. file__和__name#

这两个全局变量保存的是字符串

print(__file__)# 保存的是当前文件路径
print(__name__)# 保存当前模块名
# 当运行这个Python文件,如果是入口程序

点击并拖拽以移动

运行结果:

d:\桌面\华清\基础语法\code\Python基础语法\21-模块与包.py main

十九、内置函数#

import random
import time
import os
if __name__ != "__main__":
    # 随机数
    # random.seed(42)
    re1 = random.random()
    print("re1",re1)
    # 随机整数
    re2 = random.randint(-5,6)
    print("re2",re2)
    # 随机取出
    arr = [1,2,3,4,5,6,7,8,9]
    re3 = random.choice(arr)
    print("re3",re3)
    # 打乱列表
    re4 = random.shuffle(arr)
    print("re4",re4)#返回None
    print(arr)

    # time 模块
    def time_fn():
        t = time.time()
        print(t)

    for i in range(3):
        time_fn()
        time.sleep(1)#每次循环时间间隔5秒
        print(time.localtime())#获取时间信息
        print(time.localtime().tm_mday)#具体到某一项
        print(time.strftime("%y年%m-%d %H:%M:%S"))#格式化时间格式

# os 模块用于操作计算机的一些东西
def os_fn():
    path = os.getcwd()#获取当前文件夹地址
    print(f"====={path}=======")
    # 绝对路径
    re = os.path.join(path,"./img","a.jpg")
    print(re)
    # 相对路径
    re1 = os.path.realpath(re)
    print(re1)
    # 创建文件夹
    os.mkdir("./code/img")


if __name__ == "__main__":
    # os模块
    os_fn()


    

点击并拖拽以移动

总结#

大纲已完结,后续会有补充