Python学习7

PySpark

Spark 是Apache基金会旗下的顶级开源项目,用于对海量数据进行大规模分布式计算

Spark对Python语言的支持,重点体现在,Python第三方库:PySpark之上。PySpark不仅可以作为Python第三方库使用,也可以将程序提交的Spark集群环境中,调度大规模集群进行执行。

复制代码
"""
演示获取PySpark的执行环境入库对象:SparkContext
并通过SparkContext对象获取当前PySpark的版本
"""
# 导包
from pyspark import SparkConf,SparkContext
# 创建SparkConf 类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)
# 打印PySpark的运行版本
print(sc.version)
# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()
复制代码

SparkContext类对象,是PySpark编程中一切功能的入口。

PySpark的编程,主要分为三步:

 通过SparkContext对象,完成数据输入;  输入数据后得到RDD对象,对RDD对象进行迭代计算;  最终通过RDD对象的成员方法,完成数据输出工作

  •  RDD对象

PySpark支持多种数据的输入,在输入完成后,都会得到一个:RDD类的对象。 RDD全称为:弹性分布式数据集

PySpark针对数据的处理,都是以RDD对象作为载体,即:

数据存储在RDD内;  各类数据的计算方法,也都是RDD的成员方法;  RDD的数据计算方法,返回值依旧是RDD对象

Python数据容器转RDD对象:

PySpark 支持通过SparkContext对象的Parallelize成员方法,将:list,tuple,set,dict,str转换为PySpark的RDD对象

注意:字符串会被拆分出1个个的字符,存入RDD对象;  字典仅有key会被存入RDD对象

  • 通过SparkContext的parallelize成员方法,将Python数据容器转换为RDD对象
复制代码
"""
演示通过PySpark代码加载数据,即数据输入
"""
# 导包
from pyspark import SparkConf,SparkContext
# 创建SparkConf 类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)

# 通过parallelize方法将Python对象加载到Spark内,成为RDD对象
rdd1 = sc.parallelize([1, 2, 3, 4, 5])
rdd2 = sc.parallelize((1, 2, 3, 4, 5))
rdd3 = sc.parallelize("abcdefg")
rdd4 = sc.parallelize({1, 2, 3, 4, 5})
rdd5 = sc.parallelize({"key1": "value1", "key2": "value2"})

# 查看RDD里面有什么内容,需要用collect()方法
print(rdd1.collect())           # 结果是:[1, 2, 3, 4, 5]
print(rdd2.collect())           # 结果是:[1, 2, 3, 4, 5]

sc.stop()
复制代码
  • 通过SparkContext的textFile成员方法,读取文本文件得到RDD对象
复制代码
"""
演示通过PySpark代码加载数据,即数据输入4
"""
# 导包
from pyspark import SparkConf,SparkContext
# 创建SparkConf 类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)

# 用textFile方法,读取文件数据加载到Spark内,成为RDD对象
rdd = sc.textFile("测试.txt")
print(rdd.collect())

sc.stop()
复制代码

数据计算

PySpark的数据计算,都是基于RDD对象来进行的。RDD对象内置丰富的:成员方法(算子)

  • map算子

功能:map算子,是将RDD的数据一条条处理(处理的逻辑  基于map算子中接收的处理函数),返回新的RDD

复制代码
"""
演示RDD的map成员方法的使用
"""
# 导包
from pyspark import SparkConf,SparkContext
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"

# 创建SparkConf 类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)

# 用textFile方法,读取文件数据加载到Spark内,成为RDD对象
rdd = sc.parallelize([1, 2, 3, 4, 5])
# 通过map方法将全部数据乘以10
def func(data):
    return data*10

rdd2 = rdd.map(func)
print(rdd2.collect())
复制代码
  • map链式调用

对于返回值是新的RDD的算子,可以通过链式调用的方式多次调用算子

复制代码
# 导包
from pyspark import SparkConf,SparkContext
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"

conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
sc = SparkContext(conf = conf)

# 用textFile方法,读取文件数据加载到Spark内,成为RDD对象
rdd = sc.parallelize([1, 2, 3, 4, 5])
# 链式调用
rdd2 = rdd.map(lambda x: x * 10).map(lambda x: x + 5)
print(rdd2.collect())           # 结果是: [15, 25, 35, 45, 55]
复制代码
  • flatMap算子

