特性四:函数的闭包

1.什么是闭包
格式:
函数的嵌套结构,内部函数使用了外部的成员
外部函数执行完毕需要弹栈时,内部函数制约了外部函数的局部变量销毁
def outer():
username = "zhangsan"
# 封装一个内部函数
def inner():
password = "111"
print(f"username:{username}, password:{password}")
# 返回这个内部函数,内部函数变成外部的返回值
return inner
res = outer()
print(res) # 应该要打印inner内部函数的地址
res() # 可以调用内部函数
2.闭包的优缺点
python不建议自行使用闭包
优点:提升函数局部变量的作用域--函数的局部变量不能销毁--->全局变量
缺点:局部变量不能随函数调用而销毁造成的垃圾问题
特性五:装饰器(难)
函数装饰器
闭包的概念是学装饰器的基础
装饰器:--- 不改变原有代码
本质就是一个函数-特性为其提供一个函数参数返回一个增强后的函数
装饰器推导:
需求1:在操作用户时,为其增加日志功能
解决:为每个功能添加日志模块
需求2:在操作用户时,在功能执行前后都去添加日志功能
问题:改动太大,代码冗余
解决:抽取函数
问题:代码还是重复内容过多,考虑在不改变原有代码的情况下,能不能实现功能增强解决
以参数为函数传递,并在日志内部执行函数,在执行之前和之后进行日志输出
问题:被调用者发生改变,原有代码变动了?
解决:继续修改log函数,以函数作为参数传递,返回一个新函数,新函数与原有函数同名
# 添加1:抽去一个日志函数
def log(fn):
def inner():
print("log..before")
fn()
print("log..after")
return inner
def add_user():
print("add..user..")
add_user = log(add_user) # 添加2:增加用户的调用
add_user()
无参装饰器
def log(fn):
def inner():
print("log..before")
fn()
print("log..after")
return inner
# 编写日志增强装饰器
def log(fn):
def inner():
print("log..before")
fn()
print("log..after")
return inner
def add_user():
print("add.....user")
add_user = log(add_user)
# 调用的时装饰器的返回值-新函数
add_user()
装饰器传递原函数参数
def log(fn):
#def inner(username):# 此处加上参数,才能有参数传递进fn(参数)里的参数
def inner(*args,**kwargs): # 由于不同的函数需要的参数不一样,所以这里用可变长参数
print("log..before")
#fn(username)
fn(*args,**kwargs) # 需要同时更改可变长参数
print("log..after")
return inner
def log(fn):
#def inner(username):# 此处加上参数,才能有参数传递进fn(参数)里的参数
def inner(*args,**kwargs): # 由于不同的函数需要的参数不一样,所以这里用可变长参数
print("log..before")
#fn(username)
fn(*args,**kwargs) # 需要同时更改可变长参数
print("log..after")
return inner
def add_user(username,password):
print(f"add.....user{username},password{password}")
add_user = log(add_user)
add_user("zhangsan","111")
有参装饰器
def log(current_time):
def log_inner(fn):
def inner(*args, **kwargs):
print(f"log..before,time{current_time}")
fn(*args, **kwargs)
print(f"log..after,time{current_time}")
return inner
return log_inner
# 新任务:要加入时间功能
# 理念:一个函数只干一件事情
import time
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
def log(current_time):
def log_inner(fn):
def inner(*args, **kwargs):
print(f"log..before,time{current_time}")
fn(*args, **kwargs)
print(f"log..after,time{current_time}")
return inner
return log_inner
def add_user(username,password):
print(f"add.....user{username},password{password}")
# add_user = log(add_user)
log_in = log(current_time)
add_user = log_in(add_user)
add_user("zhangsan","111")
装饰器的语法糖
格式:
@装饰器的名字(参数)
执行流程:
执行语法糖所对应的装饰器,并传递语法糖作用原函数对象,进行装饰器的增强
下面以 有参装饰器的语法糖为例:
import time
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
def log(current_time):
def log_inner(fn):
def inner(*args, **kwargs):
print(f"log..before,time{current_time}")
fn(*args, **kwargs)
print(f"log..after,time{current_time}")
return inner
return log_inner
@log(current_time)
def add_user(username,password):
print(f"add.....user{username},password{password}")
# log_in = log(current_time)
# add_user = log_in(add_user)
add_user("zhangsan","111")
若为无参装饰器的语法糖,可以这样:(注意:不带括号)
@log_no_args
练习一:
# 案例一:使用装饰器,在函数输出结果时对其增加100
def add_100(test_fn):
def inner(*args, **kwargs):
res = test_fn(*args, **kwargs)
res = res + 100
return res
return inner
@add_100
def test_fn(number):
return number
print(test_fn(50))
类装饰器
由函数装饰器类比到类装饰器

