DeFFcode是一种跨平台的高性能视频帧解码器,通过内部封装ffmpeg,提供GPU解码支持,几行python代码就能够快速解码视频帧,并具有强大的错误处理能力。DeFFcode的APIs支持多种媒体流作为输入源,例如IP摄像机、常规多媒体文件、屏幕录制、图像序列、网络协议(例如 HTTP(s)、RTP/RSTP)等。由于FFmpeg的学习曲线非常陡峭,封装FFmpeg后的DeFFcode提供类似OpenCV-Python编码语法来帮助用户,使得在Python中学习、创建和开发基于FFmpeg的应用程序变得更加容易。DeFFcode的官方代码仓库见:deffcode。DeFFcode的官方文档见deffcode_doc

DeFFcode的作者专注于音视频流的处理,除了Deffcode,作者还开源了Python视频处理库VidGear。VidGear的具体使用见Python视频处理库VidGear使用指北。DeFFcode还处于快速发展阶段,许多功能还需要完善。VidGear提供了比DeFFcode更丰富的视频处理接口,但是DeFFcode提供了比VidGear更高效更专业的视频解码接口。如果想要从事音视频流解码相关工作,还是学习ffmpeg的C++代码使用。

入门ffmpeg使用或者想要对音视频处理有所了解推荐看看雷霄骅的博客。雷霄骅是视音频技术处理的专家,也是国内音视频领域无偿分享技术最多的程序员。但是很不幸雷霄骅因过度劳累于2016年与世长辞,所以大家还是多注意身体健康。身体才是革命的本钱,少加班,该休息就得休息,没有时间休息的人注定没有时间生病。

1 前置知识

1.1 安装

对于DeFFcode,python版本需要高于3.7。DeFFcode支持以下系统:

  • 2016以后的linux版本,推荐使用linux系统运行VidGear
  • Windows 7及以上版本
  • MacOS 10.12.6及以上版本

Deffcode安装代码如下:

pip install -U deffcode

特别要注意的是DeFFcode必须要安装ffmpeg执行文件。安装ffmpeg,其它系统自行搜索安装方法,ubuntu下直接输入:

sudo apt install ffmpeg

1.2 DeFFcode功能预览

视频流解码

DeFFcode核心功能就是利用ffmpeg进行视频解码。相关公开测试视频流地址为:

  • rtsp流:rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4,来源于https://www.wowza.com/developer/rtsp-stream-test
  • http流:http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8,来源于苹果提供的测试源
  • http流:https://abhitronix.github.io/html/Big_Buck_Bunny_1080_10s_1MB.mp4,来源于DeFFcode
  1. from deffcode import FFdecoder
  2. import cv2
  3. # FFedecoder创建视频源和视频解码规则,formulate在ffmpeg中执行语句
  4. # 本地视频
  5. # decoder = FFdecoder("test.mp4").formulate()
  6. # rtsp流
  7. decoder = FFdecoder("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4").formulate()
  8. # 从decoder中抓取RGB图像
  9. for frame in decoder.generateFrame():
  10. print(frame.shape)
  11. # 将rgb图像转换为bgr图像,送给opencv展示
  12. frame_bgr = frame[:, :, ::-1]
  13. cv2.imshow("Output Frame", frame_bgr)
  14. key = cv2.waitKey(1) & 0xFF
  15. if key == ord("q"):
  16. break
  17. # 安全关闭解码进程
  18. decoder.terminate()

视频流属性识别

对于给定的输入源,DeFFcode使用各种方法识别视频流其中包含的文件所有属性,比如是否包含音频,图像分辨率,视频码率。不同的视频流返回的属性参数不同,具体按需要探索下就行了。

  1. from deffcode import Sourcer
  2. # sourcer设置定位视频流中的数据信息,probe_stream探测视频流的输出
  3. sourcer = Sourcer("test.mp4").probe_stream()
  4. # 解析为python字典数据
  5. data = sourcer.retrieve_metadata()
  6. # pretty_json表示解析为类似json.dump后的json字符串
  7. print(sourcer.retrieve_metadata(pretty_json=True))