功能:对rdd执行map操作,然后进行解除嵌套操作

复制代码
# 导包
from pyspark import SparkConf,SparkContext
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
sc = SparkContext(conf = conf)

# 用textFile方法,读取文件数据加载到Spark内,成为RDD对象
rdd = sc.parallelize(["tomorrow is a guud day!", "today is guud", "and yesterday"])

# 需求,将RDD数据里面的单词一个个提取出来
rdd2 = rdd.flatMap(lambda x: x.split(" "))
print(rdd2.collect())
# 结果是:['tomorrow', 'is', 'a', 'guud', 'day!', 'today', 'is', 'guud', 'and', 'yesterday']
复制代码
  • reduceByKey算子

功能:针对KV型RDD(二元元组),自动按照Key进行分组,然后根据你提供的聚合逻辑,完成组内数据(value)的聚合操作

语法:

 注意: reduceByKey中接收的函数,只负责聚合,不理会分组;分组是by key 来自动分组的

复制代码
# 导包
from pyspark import SparkConf,SparkContext
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
sc = SparkContext(conf = conf)

rdd = sc.parallelize([('', 97), ('', 76), ('', 95), ('', 89)])
# 求男生和女生两个组的成绩之和
rdd2 = rdd.reduceByKey(lambda a, b: a + b)
print(rdd2.collect())       # 结果是:[('男', 173), ('女', 184)]
复制代码
  • Filter算子

功能:过滤  对想要的数据进行保留

语法:

 注意:filter算子,接收一个处理函数,可用lambda快速编写;  函数对RDD数据逐个处理,得到True的保留并返回到RDD中

复制代码
from pyspark import SparkContext, SparkConf
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

rdd = sc.parallelize([1, 2, 3, 4, 5])
# 对RDD的数据进行过滤
rdd2 = rdd.filter(lambda num: num % 2 == 0)   # 得到true的保留在rdd2中
print(rdd2.collect())
复制代码
  • distinct算子

功能:对RDD数据进行去重,返回新RDD

语法:rdd.distinct( )  无需传参

复制代码
from pyspark import SparkContext, SparkConf
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

rdd = sc.parallelize([1, 2, 3, 4, 5, 6, 7, 7, 4, 2, 9])
# 对RDD的数据进行去重
rdd2 = rdd.distinct()

print(rdd2.collect())       # 结果是:[1, 9, 2, 3, 4, 5, 6, 7]
复制代码
  • sortBy算子

功能:对RDD数据进行排序,基于你指定的排序依据

语法:

 注意:全局进行排序要设置分区数为:1   

复制代码
from pyspark import SparkContext, SparkConf
import os
os.environ['PYSPARK_PYTHON'] = "D:\Anaconda3\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

rdd = sc.textFile("测试.txt")
word_rdd = rdd.flatMap(lambda x: x.split(" "))
word_with_one_rdd = word_rdd.map(lambda word:(word, 1))
result_rdd = word_with_one_rdd.reduceByKey(lambda a, b: a + b)
# 对结果进行排序
final_rdd = result_rdd.sortBy(lambda x: x[1], ascending= False, numPartitions= 1)
print(final_rdd.collect())
复制代码

数据输出

数据输出的方法:collect:将RDD内容转换为list, reduce:对RDD内容进行自定义聚合,

take:取出RDD的前N个元素组成list,count:统计RDD元素个数

  • collect算子

功能:将RDD各个分区内的数据,统一收集到Driver中,形成一个List对象

用法: rdd.collect( )  返回值是一个list

复制代码
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON'] = 'D:\Anaconda3\python.exe'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])

# collect 算子,输出RDD为list对象
rdd_list:list = rdd.collect()
print(rdd_list)         # 结果:[1, 2, 3, 4, 5]
print(type(rdd_list))   # 结果:<class 'list'>
复制代码
  • reduce算子

功能:对RDD数据集按照传入的逻辑进行聚合

语法:

复制代码
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON'] = 'D:\Anaconda3\python.exe'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])

