1.闭包

  • 问题原由

    account_amount = 0 # 账户余额
    def atm(num, deposit=True)
        global account_amount
        if deposit:
            account_amount += num
            print(f"存款:{num},账户余额:{account_amount}")
        else:
            account_amount -= num
            print(f"取款:{num},账户余额:{account_amount}")
    
    • 尽管功能实现是可以的,但存在问题
      • 代码在命名空间上(变量定义)不够干净、整洁
      • 全局变量有被修改的风险
  • 概述

    在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们吧这个使用外部函数变量的内部函数称为闭包

  • 简单闭包

    def outer(logo):
    
        def inner(mes):
            print(f"<{logo}>{mes}<{logo}>")
        return inner
    fu = outer("flag")
    fu("你好")
    fu("Python")
    

image-20230810215235672.png

  • 使用nonlocal关键字修饰外部函数的变量,即可在内部函数中修改
def outer(num1):
    def inner(num2):
        nonlocal num1
        num1 += num2
        print(num1)
    return inner
fu = outer(10)
fu(20)
  • 修改atm取钱案例,闭包实现
def atm(account_money=0):
    def save(num,deposit=True):
        nonlocal account_money
        if deposit:
            account_money += num
        else:
            account_money -= num
        print(f"账户当前月:{account_money}")
    return save
fu = atm()
fu(300)
fu(300)
fu(100,False)
  • 注意事项
    • 优点
      • 无需定义全局变量即可实现通过函数持续的访问、修改某个值
      • 闭包使用的变量的作用域在于在函数内,难以被错误的调用修改
    • 缺点
      • 由于内部函数持续引用外部函数的值,所以回导致这部分内存空间不被释放,一直会占用内存

2.装饰器

  • 概述

    装饰器也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能

  • 原由

    def sleep():
        import random
        import time
        print("睡眠中....")
        time.sleep(random.randint(1, 5))
    
    • 希望给sleep函数,增加功能
      • 在调用sleep前输出:我要睡觉了
      • 在调用sleep后输出:我起床了
  • 装饰器的一般写法(闭包写法)

    def outer(fun):
        def inner():
            print("准备睡觉...")
            fun()
            print("起床...")
        return inner
    def sleep():
        import random
        import time
        print("睡眠中....")
        time.sleep(random.randint(1, 5))
    fn = outer(sleep)
    fn()
    
  • 装饰器的语法糖写法

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()

3.设计模式

  • 概述

    • 设计模式是一种编程套路,可以极大的方便程序的开发
    • 常见的:面向对象
  • 单例模式

    与Java一致,只需要该对象存在一个实例对象

    • str_tools
    class Str_tools:
        pass
    
    strTools = Str_tools()
    
    • test
    from str_tools import strTools
    
    s1 = strTools
    s2 = strTools
    print(id(s1))
    print(id(s2))
    
  • 工厂模式

    当需要大量创建一个类实例的时候,可以使用工厂模式

    • 优点
      • 大批量创建对象的时候有统一的入口,易于代码维护
      • 当发生修改时,仅修改工厂类的创建方法即可
      • 符合现实世界的模式,即由工厂来制作产品(对象)
    class Person:
        pass
    class Worker(Person):
        pass
    class Student(Person):
        pass
    class Teacher(Person):
        pass
    
    class PersonFactory:
        def getPerson(self, type):
            if type == "w":
                return Worker()
            elif type == "s":
                return Student()
            else:
                return Teacher()
    
    factory = PersonFactory
    worker = factory.getPerson("w")
    Student = factory.getPerson("s")
    Teacher = factory.getPerson("t")
    

4.多线程

  • 概述

    • 进程:一个程序,运行在系统上,称这个程序为一个运行进程,并分配进程ID方便系统管理
    • 线程:线程是归属进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位

    • 注意点:进程之间是存在隔离的,即不同的进程拥有各自的内存空间。线程之间是内存共享的,线程是属于进程的,一个进程的多个线程之间就是共享这个进程所拥有的内存空间

