python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > python进阶教程

python进阶之路之闭包、装饰器、设计模式、多线程、socket、正则表达式

作者:骨力

在Python中函数被视为一等公民,这意味着函数可以像其他数据类型一样被赋值给变量、作为参数传递给其他函数,甚至可以从函数中返回,这篇文章主要介绍了python进阶之路之闭包、装饰器、设计模式、多线程、socket、正则表达式的相关资料,需要的朋友可以参考下

1、闭包

a、概念

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

def outer(msg1):
    print(msg1)
    def inner(msg2):
        print(msg1 + "--" + msg2)
    return inner

out = outer("这是msg1")
out("这是msg2")
out("这是第二个msg2")

结果为:
这是msg1
这是msg1--这是msg2
这是msg1--这是第二个msg2

b、nonlocal关键字

def outer(msg1):
    def inner(msg2):
        nonlocal msg1
        msg1 += msg2
        print(f"{msg1}---{msg2}")
    return inner

out = outer(10)
out(10)
out(10)

结果为:
20---10
30---10

c、优缺点

2、装饰器

案例:定义方法睡眠5秒,睡前睡后分别输出内容

普通写法

from time import sleep
def func():
    print("开始")
    sleep(5)
    print("结束")
func()
装饰器简单写法

def outer(func):
    def inner():
        print("开始")
        func()
        print("结束")
    return inner

def sleep1():
	from time import sleep
    sleep(5)

out = outer(sleep1)
out()
装饰器高级写法

def outer(func):
    def inner():
        print("开始")
        func()
        print("结束")
    return inner

@outer
def sleep1():
    from time import sleep
    sleep(5)

sleep1()

3、设计模式

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

a、单例模式

在普通情况下,定义了一个类,多次实例化时,所得到的地址是不一样的

class Test:
    pass
test1 = Test()
test2 = Test()
print(test1 == test2)

结果为:
False

如果想要多次实例化地址一样,就要用到单例模式
保证一个类只有一个实例,并且提供一个可以访问的全局访问点

第一步:test_tool.py文件中定义内容

class Test:
    pass

test_one = Test()
#第二步:test.py文件中定义内容

from test_tool import test_one
test1 = test_one
test2 = test_one
print(test1 == test2)

结果为:
True

b、工厂模式

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

当有多个类时,每次都要自己分别定义类才会获得对应对象

class Person:
    pass
class Student:
    pass

person = Person()
student = Student()

使用工厂模式,创建统一的创建对象的入口,便于代码维护
当发生修改时,只需要修改工厂类的方法即可

class Person:
    pass
class Student:
    pass

class Factory:
    def get_person(self,type):
        if type == "s":
            return Student()
        else:
            return Person()

person = Factory().get_person("p")
student = Factory().get_person("s")

4、多线程

a、进程、线程

b、并行执行

c、多线程编程

python的多线程可以通过threading模块实现

基础语法

import threading
thread = threading.Thread(group=, target=, name=, args=, kwargs=, daemon=)
thread.start()

group:暂时无用,未来功能的预留函数
target:执行的目标任务名,就是方法名
args:以元组的方式给执行任务传参
kwargs:以字典的方式给执行任务传参
name:线程名,一般不用设置

案例:创建两个方法并使用多线程同时执行

def one(msg):
    while True:
        print(msg)
def two(msg):
    while True:
        print(msg)

import threading
#元组形式传参,只有一个元素时需要带上逗号才是元组
thread = threading.Thread(target=one, args=("one",))
#字典形式传参
thread2 = threading.Thread(target=two, kwargs={"msg": "two"})
thread.start()
thread2.start()

结果为:
one
twoone
twoone
two
two
......

5、网络编程

a、概念

socket:是进程之间通信的一个工具,负责进程之间的网络数据传输,好比数据的搬运工
2个进程之间通过socket进行相互通讯,就需要有服务端和客户端
socket服务端:等待其他进程的链接,接收客户端发来的信息并回复消息socket客户端:主动连接服务端,发送消息给服务端,并接收返回的信息

b、服务端开发

# 第一步:创建socket对象
socket_server = socket.socket()
# 第二步:为服务端绑定ip地址和端口
socket_server.bind(("127.0.0.1", 8888))
# 第三步:监听端口。
    # 参数为允许连接的数量
socket_server.listen(1)
# 第四步:等待客户端连接。
    # 会返回一个二元元组,第一个元素为客户端和服务端的连接对象,第二个元素为客户端的地址信息
    # accept方法是阻塞方法,如果没有客户端链接会一直停留在这一行
socket_client, addr = socket_server.accept()
# 第五步:接收客户端发送的数据。
    # 参数为接收数据的最大字节数
    # 返回的时一个字节数组,不是字符串,可以通过decode方法转换为字符串
data = socket_client.recv(1024).decode("utf-8")
print(f"客户端接收的消息为:{data}")
# 第六步:向客户端发送数据。
socket_client.send("hello".encode("utf-8"))
# 第七步:关闭连接
socket_client.close()   #此关闭的是客户端的连接
socket_server.close()   #此关闭的是服务端

c、客户端开发

import socket
# 第一步:创建socket对象
socket_client = socket.socket()
# 第二步:连接到服务端
socket_client.connect(("127.0.0.1", 8888))
# 第三步:发送消息
    # 发送的内容默认是通过字节传输的,通过encode方法将字符串转换为字节