# reduce 算子,对RDD进行两两聚合
num = rdd.reduce(lambda a, b:a + b)
print(num)      # 结果:15
复制代码
  • take算子

功能: 取RDD的前N个元素,组合成list返回

复制代码
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON'] = 'D:\Anaconda3\python.exe'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])

# take算子, 取出RDD的前N个元素,组成list返回
take_list = rdd.take(3)
print(take_list)            # 结果:[1, 2, 3]
复制代码
  • count算子

功能:计算RDD内有多少条数据,返回一个数值

复制代码
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON'] = 'D:\Anaconda3\python.exe'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])

# count算子,统计RDD内有多少条数据,返回值为数字
num_count = rdd.count()
print(f"rdd内有{num_count}个元素")           # 结果:rdd内有5个元素
复制代码

数据输出到文件

  • saveAsTextFile算子

功能:将RDD的数据写入文本文件中;  支持本地写出,hdfs等文件系统

代码:

rdd = sc.parallelize([1, 2, 3, 4, 5])

rdd.saveAsTextFile("想写入的文件路径")

  • 修改rdd为1个分区

方式一:SparkConf对象设置属性全局并行度为1

conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
conf.set("spark.default.parallelism","1")
sc = SparkContext(conf =conf)

方式二:创建RDD的时候设置(parallelize方法传入numSlices参数为1)

rdd = sc.parallelize([1, 2, 3, 4, 5], numSlices=1)
rdd1 = sc.parallelize([1, 2, 3, 4, 5], 1)
复制代码
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON'] = 'D:\Anaconda3\python.exe'
os.environ['HADOOP_HOME'] = 'D:\hadoop-3.0.0\hadoop-3.0.0'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
conf.set("spark.default.parallelism", "1")          # 按照方式一,分区为1
sc = SparkContext(conf = conf)

# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])
rdd2 = sc.parallelize([("hello", 3), ("Spark", 5), ("Hi", 7)])
rdd3 = sc.parallelize([[1, 3, 5], [6, 7, 9], [11, 13, 14]])

# 输出到文件中
rdd.saveAsTextFile("D:\PyCharm Community Edition 2022.3.3\PycharmProjects\output1")
rdd2.saveAsTextFile("D:\PyCharm Community Edition 2022.3.3\PycharmProjects\output2")
rdd3.saveAsTextFile("D:\PyCharm Community Edition 2022.3.3\PycharmProjects\output3")
复制代码
复制代码
from pyspark import SparkConf, SparkContext
import os
import json
os.environ['PYSPARK_PYTHON'] = 'D:\Anaconda3\python.exe'
os.environ['HADOOP_HOME'] = 'D:\hadoop-3.0.0\hadoop-3.0.0'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf = conf)

# 准备RDD     按照方式二设置分区为1
rdd = sc.parallelize([1, 2, 3, 4, 5], numSlices=1)
rdd2 = sc.parallelize([("hello", 3), ("Spark", 5), ("Hi", 7)],1)
rdd3 = sc.parallelize([[1, 3, 5], [6, 7, 9], [11, 13, 14]],1)

# 输出到文件中
rdd.saveAsTextFile("D:\PyCharm Community Edition 2022.3.3\PycharmProjects\output1")
rdd2.saveAsTextFile("D:\PyCharm Community Edition 2022.3.3\PycharmProjects\output2")
rdd3.saveAsTextFile("D:\PyCharm Community Edition 2022.3.3\PycharmProjects\output3")
复制代码

闭包

 定义双层嵌套函数,内层函数可以访问外层函数的变量;将内层函数作为外层函数的返回,次内层函数就是闭包函数

优点:

无需定义全局变量即可实现通过函数,持续访问、修改某个值。 闭包使用的变量的作用域在函数内,难以被错误的调用修改

缺点:

由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存。

复制代码
"""
演示Python的闭包特性
"""
# 简单闭包
def outer(logo):
    def inner(msg):
        print(f"<{logo}>{msg}<{logo}>")

    return inner

fn1 = outer("你好")       # 调用outer返回的是一个函数fn1
fn1("大家好")      # 通过上面返回的fn1函数  结果;<你好>大家好<你好>

