python基础----11-----闭包、装饰器、单例、工厂、多线程、socket、正则表达式、递归

news2024/11/19 13:26:03

一 闭包

  • 闭包:通过封装一个函数, 该函数内部又封装一个函数用于返回,使得得到一个无法直接修改值的临时变量,只能通过函数调用修改。
  • 闭包的作用:代替全局变量,避免全局变量的滥用。
  • 闭包的优缺点:1)优点是可以避免全局变量;2)缺点是该临时变量会一直占用内存。 但是内存都非常大,所以缺点往往可以忽略它。

例如,下图是使用全局变量,当别人导入该包,是可以得到该全局变量account_amount,然后进行修改,那么这样你的金额就有风险了。
在这里插入图片描述

使用闭包代替。

在讲闭包之前,首先先讲nonlocal的作用。nonlocal的作用是,要想在内部函数修改外部函数的变量值,需要在内部函数中使用nonlocal声明该变量,才能使用。
在这里插入图片描述

# 使用nonlocal关键字修改外部函数的值
def outer(num1):

    def inner(num2):
        # nonlocal num1
        num1 += num2
        print(num1)

    return inner

fn = outer(10)
fn(10)

例如,当我们注释掉nonlocal关键字,会报错:
在这里插入图片描述

上面了解nonlocal后,我们使用闭包实现ATM小案例。

# 使用闭包实现ATM小案例
def account_create(initial_amount=0):

    def atm(num, deposit=True):
        nonlocal initial_amount
        if deposit:
            initial_amount += num
            print(f"存款:+{num}, 账户余额:{initial_amount}")
        else:
            initial_amount -= num
            print(f"取款:-{num}, 账户余额:{initial_amount}")

    return atm

# 调用account_create后,相当于得到一个全局变量initial_amount
atm = account_create()

# 往后调用atm函数,就是对initial_amount形参的操作。
atm(100)
atm(200)
atm(100, deposit=False)

结果:
在这里插入图片描述

上面看到,不管别人如何导包,都无法得到变量initial_amount,因为此时它是一个形参,要想修改initial_amount的值,只能通过调用返回的函数。

二 装饰器

在这里插入图片描述
最简单的实现就是:

print("我睡觉了")
time.sleep(random.randint(1, 5))
print("我起床了")

但是,这种太low了,我们可以使用装饰器进行实现。

# 装饰器的一般写法(闭包)
def outer(func):
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner


def sleep():
    import random
    import time
    print("睡眠中......")
    time.sleep(random.randint(1, 5))

fn = outer(sleep)
fn()

结果:
在这里插入图片描述

上图看到,我们将sleep传给形参,这样就相当于一个全局变量,即通过闭包实现了装饰器。

下面我们来升级一下装饰器的写法,叫做装饰器的语法糖写法。
在这里插入图片描述

# 装饰器的快捷写法(语法糖)
def outer(func):
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner

@outer
def sleep():
    import random
    import time
    print("睡眠中......")
    time.sleep(random.randint(1, 5))

sleep()

结果是一样的。
在这里插入图片描述

上面看到,使用装饰器的语法糖写法,通过在sleep前声明@outer关键字,当我们调用sleep()时,相当于将sleep()函数作为参数传给了outer()函数,然后调用outer函数。

三 单例模式

在这里插入图片描述

在这里插入图片描述

单例模式实现:

str_tools_py.py:

class StrTools:
    pass

str_tool = StrTools()

test.py:

from str_tools_py import str_tool

s1 = str_tool
s2 = str_tool

print(id(s1))
print(id(s2))

在这里插入图片描述

四 工厂模式

在这里插入图片描述

在这里插入图片描述

"""
演示设计模式之工厂模式
"""

class Person:
    pass

class Worker(Person):
    pass

class Student(Person):
    pass

class Teacher(Person):
    pass


class PersonFactory:
    def get_person(self, p_type):
        if p_type == 'w':
            return Worker()
        elif p_type == 's':
            return Student()
        else:
            return Teacher()


pf = PersonFactory()
worker = pf.get_person('w')
stu = pf.get_person('s')
teacher = pf.get_person('t')

五 多线程并行执行概念

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

六 多线程编程

