python第八部分:高级特性(二)

特性四:函数的闭包

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 = re.findall(r'',res.text) for item in res: print(item) ## 补充:常见的几种排序算法 排序几次? 每次排序怎么排? ### 冒泡排序 每次比较相邻两数,将较大的数向后移 ### 选择排序 每次排序寻找最小值,并交换两数位置 ### 插入排序 将其分为已排序和未排序两组,逐渐扩大有序区域

相关推荐
茉莉玫瑰花茶4 小时前
C++ 17 详细特性解析(5)
开发语言·c++·算法
上海合宙LuatOS4 小时前
LuatOS核心库API——【audio 】
java·网络·单片机·嵌入式硬件·物联网·音视频·硬件工程
lly2024064 小时前
《堆的 shift down》
开发语言
汤姆yu4 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
TT哇4 小时前
【实习】银行经理端线下领取扫码功能实现方案
java
野犬寒鸦4 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
黎雁·泠崖5 小时前
【魔法森林冒险】2/14 抽象层设计:Figure/Person类(所有角色的基石)
java·开发语言
季明洵5 小时前
C语言实现单链表
c语言·开发语言·数据结构·算法·链表
墨雪不会编程5 小时前
C++之【深入理解Vector】三部曲最终章
开发语言·c++