fn2 = outer("天气好")     # 调用outer返回的是一个函数fn2
fn2("出来玩")      # 通过上面返回的fn2函数  结果;<天气好>出来玩<天气好>
复制代码
  • 修改外部函数变量的值

需要使用nonlocal关键字修饰外部函数的变量,才可在内部函数中修改它

复制代码
def outer(num1):

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

    return inner
fn = outer(10)
fn(10)      # 结果:20
fn(10)      # 结果:30
fn(10)      # 结果:40
复制代码

案例:

复制代码
# 使用闭包实现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

atm = account_create()
atm(100)                    # 结果:存款:+100, 账户余额:100
atm(200)                    # 结果:存款:+200, 账户余额:300
atm(100,deposit=False)      # 结果:取款:-100, 账户余额:200
复制代码

 装饰器

装饰器就是使用创建一个闭包函数,在闭包函数内调用目标函数,可以达到不改动目标函数的同时,增加额外的功能。

  • 简单装饰器写法:
复制代码
# 演示装饰器的一般写法(闭包):
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()
复制代码
  • 装饰器的语法糖写法:

使用@outer 定义在目标函数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()
复制代码

设计模式

设计模式是一种编程套路,可以极大的方便程序的开发。最常见、最经典的设计模式,就是我们所学习的面向对象

除了面向对象外,在编程中也有很多既定的套路可以方便开发,我们称之为设计模式:

  • 单例、工厂模式
  • 建造者、责任链、状态、备忘录、解释器、访问者、观察者、中介、模板、代理模式
  • 等等模式

单例模式

创建类的实例后,就可以得到一个完整的、独立的类对象。可以节省内存、节省创建对象的开销。

class Tool:
    pass
t1 = Tool()
t2 = Tool()
print(t1)           # 结果:<__main__.Tool object at 0x000001908931A460>
print(t2)           # 结果:<__main__.Tool object at 0x000001908938C280>

通过print()语句可以看出,它们的内存地址是不相同的,即t1和t2是完全独立的两个对象。

单例模式是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

定义: 保证一个类只有一个实例,并提供一个访问它的全局访问点

使用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它时。

 工厂模式

当需要大量创建一个类的实例的时候,可以使用工厂模式。即,从原生的使用类的构造去创建对象的形式迁移到,基于工厂提供的方法去创建对象的形式

好处:大批量创建对象的时候有统一的入口,易于代码维护;  当发生修改,仅修改工厂类的创建方法即可;   符合现实世界的模式,即由工厂来制作产品

复制代码
# 演示设计模式之工厂模式
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')
复制代码

进程、线程

现代操作系统比如Mac OS X, UNIX, Linux, Windows等,都是支持“多任务”的操作系统。

进程:就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。

线程:线程是属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位

进程就好比一家公司,是操作系统对程序进行运行管理的单位。线程就好比公司的员工,进程可以有多个线程(员工),是进程实际的工作者。

操作系统中可以运行多个进程,即多任务运行。一个进程内可以运行多个线程,即多线程运行。

进程之间是内存隔离的,即不同的进程拥有各自的内存空间。这就类似于不同的公司拥有不同的办公场所。

线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。这就好比,公司员工之间是共享公司的办公场所。

并行执行

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

处理进程外,线程其实也是可以并行执行的。也就是比如一个Python程序,其实是完全可以做到:

一个线程在输出:你好;  一个线程在输出:Hello

像这样一个程序再同一时间做两件乃至多件不同的事情,我们就称之为:多线程并行执行

threading模块

绝大数编程语言,都允许多线程编程,Python也不例外。Python的多线程可以通过threading模块来实现。

复制代码
# 演示多线程编程的使用
import time
import threading

def sing():
    print("我在唱歌,啦啦啦啦....")
    time.sleep(1)

def dance():
    print("我在跳舞,哗哗哗哗....")
    time.sleep(1)

if __name__ == '__main__':
    # 创建一个唱歌的线程
    sing_thread = threading.Thread(target=sing)
    # 创建一个跳舞的线程
    dance_thread = threading.Thread(target=dance)

    # 让线程去干活吧:
    sing_thread.start()
    dance_thread.start()
复制代码

需要传参的话可以通过:

  • args参数通过元组(按参数顺序)的方式传参
  • 使用kwargs参数用字典的形式传参