在这里插入图片描述

"""
演示多线程编程的使用
"""
import time
import threading

def sing(msg):
    while True:
        print(msg)
    #time.sleep(1)

def dance(msg):
    while True:
        print(msg)
    #time.sleep(1)

if __name__ == '__main__':
    # 创建一个唱歌的线程
    sing_thread = threading.Thread(target=sing, args=("我要唱歌 哈哈哈", ))
    # 创建一个跳舞的线程
    dance_thread = threading.Thread(target=dance, kwargs={"msg": "我在跳舞哦 啦啦啦"})

    # 让线程去干活吧
    sing_thread.start()
    dance_thread.start()

    # # 等待线程结束并回收
    # sing_thread.join()
    # dance_thread.join()
    # 
    # # 测试主线程是否退出
    # print("main结束")

结果,就是两个线程一直在打印,这个打印顺序是无序的,看CPU的调用顺序决定,CPU先调用谁,那么就哪个线程执行。
在这里插入图片描述

七 Socket服务端开发

在这里插入图片描述

在这里插入图片描述

服务端编程步骤:
在这里插入图片描述

在这里插入图片描述

"""
演示Socket服务端开发
"""
import socket

# 1 创建Socket对象
socket_server = socket.socket()

# 2 绑定ip地址和端口
socket_server.bind(("localhost", 8888))

# 3 监听端口
socket_server.listen(1)
# listen方法内接受一个整数传参数,表示接受的客户端链接数量

print(f"等待客户端连接,服务器端口是:8888")

# 4 等待客户端链接。
# 这里没有客户端连接时会阻塞
# result: tuple = socket_server.accept()
# conn = result[0]        # 客户端和服务端的链接对象
# address = result[1]     # 客户端的地址信息
conn, address = socket_server.accept()

# accept方法返回的是二元元组(链接对象, 客户端地址信息)
# 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
# accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了

print(f"接收到了客户端的链接,客户端的信息是:{address}")

while True:
    # 5 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
    # recv客户端没有接收到数据也会阻塞,这里只演示1个客户端的例子.
    data: str = conn.recv(1024).decode("UTF-8")
    # recv接受的参数是缓冲区大小,一般给1024即可
    # recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象

    print(f"客户端发来的消息是:{data}")
    # 6 发送回复消息
    msg = input("请输入你要和客户端回复的消息:")
    if msg == 'exit':
        break
    conn.send(msg.encode("UTF-8"))

# 7 关闭链接
conn.close()
socket_server.close()

下载网络调试助手作为客户端:
https://github.com/nicedayzhu/netAssist/releases。

在这里插入图片描述

在这里插入图片描述

八 Socket客户端开发

在这里插入图片描述

在这里插入图片描述

那么我们在pycharm启动上面服务端和客户端的代码,注意在pycharm是可以同时运行的。

客户端打印:
在这里插入图片描述

服务端打印:
在这里插入图片描述

九 正则表达式-基础方法

在这里插入图片描述

match():
在这里插入图片描述

这里注意,match()要求开头就要匹配,如果开头都不匹配,那么直接返回None,例如上图的s='1python xxx’与’python’比较,因为开头就不匹配了。所以直接返回None。

search():
搜索整个字符串,返回找到匹配的第一个字符串。类似C++的string.find()。

在这里插入图片描述

findall():搜索整个字符串,返回找出的全部匹配项。
在这里插入图片描述

"""
演示Python正则表达式re模块的3个基础匹配方法
"""
import re

s1 = "python itheima python python"
s2 = "1python itheima python python"

# 1 match 从头匹配
result = re.match("python", s1)
print(result)
# print(result.span())
# print(result.group())

result = re.match("python", s2)
print(result)

# 2 search 搜索匹配
result = re.search("python", s1)
print(result)

# 3 findall 搜索全部匹配
result = re.findall("python", s1)
print(result)


在这里插入图片描述

十 正则表达式-元字符匹配

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

案例。
在这里插入图片描述

"""
演示Python正则表达式使用元字符进行匹配
"""
import re

# 1. 查找小写b到e,大写F-Z,数字3-9的所有字符
s1 = "itheima1 @@python2 !!666 ##itccast3"
result = re.findall(r'[b-eF-Z3-9]', s1)   # 字符串前面带上r的标记,表示字符串中转义字符无效,就是普通字符的意思
print(result)