2 基础使用

2.1 解码视频文件

DeFFcode的FFdecoder API很容易支持多媒体视频文件路径作为其source参数的输入。通过它的frame_format参数,您可以轻松解码所有知名计算机视觉库(例如 OpenCV)都支持的任何像素格式的视频帧。FFdecoder API 的generateFrame()函数可用于多种方法来访问来自给定源的RGB帧,例如生成器(推荐方法)、调用with语句和迭代器。在下面示例中,我们将使用上述访问方法从给定的视频文件中解码默认的RGB24视频帧。

生成器调用

  1. from deffcode import FFdecoder
  2. decoder = FFdecoder("test.mp4").formulate()
  3. # 读取RGB24图像
  4. for frame in decoder.generateFrame():
  5. if frame is None:
  6. break
  7. print(frame.shape)
  8. decoder.terminate()

with调用

调用with语句方法可用于使代码更简单、更清晰、更易读。这种方法还自动处理FFdecoder API 中的formulate()和terminate()方法的管理,因此不需要显式调用它们。


  1. from deffcode import FFdecoder
  2. import cv2
  3. # 不需要调用formulate和terminate
  4. with FFdecoder("test.mp4") as decoder:
  5. for frame in decoder.generateFrame():
  6. if frame is None:
  7. break
  8. print(frame.shape)

迭代器调用

迭代器的调用方式类似于OpenCV-Python读取视频的方式。


  1. from deffcode import FFdecoder
  2. decoder = FFdecoder("test.mp4").formulate()
  3. while True:
  4. # next返回迭代器的下一个项目
  5. frame = next(decoder.generateFrame(), None)
  6. if frame is None:
  7. break
  8. print(frame.shape)
  9. decoder.terminate()

参数设置

  1. # 设置解码后的图像为bgr24,可以直接给opencv使用
  2. FFdecoder("test.mp4", frame_format="bgr24")
  3. # 设置解码后的图像为灰度图像,verbose输出解码的详细统计信息
  4. FFdecoder("test.mp4", frame_format="gray", verbose=True)
  5. # 设置解码后的图像为yuv420p格式,verbose输出解码的详细统计信息
  6. FFdecoder("test.mp4", frame_format="yuv420p", verbose=True)

2.2 解码本地摄像头和屏幕截取

这部分不同平台使用方法不同,而且涉及到很多参数的使用和软件安装,所以这里推荐自行阅读Decoding Live Feed Devices

2.3 解码网络流

与解码视频文件类似,DeFFcode 的 FFdecoder API直接支持具有特定协议(如RTSP/RTP、HTTP(s)、MPEG-TS 等)的网络流作为其source参数的输入。以下示例用的都是网络上的公开视频流,由于网速问题有可能连接不上。

http流解码

  1. from deffcode import FFdecoder
  2. import cv2
  3. # 获得BGR24图像
  4. # decoder = FFdecoder("ttp://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8", frame_format="bgr24").formulate()
  5. decoder = FFdecoder("https://abhitronix.github.io/html/Big_Buck_Bunny_1080_10s_1MB.mp4", frame_format="bgr24").formulate()
  6. for frame in decoder.generateFrame():
  7. if frame is None:
  8. break
  9. cv2.imshow("Output", frame)
  10. key = cv2.waitKey(1) & 0xFF
  11. if key == ord("q"):
  12. break
  13. cv2.destroyAllWindows()
  14. decoder.terminate()

RTSP/RTP流解码


  1. from deffcode import FFdecoder
  2. import cv2
  3. # 设置传输协议为tcp
  4. ffparams = {"-rtsp_transport": "tcp"}
  5. # 取流
  6. decoder = FFdecoder("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4", frame_format="bgr24", verbose=True, **ffparams).formulate()
  7. for frame in decoder.generateFrame():
  8. if frame is None:
  9. break
  10. cv2.imshow("Output", frame)
  11. key = cv2.waitKey(1) & 0xFF
  12. if key == ord("q"):
  13. break
  14. cv2.destroyAllWindows()
  15. decoder.terminate()