复制代码
# 演示多线程编程的使用
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()
复制代码

socket

socket是进程之间通信的一个工具,好比现实生活中的插座,所有的家用电器想要工作都是基于插座进行,进程之间想要进行网络通信需要socket.

Socket负责进程之间的网络数据传输,好比数据的搬运工。

 2个进程之间通过Socket进行相互通讯,就必须有服务端和客户端

Socket服务端:等待其它进程的连接,可接受发来的消息、可以回复消息

Socket客户端:主动连接服务端、可以发送消息、可以接收回复

  •  Socket服务端编程

1.创建socket对象

import socket
socket_server = socket.socket()

2.绑定socket_server到指定IP和地址

socket_server.bind(host, port)

3.服务端开始监听端口

socket_server.listen(backlog)
# backlog为int整数,表示允许的连接数量,超出的会等待,可以不填,不填会自动设置一个合理值

4.接受客户端连接,获得连接对象

conn, address = socket_server.accept()
print(f"接收到客户端连接,连接来自{address}")
# accept方法是阻塞方法,如果没有连接,就会卡在当前这一行不向下执行代码
# accept返回的是一个二元元组,可以使用上述形式,用两个变量接受二元元组的2个元素

5.客户端连接后,通过recv方法,接收客户端发送的消息

复制代码
while True:
    data = conn.recv(1024).decode("UTF-8")
    # recv方法的返回值是字节数组(Bytes),可以通过decode使用UTF_8解码为字符串
    # recv方法的传参是buffsize,缓冲区大小,一般设置为1024即可
    if data == 'exit':
        break
    print("接收到发送来的数据:", data)
# 可以通过while True无限循环来保持和客户端进行数据交互
# 可以通过判定客户端发来的特殊标记,如exit,来退出无限循环
复制代码

6.通过conn(客户端当次连接对象),调用send方法可以回复消息

while True:
    data = conn.recv(1024).decode("UTF-8")
    if data == 'exit':
        break
    print("接收到发送来的数据:", data)
    
    conn.send("你好呀嘿嘿".encode("UTF-8"))

7.conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接

conn.close()
socket_server.close()

 

整体:

复制代码
import socket
# 创建Socket对象
socket_server = socket.socket()
# 绑定IP地址和端口
socket_server.bind("localhost", 8888)
# 监听端口
socket_server.listen(1)
# listen方法内接收一个整数传参数,便是接收的连接数量
# 等待客户端连接
conn, address = socket_server.accept()
# accept返回的是一个二元元组(连接对象, 客户端地址信息)
# 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接收二元元组内的两个元素
# accept()方法,是阻塞方法,如果没有连接,就会卡在当前这一行不向下执行代码

print(f"接收到客户端连接,连接来自{address}")


while True:
    # 接收客户端信息,要使用客户端和服务端的本次连接对象,而非socket_server对象
    data: str = conn.recv(1024).decode("UTF-8")
    # recv方法的返回值是字节数组(Bytes),可以通过decode使用UTF_8解码为字符串
    # recv方法的传参是buffsize,缓冲区大小,一般设置为1024即可
    print(f"客户端发来的消息是:{data}")
    # 发送回复消息
    msg = input("请输入你要和客户端回复的消息:")
    if msg == 'exit':
        break
    conn.send(msg.encode("UTF-8"))
# 可以通过while True无限循环来保持和客户端进行数据交互
# 可以通过判定客户端发来的特殊标记,如exit,来退出无限循环
while True:
    data = conn.recv(1024).decode("UTF-8")
    if data == 'exit':
        break
    print("接收到发送来的数据:", data)

    conn.send("你好呀嘿嘿".encode("UTF-8"))

# 关闭连接
conn.close()
socket_server.close()
复制代码
  • socket客户端编程

1.创建socket对象

import socket
socket_client = socket.socket()

2.连接到服务端

socket_client.connect("localhost", 8888)

3.发送消息

while True:
    # 可以通过无限循环来保证持续的发送消息给服务端
    send_msg = input("请输入要发送的消息:")
    if send_msg == 'exit':
        # 通过特殊标记来确保可以退出无限循环
        break
    socket_client.send(send_msg.encode("UTF-8"))        #消息需要编码为字节数组(UTF-8编码)