print("==========================")

# 2 匹配账号,只能由字母和数字组成,长度限制6到10位
# ^[0-9a-zA-Z]:表示开头第一个字符只能是数字和字母
# {6,10}:表示上一个规则出现6-10次。
# $:表示我要结尾,后面不能有内容
r = '^[0-9a-zA-Z]{6,10}$'
s2 = '123456_'
s21 = '123456'
print(re.findall(r, s2))
print(re.findall(r, s21))

print("==========================")

# 3 匹配QQ号,要求纯数字,长度5-11,第一位不为0
# ^[1-9]:表示第一个字符是1-9的数字。
# [0-9]:表示第二个字符串是0-9的数字
# {4,10}:表示前一个规则的字符出现4-10次。注意,本规则是修饰上一个规则,
# 这个4包含上一个规则([0-9]),所以是{4,10},而不是{3,10}。上面的{6,10}同理
r = '^[1-9][0-9]{4,10}$'
s3 = '123453678'
s31 = '12345'
print(re.findall(r, s3))
print(re.findall(r, s31))

print("==========================")

# 4 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
# abc.efg.daw@qq.com.cn.eu.qq.aa.cc
# abc@qq.com
# 我们假设邮箱地址是xxx.xxx.xxx@xxx.xxx的形式,反正内容可以出现很多次,例如:
# {内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}@{内容}.{内容}.{内容}
# 1)^[\w-]:表示开头只能是单词字符,然后-表示也可以出现它,即表示第一个字符可以出现 单词字符 和 -。
# 2)+:表示前一个规则可以出现1到无数次。
# 3)(\.[\w-]+):外层括号表示这个括号内是一整个规则; \.表示点,\只是转义;  [\w-]+表示单词字符和-可以出现1到无数次,即代表内容。
#       所以这里意思就是:第一个字符是., 然后后面的内容是单词字符可以出现1到无数次。
#       注意(个人理解),这里的+应该只修饰[\w-],而不是修饰\.[\w-],即不带上点(.),因为[\w-]只代表一个字符,
#       如果带上点的话,那么(\.[\w-]+)就表示:.内容.内容.内容... 一直这样,而内容[\w-]只代表一个字符,
#       例如:.a.b.c 所以这是不合理的。

# 4)*:表示上一个规则可以出现0-无数次,即.内容可以是0-无数次。
# 5)@(qq|163|gmail):匹配 @ 加上qq、163、gmail其中的一种。
# 6)(\.[\w-]+):和第3)点一样。
# 7)+:表示前一个规则可以出现1到无数次。
# 8)$:表示结尾。
# 9)注意,我们看到,最外层加上了大括号,r'(xxx)',这是因为如果不加,findall会把结果安装每个小规则分成多个元素返回
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
s4 = 'a.b.c.d.e.f.g@qq.com.a.z.c.d.e'
s41 = 'a.b.c.d.e.f.g@126.com.a.z.c.d.e'
s42 = 'a.b.c.d.e.f.g@163'
s43 = 'a.b.c.d.e.f.g@163.com'
print(re.match(r, s4))
print(re.match(r, s41))
print(re.match(r, s42))
print(re.match(r, s43))

print("==========================")
# 9)注意,我们看到,最外层加上了大括号,r'(xxx)',这是因为如果不加,findall会把结果安装每个小规则分成多个元素返回
r44 = r'^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$'
s44 = 'a.b.c.d.e.f.g@163.com'
print(re.findall(r44, s44))

结果:
在这里插入图片描述

十一 递归

在这里插入图片描述
先讲几个与文件目录相关的接口:

def test_os():
    """演示os模块的3个基础方法"""
    print(os.listdir("D:/test"))        	# 列出路径下的内容
    # print(os.path.isdir("D:/test/a"))   # 判断指定路径是不是文件夹
    # print(os.path.exists("D:/test"))    # 判断指定路径是否存在

我们以递归找文件为例,下面是文件目录结构:
在这里插入图片描述