socket_client.send("hello".encode("utf-8"))
# 第四步:接收返回的消息
    # 参数为接收数据的最大字节数,此方法为阻塞的
    # 返回的时一个字节数组,不是字符串,可以通过decode方法转换为字符串
recv_data = socket_client.recv(1024).decode("utf-8")
print(f"服务端回复的消息为:{recv_data}")
# 第五步:关闭连接
socket_client.close()   #此关闭的是客户端的连接

6、正则表达式

a、概念

b、基础方法

案例:找出字符串中是否包含python开头的字符串

#情况一
import re
s = "python test python test"
result = re.match("python",s)
print(result)
print(result.span())		#这里是打印匹配字符串开头和结束的下标
print(result.group())		#这里是打印匹配的字符串内容

结果为:
<re.Match object; span=(0, 6), match='python'>
(0, 6)
python
#情况二
import re
s = "1python test python test"
result = re.match("python",s)	#因为s是以1开头,所以无法匹配python字符串
print(result)

结果为:
None

案例:找出字符串中是否包含python开头的字符串

#情况一
import re
s = "111python test python test"
result = re.search("python",s)
print(result)
print(result.span())	#这里返回的是匹配字符串的开头和结尾下标位置
print(result.group())	#这里返回的是匹配的字符串

结果为:
<re.Match object; span=(3, 9), match='python'>
(3, 9)
python
#情况二
import re
s = "111 test 2222 test"
result = re.search("python",s)
print(result)

结果为:
None
#情况一
import re
s = "111python test python test"
result = re.findall("python",s)
print(result)

结果为:
['python', 'python']
#情况二
import re
s = "111 test 2222 test"
result = re.findall("python",s)
print(result)

结果为:
[]

c、元字符匹配

在上面我们进行了基础的字符串匹配,正则最强大的功能在于元字符匹配规则

字符功能
.匹配任意1个字符(除了\n),\. 就是匹配点本身
[ ]匹配 [ ] 中列举的字符
\d匹配数字,即 0-9
\D匹配非数字
\s匹配空白,即空格,tab键
\S匹配非空白
\w匹配单词字符,即 a-z、A-Z、0-9、_
\W匹配非单词字符
字符功能
*匹配前一个规则的字符出现0至无限次
+匹配前一个规则的字符出现1至无限次
?匹配前一个规则的字符出现0次或1次
{m}匹配前一个规则的字符出现m次
{m,}匹配前一个规则的字符出现最少m次
{m,n}匹配前一个规则的字符出现m到n次
字符功能
^匹配字符串开头
$匹配字符串结尾
\b匹配一个单词的边界
\B匹配非单词边界
字符功能
|匹配左右任意一个表达式
( )将括号中字符作为一个分组
\b匹配一个单词的边界
\B匹配非单词边界

案例一:找出字符串中所有数字

import re
s = "test@@1452282!!###python"
# 找出全部数字
result = re.findall(r'\d',s)    #字符串前带上r的标记,表示字符串中转义字符无效,就是普通字符
print(result)

结果为:
['1', '4', '5', '2', '2', '8', '2']

案例二:找出字符串中所有特殊字符

import re
s = "test@@1452282!!###python"
# 找出全部特殊字符
result = re.findall(r'\W',s)    #字符串前带上r的标记,表示字符串中转义字符无效,就是普通字符
print(result)

结果为:
['@', '@', '!', '!', '#', '#', '#']

案例三:找出字符串中所有英文字母

import re
s = "test@@1452282!!###python"
# 找出全部英文字母
result = re.findall(r'[a-zA-Z]',s)    #字符串前带上r的标记,表示字符串中转义字符无效,就是普通字符
print(result)

结果为:
['t', 'e', 's', 't', 'p', 'y', 't', 'h', 'o', 'n']

案例四:匹配字符串中只能包含字母和数字,并且长度为6到18位

import re
r = "^[0-9a-zA-Z]{6,18}$"
result = re.findall(r,"123adalg")
result2 = re.findall(r,"laeooeoaoao11111111oa44252")
print(result)
print(result2)

结果为:
['123adalg']
[]

案例五:匹配字符串为纯数字,长度5到11位,第一位不为0

import re
r = "^[1-9][0-9]{4,10}$"
result = re.findall(r,"012345")
result2 = re.findall(r,"12355")
print(result)
print(result2)

结果为:
[]
['12355']

案例六:匹配字符串的邮箱地址,只允许qq、163、gmail这三种邮箱地址

import re
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
result = re.match(r,"12346@162.com")
result2 = re.match(r,"12346@163.com")
print(result)
print(result2.group())

结果为:
None
12346@163.com

7、递归

递归:即方法(函数)自己调用自己的一种特殊的编程写法

案例:使用递归设计一个函数,获取一个路径下的所有文件名

import os
def get_all_files(path):
    """
    获取指定路径下的所有文件
    :param path: 被判断的文件夹
    :return: list,包含全部的文件,如果目录不存在或者无文件则返回一个空list
    """
    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_all_files(new_path)   # 递归调用
            else:
                file_list.append(new_path)


    else:
        print("路径不存在")
        return []

    return file_list

总结

到此这篇关于python进阶之路之闭包、装饰器、设计模式、多线程、socket、正则表达式的文章就介绍到这了,更多相关python进阶教程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文