4.接收返回消息

while True:
    send_msg = input("请输入要发送的消息:").encode("UTF-8")
    socket_client.send(send_msg)

    recv_data = socket_client.recv(1024)    # 1024是缓冲区大小,一般1024即可
    # recv方法是阻塞式,即不接收到返回,就会卡在这一行等待
    print("服务端回复消息为:", recv_data.decode("UTF-8"))   # 接收的消息需要通过UTF-8解码为字符串

5.关闭连接

socket_client.close() # 最后通过close关闭连接

正则表达式

正则表达式,又称规则表达式,是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则)的文本。

简单来说,正则表达式就是使用:字符串定义规则,并通过规则去验证字符串是否匹配。

比如:验证一个字符串是否符合条件的电子邮箱地址,只需要配置好正则规则,即可匹配任意邮箱。

Python正则表达式,使用re模块,并基于re模块中三个基础方法来做正则匹配。

分别是:match、search、findall三个基础方法

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

从被匹配字符串开头进行匹配,匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空。

# 演示Python正则表达式re模块的3个基础匹配方法
import re
s = "python hello!"  # 如果这里是11python,match就找不到匹配项
# match  从头匹配
result = re.match("python", s)
print(result)
# 结果:<re.Match object; span=(0, 6), match='python'>
  • search(匹配规则, 被匹配字符串)

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

# 演示Python正则表达式re模块的3个基础匹配方法
import re
s = "11python hello! python Python"
result = re.search("python", s)
print(result)
# 结果:<re.Match object; span=(2, 8), match='python'>
  • findall(匹配规则,被匹配字符串)

匹配整个字符串,找出全部匹配项,找不到返回空list: [ ]

# 演示Python正则表达式re模块的3个基础匹配方法
import re
s = "python hello! python Python"
# findall 搜索全部匹配
result = re.findall("python", s)
print(result)
# 结果:['python', 'python']

 元字符匹配

单字符匹配:

# 演示Python正则表达式使用元字符进行匹配
import re
s = "python nihao 878sdh ah2hfs3 #hdfu"
result = re.findall(r'\d', s)   # 字符串前面带上r的标记,表示字符串中转义字符无效,就是普通字符的意思
print(result)       # 结果:['8', '7', '8', '2', '3']

找出特殊字符: re.findall(r'\W', s)

找出全部英文字母:  re.findall(r' [a-zA-Z]', s)

数量匹配

 边界匹配

 分组匹配

复制代码
# 正则表达式案例
import re
# 匹配账号,只能由字母和数字组成,长度限制6到10位
r = '^[0-9a-zA-Z]{6,10}$'
s = '123456_'
print(re.findall(r, s))
# 匹配QQ好,要求纯数字,长度5-11,第一位不为0
r = '^[1-9][0-9]{4,10}$'    # 是4-10,因为不算第一位,第一位已经单独考虑
s = '12314345'
print(re.findall(r, s))
复制代码

递归

递归是编程中一种非常重要的算法

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

 最典型的递归场景为找出一个文件夹中全部的文件

复制代码
import os.path


def get_file_recursion_from_dir(path):
    """
    从指定的文件夹中使用递归的方式,获取全部的文件列表
    :param path: 被判断的文件夹
    :return:  list,被包含的全部文件,如果目录不存在或者无文件就返回一个空list
    """
    file_list = []
    if os.path.exists(path):   # 判断路径是否存在,若存在则将这其中的所有目录的路径补全存放在new_path中
        new_path = path + "/" + f
        if os.path.isdir(new_path):     # 判断是否为文件
            # 进入到这里,表明这个目录是文件夹而不是文件
            file_list += get_file_recursion_from_dir(new_path)  # 为文件夹,则递归调动继续记录文件夹内的文件
        else:
            file_list.append(new_path)      # 进入这里表明是文件,则放入列表中
    else:
        print(f"指定的目录{path},不存在")
        return []   # 目录不存在,返回空列表
    return file_list

if __name__ == '__main__':
    get_file_recursion_from_dir("D:/test")
复制代码

 

posted on   gjwqz  阅读(27)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示