"""
演示Python递归操作
需求:通过递归,找出一个指定文件夹内的全部文件

思路:写一个函数,列出文件夹内的全部内容,如果是文件就收集到list
如果是文件夹,就递归调用自己,再次判断。

"""
import os


def test_os():
    """演示os模块的3个基础方法"""
    print(os.listdir("C:/Users/asus/Desktop/python-code/递归"))        # 列出路径下的内容
    # print(os.path.isdir(C:/Users/asus/Desktop/python-code/递归"))   # 判断指定路径是不是文件夹
    # print(os.path.exists(C:/Users/asus/Desktop/python-code/递归"))    # 判断指定路径是否存在


def get_files_recursion_from_dir(path):
    """
    从指定的文件夹中使用递归的方式,获取全部的文件列表
    :param path: 被判断的文件夹
    :return: list,包含全部的文件,如果目录不存在或者无文件就返回一个空list
    """
    print(f"当前判断的文件夹是:{path}")
    file_list = []
    if os.path.exists(path):
        for f in os.listdir(path):
            new_path = path + "/" + f
            if os.path.isdir(new_path):
                # 进入到这里,表明这个目录是文件夹不是文件
                file_list += get_files_recursion_from_dir(new_path)
            else:
               file_list.append(new_path)
    else:
        print(f"指定的目录{path},不存在")
        return []

    return file_list

if __name__ == '__main__':
    file_lists = get_files_recursion_from_dir("C:/Users/asus/Desktop/python-code/递归")
    for f in file_lists:
        print(f)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/633531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为荣耀系列uniapp无法USB连接手机调试问题解决方案汇总

华为荣耀系列是一个异常奇葩的手机,经常出现无法调试的问题。 目前我整理出一套完整的切实多次测试可行的解决方案。 一、打开手机的关于手机 设置里面-一直快速点击版本号,连续点10几下。 此时处于开发者模式。 二、打开开发者选项 1、打开开发者…

搭建一个定制版New Bing吧

项目介绍 项目地址:https://github.com/adams549659584/go-proxy-bingai 引用项目简介:用 Vue3 和 Go 搭建的微软 New Bing 演示站点,拥有一致的 UI 体验,支持 ChatGPT 提示词,国内可用,国内可用&#xff…

功能安全开发学习实践心得-概念篇

【写在前面】 记录功能安全开发学习&实践过程中遇到的坎,此篇为概念(即行业/标准术语)的梳理。实践过程中发现不清楚概念,交流即没法进行,反之,理清概念的过程,即是把整个开发过程串联的过…

50、基于51单片机NRF24l01无线寻物跟踪儿童防丢器系统(程序+原理图+PCB图+设计资料+参考论文+开题报告+元器件清单等)

摘 要 正现代城市生活节奏越来越快,在城市中生活的人们,由于工作、家庭、个人发展、孩子教育、职场竞争等诸多原因,大脑时刻处于紧张状态,容易产生紧张和焦虑情绪,生活压力也越来越大。长期处于这样的状态中,会导致记忆力下降、注意力不集中、容易丢三落四,比如人们常常会记不…

『DevOpse最佳实践』使用Jenkins和Harbor进行持续集成和交付的解决方案

📣读完这篇文章里你能收获到 全文采用图文形式讲解学会使用Harbor配置项目学会在Jenkins中配置Harbor推送权限使用Jenkins和Harbor进行持续集成的实践感谢点赞收藏,避免下次找不到~ 文章目录 一、准备工作1. 环境准备2. 修改Docker配置文件3. Docker登陆…

Netty实战(十一)

预置的ChannelHandler和编解码器(一)HTTP和SSL/TLS的添加和使用 一、SSL和TLS添加二、基于Netty的HTTP程序2.1 HTTP解码器、编码器和编解码器2.2 聚合HTTP消息2.3 HTTP压缩 一、SSL和TLS添加 作为一个通讯框架,通讯数据的安全性也是不可或缺的…

LVS+KeepAlived集群

LVSKeepAlived集群 一.KeepAlived的原理 1.1基于什么协议 KeepAlived基于VRRP热备份协议# VRRP协议号112# VRRP组播地址224.0.0.18# VRRP通告报文的TTL值必须是2551.2如何选举Master 1)初始化时根据state判断master和backup。 2)最终根据优先级决定m…