image-20230810215436911.png

  • 并行执行

    • 指同一时间做不同的工作
    • 进程之间就是并行执行,操作系统可以同时运行好多程序,这些程序都是在并行执行
  • 多线程编程

    • threading模块
    import threading
    
    threadObj = threading.Thread([group [, target [, name [, args [, kwargs]]]])
    - group:暂时没作用,未来功能的预留参数
    - target:执行的目标任务名
    - args:以元组的方式给执行任务传参
    - kwargs:以字典的方式给执行任务传参
    - name:线程名,一般不设置
    
    # 启动线程,让线程开始工作
    threadObj.start()
    
    • 实例编程代码
    def sing():
        while True:
            print("我在唱歌....")
            time.sleep(1)
    
    def dance():
        while True:
            print("我在跳舞....")
            time.sleep(1)
    
    if __name__ == '__main__':
        # 创建一个线程执行唱歌函数
        singStread = threading.Thread(target=sing)
        # 常见一个线程执行跳舞函数
        danceThread = threading.Thread(target=dance)
    
        # 执行线程
        singStread.start()
        danceThread.start()
    
    • 传参
    ef sing(mes):
        while True:
            print(mes)
            time.sleep(1)
    
    def dance(mes):
        while True:
            print(mes)
            time.sleep(1)
    
    if __name__ == '__main__':
        # 创建一个线程执行唱歌函数
        singStread = threading.Thread(target=sing, args=("我在唱歌....",))
        # 常见一个线程执行跳舞函数
        danceThread = threading.Thread(target=dance, kwargs={"mes":"我在跳舞....",})
    
        # 执行线程
        singStread.start()
        danceThread.start()
    

5.网络编程

  • Socket
    • 是进程之间通信的一个工具,进程之间想要进行网络通信就需要socket
  • 客户端和服务端

    • 服务端:等待其它进程的连接、可接受发来的消息、可以回复消息
    • 客户端:主动连接服务端、可以发送消息、可以接受回复
  • Scoket服务端编程

import socket
# 创建Socket对象
serverSocket = socket.socket()
# 绑定ip地址和端口  参数为二元元组类型
serverSocket.bind(("localhost", 8888))
# 监听端口  # listen方法参数为整数类型,表示连接的数量
serverSocket.listen(1)
# 等待客户端链接
# result: cuple = serverSocket.accept()
# conn = result[0]   客户端和服务端的连接对象
# address = result[1] 客户端的地址信息
conn, address = serverSocket.accept()    # accept()接受的是元组类型,分别为两个值,可以用两个变量来接受
# accept 是阻塞方法,等待客户端的连接,如果没有连接,则不会执行下面的代码
# 接收客户端信息  使用服务端与客户端的连接对象
while True:
    print(f"接收到了客户端的信息,客户端的信息是:{address}")
    data = conn.recv(1024).decode("UTF-8")
    # recv接受的参数是缓冲区的大小,一般为1024
    # recv方法的返回值为字节数组,不是字符串,通过decode方法传参为编码格式utf-8来转为字符串对象
    print(f"客户端发来的信息是:{data}")
    # 发送回复信息
    mes = input("请输入你要和客户端回复的消息:")  # encode可以将字符串转为字节数组对象
    if mes == "exit":
        break
    conn.send(mes.encode("UTF-8"))
# 关闭链接
conn.close()
serverSocket.close()
  • Scoket客户端编程
import socket
# 创建socket对象
clientSocket = socket.socket()
# 连接到服务端
clientSocket.connect(("localhost", 8888))
# 发送信息
while True:
    mes = input("请输入要发送给服务端的信息:")
    clientSocket.send(mes.encode("UTF-8"))
    if mes == "exit":
        break
    # 接受返回信息
    revcMes = clientSocket.recv(1024)  # 1024缓冲区的大小,同样recv为阻塞方法
    print(f"服务端回复的信息为:{revcMes.decode('UTF-8')}")
# 关闭连接
clientSocket.close()

6.正则表达式

概述

  • 与Java一致,语法不同
  • 模块类为import re

三个基础方法

  • re.match(匹配规则,被匹配字符串)

从被匹配字符串开头进行匹配,匹配成功返回匹配对象,匹配不成功返回空

import re
# match 从头匹配(匹配不上,返回None)
str = "mahaonan haonan"
result = re.match("mahaonan", str)
print(result)           # <re.Match object; span=(0, 8), match='mahaonan'>
print(result.span())    # (0, 8)
print(result.group())   # mahaonan
  • re.search(匹配规则,被匹配字符串)

搜索整个字符串,找出匹配的。从前向后,找到第一个就停止,不会继续匹配

str = "133haonan88888mahaonan888"
result = re.search("haonan", str)
print(result)           # <re.Match object; span=(3, 9), match='haonan'>
print(result.span())    # (3, 9)
print(result.group())   # haonan
  • re.findall(匹配规则,被匹配字符串)

匹配整个字符串,找出全部匹配项

str = "133haonan88888mahaonan888"
result = re.findall("haonan", str)
print(result)   #['haonan', 'haonan']

6.1、元字符匹配

  • 单字符匹配

image-20230810215659365.png

  • 示例

    s = "mahaonan @@@ 2354 haonan 777!!"
    # 找出全部数字
    re.findall(r"\d", s)
    # 字符串的r标记,表示当前字符串是原始字符串,即内部的转义字符无效而是普通字符
    # 找出特殊字符
    re.findall(r"\W", s)
    # 找出全部英文字母
    re.findall(r"[a-zA-Z]", s)
    
  • [] 作用与Java一致

  • 数量匹配

image-20230810215707766.png

  • 元字符匹配

image-20230810215713561.png

  • 分组匹配

image-20230810215719073.png

  • 示例代码
import re
# 匹配账号,只能由字母和数字组成,长度限制6-10位
r = "^[a-zA-Z0-9]{6,10}$"
str = input("请输入账号(由字母和数字组成,长度6-10):")
result = re.findall(r, str)
print(result)
# 匹配QQ号,要求纯数字,长度5-11,第一位不为0
print(re.findall(r"^[1-9]\d{4,10}$", input("请输入QQ号(纯数字,长度5-11,第一位不为0):")))
# 匹配邮箱地址,只允许qq、163、gmail着三种邮箱地址
r = r"(^[\w-]+(\.[\w-]+)*@(qq|163|gamail)(\.[\w-]+)+$)"
print(re.match(r, input("请输入邮箱地址:")))

7.递归

  • 概述
    • 与Java一致
  • 递归找文件
    • 找出指定路径下的所有文件,文件夹则使用递归进行继续查找
import os

print(os.listdir("E:/TestPhoto"))   # 将该文件下的所有文件名称打印出来
print(os.path.isdir("E:/TestPhoto"))    # 判断该路径是否是文件夹
print(os.path.exists("E:/TestPhoto"))   # 判断该路径的文件是否存在

def findAllDicrectory(path):
    """
    指定路径,查找到所有的文件列表
    :param path: 被判断的文件夹
    :return: 包含全部的文件,如果不存在或者无文件,则返回空的list列表
    """
    files = []
    if os.path.exists(path):
        directories = os.listdir(path)
        for i in directories:
            if os.path.isdir(f"{path}/{i}"):
                files += findAllDicrectory(f"{path}/i")
            else:
                files.append(i)
    else:
        return files
    return files
print(findAllDicrectory("E:/TestPhoto"))

results matching ""

    No results matching ""