2.4 从图像序列捕获帧

特定命名图像序列读取

下面的代码展示了如何带有特定数字标记的图像序列逐帧读取图像。您可以使用以下FFmpeg命令从视频文件中提取时间长度为2s的图像序列,注意图像保存的文件夹路径应该要预先创建。

ffmpeg -t 2 -i test.mp4 imgs/image%02d.png

  1. from deffcode import FFdecoder
  2. import cv2
  3. # 设置特定数字开始读图,在本例为img01.png
  4. ffparams = {"-ffprefixes":["-start_number", "1"]}
  5. # 注意图像数大于三张
  6. # img%02d.png: 格式化输出文件名,本示例中输出img00.png,img01.png, img02.png等
  7. # 如果是jpeg图像序列,图像后缀名应该为jpeg而不是jpg
  8. decoder = FFdecoder("imgs/img%02d.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
  9. for frame in decoder.generateFrame():
  10. if frame is None:
  11. break
  12. cv2.imshow("Output", frame)
  13. key = cv2.waitKey(1) & 0xFF
  14. if key == ord("q"):
  15. break
  16. cv2.destroyAllWindows()
  17. decoder.terminate()

glob 模式

如果图像是连续的,但不一定是数字顺序,则通配符(*表示任意数量的任意字符)很有用,但是以下代码无法在windows下使用。

  1. from deffcode import FFdecoder
  2. import cv2
  3. # glob模式抓取图像
  4. # glob模式在 Windows FFmpeg 版本上不可用。
  5. ffparams = {"-ffprefixes":["-pattern_type", "glob"]}
  6. decoder = FFdecoder("imgs/img*.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
  7. for frame in decoder.generateFrame():
  8. if frame is None:
  9. break
  10. cv2.imshow("Output", frame)
  11. key = cv2.waitKey(1) & 0xFF
  12. if key == ord("q"):
  13. break
  14. cv2.destroyAllWindows()
  15. decoder.terminate()

循环读取图像

下面的设置展示了从单个或者多个图像循环读取的示例。注意jpg图像都以jpeg后缀命名。

  1. # `-loop 1` 表示循环读取,loop是bool类型
  2. ffparams = {"-ffprefixes":["-loop", "1"]}
  3. # 设置单张图像循环读取
  4. decoder = FFdecoder("imgs/img01.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
  5. # 设置多张图像循环读取
  6. decoder = FFdecoder("imgs/img%02d.png", frame_format="bgr24", verbose=True, **ffparams).formulate()

2.5 保存视频

通过OpenCV保存视频

  1. from deffcode import FFdecoder
  2. import json, cv2
  3. decoder = FFdecoder("test.mp4", frame_format="bgr24").formulate()
  4. # decoder.metadata读取视频属性json数据,并转码为字典
  5. metadata_dict = json.loads(decoder.metadata)
  6. FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
  7. FRAMERATE = metadata_dict["source_video_framerate"]
  8. FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
  9. writer = cv2.VideoWriter("output.avi", FOURCC, FRAMERATE, FRAMESIZE)
  10. for frame in decoder.generateFrame():
  11. if frame is None:
  12. break
  13. writer.write(frame)
  14. cv2.imshow("Output", frame)
  15. key = cv2.waitKey(1) & 0xFF
  16. if key == ord("q"):
  17. break
  18. cv2.destroyAllWindows()
  19. decoder.terminate()
  20. writer.release()

通过VidGear保存视频(推荐)

使用这种方式保存视频,视频文件压缩率更高,保存速度更快,但是也CPU利用率也更高。

  1. from deffcode import FFdecoder
  2. from vidgear.gears import WriteGear
  3. import json
  4. decoder = FFdecoder("test.mp4", frame_format="bgr24", verbose=True).formulate()
  5. output_params = {
  6. "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"]
  7. }
  8. writer = WriteGear(output_filename="output.mp4", **output_params)
  9. for frame in decoder.generateFrame():
  10. if frame is None:
  11. break
  12. writer.write(frame)
  13. decoder.terminate()
  14. writer.close()

参数设置

以下是各种ffmpeg参数的设置方法,ffparams设置参数后,然后传入FFdecoder。

  1. # 截取前3s视频,按倒序保存
  2. ffparams = {
  3. "-vf": "trim=end=7,reverse"
  4. }
  5. # 裁剪中央输入区域,宽高都为输入视频的2/3,然后拉伸为原图像尺寸
  6. ffparams = {
  7. "-vf": "crop=2/3*in_w:2/3*in_h"
  8. }
  9. # 逆时针旋转图像30度,用绿色填充旋转图像未覆盖的区域
  10. ffparams = {
  11. "-vf": "trim=end=7,rotate=angle=-30*PI/180:fillcolor=green"
  12. }
  13. # 保存前7秒视频,逆时针旋转90度,保持纵向布局
  14. # dir为旋转方向,具体可以搜搜ffmpeg transpose
  15. ffparams = {
  16. "-vf": "trim=end=7,transpose=dir=2:passthrough=portrait"
  17. }
  18. # 水平翻转,然后缩放图像到其原始大小的一半
  19. ffparams = {
  20. "-vf": "hflip,scale=w=iw/2:h=ih/2"
  21. }
  22. # 设置参数
  23. decoder = FFdecoder(
  24. "test.mp4", frame_format="bgr24", verbose=True, **ffparams
  25. ).formulate()

2.6 特定帧存储

DeFFcode的FFdecoder API使用FFmpeg参数-ss提供轻松且精确的帧搜索,使我们能够从输入源的特定部分保存图像。

  1. from deffcode import FFdecoder
  2. from PIL import Image
  3. # 定义FFmpeg参数以查找00:00:01.45处图像,并获得一帧图像
  4. ffparams = {"-ss": "00:00:01.45", "-frames:v": 1}
  5. # 初始化参数
  6. decoder = FFdecoder("test.mp4", **ffparams).formulate()
  7. # 读取图像
  8. frame = next(decoder.generateFrame(), None)
  9. # 保存图像
  10. if not (frame is None):
  11. im = Image.fromarray(frame)
  12. im.save("test.png")
  13. else:
  14. raise ValueError("Something is wrong!")
  15. decoder.terminate()

3 进阶使用

3.1 虚拟源生成与解码

DeFFcode提供各种创建虚拟视频流的示例,具体使用见Decoding Live Virtual Sources,这里只列出两个经典的案例。

从测试源模式生成和解码帧

testsrc图生成一个测试视频模式,显示颜色模式、滚动渐变和时间戳。这对于测试目的很有用。

  1. from deffcode import FFdecoder
  2. import cv2
  3. # 定义参数
  4. ffparams = {
  5. # 播放时间为10秒
  6. "-ffprefixes": ["-t", "10"],
  7. }
  8. # 生成尺寸为1280x720,帧率30的testsrc测试图像
  9. decoder = FFdecoder(
  10. "testsrc=size=1280x720:rate=30",
  11. source_demuxer="lavfi",
  12. frame_format="bgr24",
  13. **ffparams
  14. ).formulate()
  15. for frame in decoder.generateFrame():
  16. if frame is None:
  17. break
  18. cv2.imshow("Output", frame)
  19. key = cv2.waitKey(1) & 0xFF
  20. if key == ord("q"):
  21. break
  22. cv2.destroyAllWindows()
  23. decoder.terminate()

使用自定义文本效果从渐变生成和解码帧

  1. from deffcode import FFdecoder
  2. import cv2
  3. ffparams = {
  4. "-ffprefixes": ["-t", "15"], # 15秒播放
  5. "-vf": "drawtext=" # 绘制文本
  6. + "text='%{localtime\:%X}':" # 时间 (HH::MM::SS)
  7. + "fontfile='c\:\/windows\/fonts\/arial.ttf':" # 字体
  8. + "x=(w-text_w)/2:y=h-40*t:" # 向上滚动效果
  9. + "fontsize=50:" # 字体大小
  10. + "fontcolor=white", # 字体颜色
  11. }
  12. decoder = FFdecoder(
  13. "gradients=n=3",
  14. source_demuxer="lavfi",
  15. frame_format="bgr24",
  16. **ffparams
  17. ).formulate()
  18. for frame in decoder.generateFrame():
  19. if frame is None:
  20. break
  21. cv2.imshow("Output", frame)
  22. key = cv2.waitKey(1) & 0xFF
  23. if key == ord("q"):
  24. break
  25. cv2.destroyAllWindows()
  26. decoder.terminate()

3.2 硬件加速视频解码

FFmpeg 提供对不同平台上不同支持的专用硬件的访问,以执行一系列与视频相关的任务,以更快地完成或使用更少的其他资源(特别是 CPU)。使用ffmpeg -decoders终端命令列出所有 FFmpeg 支持的解码器。可以看看具体ffmpeg支持本机哪种硬件解码。

比如判断ffmpeg是否可以通过依赖于gpu cuda的h264_cuvid解码,可以输入以下指令。如果输出包含了h264_cuvid那么就是支持的,可以通过gpu加速解码。

linux系统:ffmpeg -hide_banner -decoders | grep h264

windows系统:ffmpeg -hide_banner -decoders | findstr h264

如果支持h264_cuvid加速解码,可以尝试以下示例代码。

  1. from deffcode import FFdecoder
  2. import cv2
  3. ffparams = {
  4. "-vcodec": "h264_cuvid", # CUVID H.264加速视频解码
  5. "-ffprefixes": ["-vsync", "0"], # 视频同步方法,一般都是自动,这里设置为0
  6. }
  7. decoder = FFdecoder(
  8. "test.mp4", frame_format="bgr24", verbose=True, **ffparams
  9. ).formulate()
  10. for frame in decoder.generateFrame():
  11. if frame is None:
  12. break
  13. cv2.imshow("Output", frame)
  14. key = cv2.waitKey(1) & 0xFF
  15. if key == ord("q"):
  16. break
  17. cv2.destroyAllWindows()
  18. decoder.terminate()

3.3 复杂效果添加

添加水印

以下代码展示了如何在读取的视频中添加图像,并保存视频到本地。

  1. from deffcode import FFdecoder
  2. from vidgear.gears import WriteGear
  3. import json, cv2
  4. # 定义带有复杂水印的视频过滤器
  5. ffparams = {
  6. "-ffprefixes": ["-t", "5"], # 视频总长度为5秒
  7. "-clones": [
  8. "-i",
  9. "watermark.png",
  10. ],
  11. "-filter_complex": "[1]format=rgba," # 设置水印图像输入格式
  12. + "colorchannelmixer=aa=0.7[logo];" # 设置水印透明度,数值越小越透明
  13. + "[0][logo]overlay=W-w-{pixel}:H-h-{pixel}:format=auto,".format(
  14. pixel=5 # 设置水印图片在距离输入视频右下角5个像素处
  15. )
  16. + "format=bgr24", # 设置输出格式
  17. }
  18. decoder = FFdecoder(
  19. "test.mp4", frame_format="bgr24", verbose=True, **ffparams
  20. ).formulate()
  21. output_params = {
  22. "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
  23. }
  24. # 保存视频
  25. writer = WriteGear(output_filename="output.mp4", **output_params)
  26. for frame in decoder.generateFrame():
  27. if frame is None:
  28. break
  29. writer.write(frame)
  30. decoder.terminate()
  31. writer.close()

图像效果混合

下面的代码展示了如何往图像序列中混合虚拟效果。

  1. from deffcode import FFdecoder
  2. from vidgear.gears import WriteGear
  3. import cv2, json
  4. ffparams = {
  5. "-ffprefixes": [
  6. "-t", "10", # 视频长度为10s
  7. "-f", "lavfi", # 使用输入虚拟数据
  8. "-i", "mandelbrot=rate=25", # 视频帧率
  9. ],
  10. "-custom_resolution": (1280, 720), # 重新设置图像 1280x720
  11. "-filter_complex":"[1:v]format=yuv444p[v1];"
  12. + "[0:v]format=gbrp10le[v0];"
  13. + "[v1][v0]scale2ref[v1][v0];"
  14. + "[v0][v1]blend=all_mode='heat',"
  15. + "format=yuv422p10le[v]",
  16. "-map": "[v]",
  17. }
  18. # 设置图像序列路径
  19. decoder = FFdecoder(
  20. "./imgs/image-%03d.png", frame_format="bgr24", verbose=True, **ffparams
  21. ).formulate()
  22. output_params = {
  23. "-input_framerate": 25,
  24. }
  25. writer = WriteGear(output_filename="output.mp4", **output_params)
  26. for frame in decoder.generateFrame():
  27. if frame is None:
  28. break
  29. writer.write(frame)
  30. decoder.terminate()
  31. writer.close()

此外Deffcode还支持添加各种艺术效果,具体方法可以阅读transcode-art-filtergraphs

3.4 视频属性数据更改

添加新属性

下面代码展示了读取视频后,往读取的属性数据中添加新的属性,注意该操作并不更改视频的实际属性数据。

  1. from deffcode import FFdecoder
  2. import json
  3. decoder = FFdecoder("test.mp4", verbose=True)
  4. # 设置字典数据
  5. data = dict(
  6. mystring="abcd",
  7. myint=1234,
  8. mylist=[1, "Rohan", ["inner_list"]],
  9. mytuple=(1, "John", ("inner_tuple")),
  10. mydict={"anotherstring": "hello"},
  11. myjson=json.loads('{"name": "John", "age": 30, "city": "New York"}'),
  12. )
  13. # 分配视频的属性数据
  14. decoder.metadata = data
  15. decoder.formulate()
  16. print(decoder.metadata)
  17. decoder.terminate()

修改已有视频属性

在视频流解码前,可以设置视频流的属性数据,那么就会以更改后的属性解码图像。

  1. from deffcode import FFdecoder
  2. import cv2
  3. decoder = FFdecoder("test.mp4", verbose=True)
  4. # 替换属性数据,会以当前属性解码视频
  5. decoder.metadata = {
  6. "output_frames_pixfmt": "gray", # 灰度图
  7. "source_video_resolution": [352, 288], # 宽高更改为352,288
  8. }
  9. decoder.formulate()
  10. print(decoder.metadata)
  11. for frame in decoder.generateFrame():
  12. if frame is None:
  13. break
  14. cv2.imshow("Output gray", frame)
  15. key = cv2.waitKey(1) & 0xFF
  16. if key == ord("q"):
  17. break
  18. cv2.destroyAllWindows()
  19. decoder.terminate()

4 参考

[常用工具] Python视频解码库DeFFcode使用指北的更多相关文章

  1. [常用工具] Python视频处理库VidGear使用指北

    VidGear是一个高性能的Python视频处理库,它在预载多个专业视频图像处理库的基础上,如OpenCV.FFmpeg.ZeroMQ.picamera.starlette.yt_dlp.pyscre ...

  2. 常用的 Python 标准库都有哪些?

    标准库:os 操作系统,time 时间,random 随机,pymysql 连接数据库,threading 线程,multiprocessing进程,queue 队列. 第三方库:django 和 f ...

  3. [python] 向量检索库Faiss使用指北

    Faiss是一个由facebook开发以用于高效相似性搜索和密集向量聚类的库.它能够在任意大小的向量集中进行搜索.它还包含用于评估和参数调整的支持代码.Faiss是用C++编写的,带有Python的完 ...

  4. Java常用工具类题库

    一.    填空题 在Java中每个Java基本类型在java.lang包中都在一个相应的包装类,把基本类型数据转换为对象,其中包装类Integer是___Number__的直接子类. 包装类Inte ...

  5. 常用的python标准库

    os  :   操作系统接口 sys:    命令行操作 re : 正则模块 math :   数学模块 time,timedate: 日期模块 random: 随机数模块 threading: 线程 ...

  6. Python之locust踩坑指北

    坑点1:locust安装报错 其中一种情况:error:Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visua ...

  7. 『Python题库 - 简答题』 Python中的基本概念 (121道)

    ## 『Python题库 - 简答题』 Python中的基本概念 1. Python和Java.PHP.C.C#.C++等其他语言的对比? 2. 简述解释型和编译型编程语言? 3. 代码中要修改不可变 ...

  8. Python 标准库中的装饰器

    题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...

  9. 常用python机器学习库总结

    开始学习Python,之后渐渐成为我学习工作中的第一辅助脚本语言,虽然开发语言是Java,但平时的很多文本数据处理任务都交给了Python.这些年来,接触和使用了很多Python工具包,特别是在文本处 ...

随机推荐

  1. 【机器学习】利用 Python 进行数据分析的环境配置 Windows(Jupyter,Matplotlib,Pandas)

    环境配置 安装 python 博主使用的版本是 3.10.6 在 Windows 系统上使用 Virtualenv 搭建虚拟环境 安装 Virtualenv 打开 cmd 输入并执行 pip inst ...

  2. 浅谈-动态路由之OSPF的理解

    路由 在网络中,路由相当于就是一张地图,让路由器知道这个对应的IP数据包应该往哪端口.网段走:而这个"地图"我们称之为路由表,不同的目的IP路由表的下一个跳也不同,其生成方式有又有 ...

  3. 细聊.Net Core中IServiceScope的工作方式

    前言 自从.Net Core引入IOC相关的体系之后,关于它的讨论就从来没有停止过,因为它是.Net Core体系的底层框架,你只要使用了.Net Core的时候就必然会用到它.当然关于使用它的过程中 ...

  4. 使用react+redux实现弹出框案例

    redux 实现弹出框案例 实现效果,点击显示按钮出现弹出框,点击关闭按钮隐藏弹出框 新建弹出框组件 src/components/Modal.js, 在index.js中引入app组件,在app中去 ...

  5. 40.TokenAuthentication认证

    TokenAuthentication认证介绍 TokenAuthentication是一种简单的基于令牌的HTTP认证 适用于CS架构,例如普通的桌面应用程序或移动客户端   TokenAuthen ...

  6. C#--String.Substring方法

    第一种:String.SubString(int start,int length)    截取指定长度的字符串 这里有两个int型的参数  string表示字符串截取的起始位置,length表截取的 ...

  7. Windows下自动云备份思源笔记到Gitee

    前言 思源笔记是一款本地笔记为主的软件,其目前提供了148元/year的付费同步功能,但对于21世纪中国难民而言还是太贵啦. 条件允许的同学还是使用官方的同步,支持下作者. 所以,就在思考有没有白嫖的 ...

  8. Python基础之函数:3、多层语法糖、装饰器和装饰器修复技术及递归函数

    目录 一.多层语法糖 1.什么是多层语法糖: 2.多层语法糖用法: 二.有参装饰器 1.什么是有参装饰器: 2.有参装饰器的作用: 三.装饰器修复技术 1.什么是装饰器修复技术: 四.递归函数 1.什 ...

  9. 聊聊kafka

    两个月因为忙于工作毫无输出了,最近想给团队小伙伴分享下kafka的相关知识,于是就想着利用博客来做个提前的准备工作了:接下来会对kafka做一个简单的介绍,包括利用akf原则来解析单机下kafk的各个 ...

  10. 【iOS逆向与安全】frida-trace入门

    前言 frida-trace是一个用于动态跟踪函数调用的工具.支持android和ios.安装教程请参考官网.工欲善其事必先利其器.本文将以某App为示范,演示frida-trace的各种方法在iOS ...