无参类装饰器
class log_no_args_class():
func = None
def __init__(self, func):
self.func = func # 东西传进来之后,要交给类的成员
# 提供了装饰器独有的函数 __call__(),所有的实现细节都在此函数中
def __call__(self, *args, **kwargs):
print("log..before")
self.func(*args, **kwargs)
print("log..after")
# 定义无参类装饰器
class log_no_args_class():
func = None
def __init__(self, func):
self.func = func # 东西传进来之后,要交给类的成员
# 提供了装饰器独有的函数 __call__(),所有的实现细节都在此函数中
def __call__(self, *args, **kwargs):
print("log..before")
self.func(*args, **kwargs)
print("log..after")
# 定义原函数
@log_no_args_class
def add_user(username):
print(f"username: {username}")
# 调用原函数
add_user("zhangsan")
有参类装饰器
class log_args_class():
def __init__(self,current_time):
self.current_time = current_time
def __call__(self,func):
def inner(*args, **kwargs):
print(f"log..before{self.current_time}")
func(*args, **kwargs)
print(f"log..after{self.current_time}")
return inner
#定义有参类装饰器
import time
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
class log_args_class():
def __init__(self,current_time):
self.current_time = current_time
def __call__(self,func):
def inner(*args, **kwargs):
print(f"log..before{self.current_time}")
func(*args, **kwargs)
print(f"log..after{self.current_time}")
return inner
# 定义原函数
@log_args_class(current_time)
def add_user(username):
print(f"username: {username}")
# 调用原函数
add_user("zhangsan")
装饰器的执行顺序问题
由内向外的一个增强过程
图解:


练习:
# 1.使用类装饰器完成在函数输出值+100
# 2使用任意装饰器完成,某个函数执行5次
# 3.编写装饰从器完成,在写入任意字符到文件中添加写入时间,使用两种装饰器完成
# 4.使用两种装饰器完成,每次调用函数时记录调用函数名称_name__及调用函数时间,并写入义件
# 任务一
class res_add_100():
def __init__(self,func):
self.func = func
def __call__(self,*args,**kwargs):
try:
return self.func(*args,**kwargs) + 100
except:
return "非法字符"
@res_add_100
def test_dor1(number):
return number
print(test_dor1(10))
# 任务二
def func_loop_5(func):
def inner():
for i in range(5):
func()
return inner
@func_loop_5
def test_dor2():
print("zhangsan")
test_dor2()
# 任务三
import time
current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
def add_time_func(current_time):
def fun_inner(func):
def inner(*args, **kwargs):
func(*args, **kwargs)
try:
with open("data.txt", "a+", encoding="utf-8") as f:
f.write(f"现在时间{current_time}\n")
except Exception as e:
print(e)
return inner
return fun_inner
@add_time_func(current_time)
def write_str(str):
try:
with open("data.txt", "a+", encoding="utf-8") as f:
f.write(f"{str}\t")
print("已经写入")
except Exception as e:
print(e)
write_str("wangwu")
特性六:正则表达式
位运算符
1.位运算 --二进制(补码)逻辑运算
1.1 二进制的原码/反码/补码
正数的原反补码相同
1.2 计算二进制 --负数
原码-6 :0110
反码 :1001
补码: 1010
2.运算符
位与 & 一个为0则为0
位或 | 一个为1则为1
异或 ^ 相同为0 不同为1
取反 ~ 1变0 0 变1
左移 << 低位补0
右移 >> 高位看原来补0/1 低位舍弃
正则表达式
1.什么是正则
具备一套校验规则(特殊含义的字符),通过规则判断字符串是否匹配
2.使用正则
导入内置模块 re
3.常见的正则函数

# 测试正则常用函数
import re
str1 = "https://www.baidu.com"
# 测试match函数 --从开头开始匹配,如果开头未匹配到规则则返回None
res = re.match("http",str1)
print(res)
print(type(res)) # <class 're.Match'>
res = re.match("baidu",str1)
print(res)
print(type(res)) # <class 'NoneType'>
# 测试search函数 搜索整个字符串,将满足条件的所有字符串以列表返回
res = re.search("http",str1)
print(res)
print(type(res)) # <class 're.Match'>
res = re.search("baidu",str1)
print(res)
print(type(res)) # <class 're.Match'>
# 测试findall函数 搜索整个字符串
res = re.findall("baidu",str1)
print(res)
print(type(res)) # <class 'list'>
# 测试sub 搜索并替换字符串
res = re.sub("baidu","python",str1)
print(res)
print(type(res))
# 测试split 根据给出的子串分割字符串
res = re.split("baidu",str1)
print(res)
print(type(res)) # <class 'list'>
res = re.split(".",str1) #正则中的.表示的是所有
print(res)
res = re.split("\.",str1) #如果要使用.,就要转义
print(res)
正则规则1
1.匹配单个字符
. 表示任意字符
\] 匹配括号中任意某个字符 \\d 匹配数字字符 等价于\[0-9
\D 匹配非数字字符
\s 匹配空格字符
\S 匹配非空格字符
a-zA-Z0-9\] 单词字符 等价于\\w
\\W 非单词字符
#### 2.匹配多个字符
数量词:
\* 0个或多个 可以没有数字字符
?0个或1个 可以没有数字字符
+ 1个或多个 至少具备一个数字字符
{m} 匹配m词字符
{m,}至少m个字符
{m,n} m-n个字符
### 正则起始符
开始: \^
结束: $
判断是否以单词结尾 \\b --了解即可
判断是否以非单词结尾 \\b --了解即可、
### 正则的分组
#### 1.分组的问题
X \| X 或 规则满足其一即可
分组使用() --本质:二次筛选
#### 2.贪婪与非贪婪
默认的匹配规则都是贪婪模式
通过量词后添加? 可以开启非贪婪模式
#### 3.爬虫案例 --爬取一个官网的所有图片
import re
import requests
url = "https://www.gsau.edu.cn/"
res = requests.get(url)
print(type(res.text)) #',res.text)
for item in res:
print(item)
## 补充:常见的几种排序算法
排序几次?
每次排序怎么排?
### 冒泡排序
每次比较相邻两数,将较大的数向后移
### 选择排序
每次排序寻找最小值,并交换两数位置
### 插入排序
将其分为已排序和未排序两组,逐渐扩大有序区域