【小沐学Python】Python实现在线电子书(Sphinx + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建测试工程4、项目文件结构5、编译为本地文件6、编译为http服务7、更改样式主题8、支持markdown9、修改文档显示结构10、项目托管到github11、部署到ReadtheDocs结语 1、简介 Sphinx 是一个 文档生成器 ,您也可以把它看成一种工具&…

Win10开启混合现实模拟器

最近要做一个类似工业元宇宙的项目,准备先在Win10上先进行模拟,而Win10已经提供了混合现实模拟器,可以在没有头显的情况下进行模拟。本文讲解如何开启这个模拟器。 微软官方给了一个链接讲述如何开启混合现实模拟器,可以点击这里…

嘀嗒陪诊小程序v1.0.8+小程序前端

嘀嗒陪诊小程序功能相对简单,后台也简捷,如果只是做个陪诊服务的小程序也基本能满足了,整体测试了下海参崴发现BUG,小程序端也能正常为使用,唯一用户授权接口是老的。 应用背景:人口老龄化少子化&#xff…

【数据结构】--单链表力扣面试题⑦环形链表

注:本篇文章不含环形链表的数学推理证明,只提供图解等思路 环形链表是一个非常经典的问题 题述:给定一个链表,判断链表中是否有环。 如果链表中有某个节点,可以通过连续追踪 next 指针再次到达,则链表中…

代码随想录算法训练营第五十三天|1143.最长公共子序列|1035.不相交的线|53. 最大子序和

LeetCode1143.最长公共子序列 动态规划五部曲: 1,确定dp数组(dp table)以及下标的含义:dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]。为什么要定…

【无功优化】“碳中和”目标下电气互联系统有功-无功协同优化模型(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

从零玩转系列之微信支付实战基础框架搭建

一、前言 halo各位大佬很久没更新了最近在搞微信支付,因商户号审核了我半个月和小程序认证也找了资料并且将商户号和小程序进行关联,至此微信支付Native支付完成.此篇文章过长我将分几个阶段的文章发布(项目源码都有,小程序和PC端) 在此之前已经更新了微信支付开篇、微信支付安…

【Matlab代码实现】电动过滤器:LPF和HPF、模拟调制:调幅和调频、WiFi、蓝牙和蜂窝网络的容量分析.....

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

第五章 二次型

引言 题型总结中推荐例题有蓝皮书的题型较为重要,只有吉米多维奇的题型次之。码字不易,如果这篇文章对您有帮助的话,希望您能点赞、评论、收藏,投币、转发、关注。您的鼓励就是我前进的动力! 知识点思维导图 补充&…

十一、进程间通信——管道

目录 零、前置知识 一、什么是进程间通信 (一)含义 (二)发展 (三)类型 1.管道 2.System V IPC 3.POSIX IPC 二、为什么要有进程间通信 三、怎么进行进程间通信 (一)什么是…

PoseiSwap的趋势性如何体现?

DEX 代表了一种先进的意识形态,相对于 CEX 其更强调无许可、去中心化以及公开透明。然而随着 DeFi 赛道逐渐从 2021 年年底的高峰逐渐转向低谷,DEX 整体的交易量、TVL等数据指标也开始呈现下滑的趋势,DEX 正在面临发展的新瓶颈期。 在这样的背…

时间序列预测的20个基本概念总结

1、时间序列 时间序列是一组按时间顺序排列的数据点 比如: 每小时的气压每年的医院急诊按分钟计算的股票价格 2、时间序列的组成部分 时间序列数据有三个主要组成部分。 趋势季节性残差或白噪声 3、趋势 在时间序列中记录的长期缓慢变化/方向。 4、季节性 …

51、基于51单片机洗衣机控制系统(带水位)系统设计(程序+原理图+PCB源文件+Proteus仿真+参考论文+开题报告+任务书+流程图+元器件清单等)

摘 要 随着数字技术的快速发展,数字技术被广泛应用于智能控制的领域中。单片机以体积小、功能全、价格低廉、开发方便的优势得到了许多电子系统设计者的青睐。它适合于实时控制,可构成工业控制器、智能仪表、智能接口、智能武器装置以及通用测控单元等。…