读源码 - stagesepx
背景
近段时间笔者在GitHub 发现一个有意思的工具:stagesepx ,经过这段时间的学习和研究,也基本将其应用于实际项目中,并产生了不错的效果,而本文旨在于记录stagesepx源码中诸多优雅的用法和思路,作以学习、积累
一、概述
stagesepx
轻量化的、基于图像处理与机器学习的、全自动的视频分析工具。它提供了丰富的可定制性,能够根据你的实际需求分析视频并将其拆分为一系列阶段。在此之后,你可以清晰地得知视频包含了几个阶段、以及每个阶段发生了什么。而这一切都是自动完成的。
更多内容请移步GitHub项目地址,此外stagesepx作者也很贴心的给出了开箱即用的实例:work_with_stagesepx
二、源码中优雅的用法
优雅的赋值/返回
# 赋值/返回,当输入为空时,赋一个固定值,否则将输入赋值/返回
def foo(input):
return input or ‘null'
# return input if input else ’null'
递归方法新建多级目录
import os
# target_dir - 目标目录
# exist_ok - 默认为False,表示当新建目录存在时抛异常
os.makedirs(target_dir, exist_ok=True)
更简洁的日志输出
from loguru import logger
logger.debug('this is a debug log')
logger.info('this is a info log')
logger.warning('this is a warning log')
logger.error('this is a error log')
logger.success('this is a success log')
>>> output
2020-02-26 17:55:12.681 | DEBUG | __main__:<module>:38 - this is a debug log
2020-02-26 17:55:12.681 | INFO | __main__:<module>:39 - this is a info log
2020-02-26 17:55:12.681 | WARNING | __main__:<module>:40 - this is a warning log
2020-02-26 17:55:12.681 | ERROR | __main__:<module>:41 - this is a error log
2020-02-26 17:55:12.681 | SUCCESS | __main__:<module>:42 - this is a success log
格式化输出的另一种姿势
s = 'hello'
print(f'{s}, world !')
基于生成器读取多个文件
上下文管理的生成器常常与with联合使用
import contextlib
# 上下文管理生成器
@contextlib.contextmanager
def op(fp):
res = open(fp, 'rb')
try:
yield res
finally:
res.close()
for ff in ['./ss.py', './test_adbutils.py']:
with op(ff) as rf:
res = rf.readline()
while res:
print(res)
res = rf.readline()
sorted进阶
# key - 可自定义排序的基准,通常与lambda结合
# reverse - bool类型,默认为False表示不颠倒(升序)
l = [(1,3), (-1, 0), (3, 7)]
l0 = sorted(l, key=lambda x: x[0])
l1 = sorted(l, key=lambda x: x[1])
>>> output
l
Out[21]: [(1, 3), (-1, 0), (3, 7)]
l0
Out[22]: [(-1, 0), (1, 3), (3, 7)]
l1
Out[23]: [(-1, 0), (1, 3), (3, 7)]
入参类型限制
python3.5引入
通常方法的入参类型限制的格式如下
# 不带初始值
def func(a: int, b: str, c: bool):
......
# 带初始值
def func_with_args(
a: int = 0,
b: str = None,
):
......
可引入typing,提供更多的类型
# typing.Union[a, b, c] - 表示path入参类型为a/b/c其中一种即可,否则IDE warn提示
# target_size: typing.Tuple[int, int] = None - 表示target_size为元组类型,且只能有两个整形
# _hook_list: typing.List[BaseHook] = list() - 表示_hook_list为BaseHook的列表类型
# As follows:
import typing
class VideoObject(object):
def __init__(
self,
path: typing.Union[bytes, str, os.PathLike],
pre_load: bool = None,
fps: int = None,
*_,
**__,
):
self.path: str = str(path)
self.data: typing.Optional[typing.Tuple[VideoFrame]] = tuple()
......
绝对安全的路径
# method 1
import os
PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)
# methon 2
from pathlib import Path
P = lambda p: Path(p).resolve()
__file__ - 返回当前python文件所在的路径
os.path.dirname(__file__) - 返回当前python文件所在的目录
os.path.dirname/basename() - 分别为获取目标所在的目录和目标名
os.path.split() - 拆分路径为:[目录/路径的头, 目录/路径的尾]
os.path.splitext('./demo.log') - ('./demo', '.log')
# os.path.dirname/basename()实现
def basename(p):
"""Returns the final component of a pathname"""
return split(p)[1]
# Return the head (dirname) part of a path.
def dirname(p):
"""Returns the directory component of a pathname"""
return split(p)[0]
josn.dumps/dump()进阶
d = {'1': 2, '3': 4, '0': 3, '中国': 'ss', 'b': 'inf'}
res = json.dumps(
d,
ensure_ascii=False, # 是否使用ascii
skipkeys=True, # 跳过非int str float bool None的key
indent=None, # 可设置缩紧层级
separators=(', ', ': '), # key vaules的分离格式
sort_keys=True # 是否按照key排序,注意排序时要求key类型统一
)
print(res)
pathlib库
参考:https://www.cnblogs.com/huangm1314/p/11318514.html
from pathlib import Path
Path.cwd()
Out[23]: PosixPath('/Users/ssfanli/Myfolder/pyproj/owner/stagesepx')
Path.home()
Out[24]: PosixPath('/Users/ssfanli')
res = Path('./demo.mp4')
print(res, type(res))
demo.mp4 <class 'pathlib.PosixPath'>
# 属性
# .nane - 文件名,包含拓展名
# .stem - 仅文件名,不包含拓展名
# .parent - 上一级目录名
# .suffix - 获取文件的拓展名
# .anchor - 哪个盘
abs_p = p.resolve()
abs_p
PosixPath('/Users/ssfanli/Myfolder/pyproj/work/YSPTimeConsuming/main.py')
abs_p.name
'main.py'
abs_p.stem
'main'
abs_p.parent
PosixPath('/Users/ssfanli/Myfolder/pyproj/work/YSPTimeConsuming')
abs_p.suffix
'.py'
abs_p.anchor
'/'
# iterdir(‘./’) - 返回'./'路径下的所有内容的生成器
p = Path('./')
all_p = p.iterdir()
for i in all_p:
print(i)
>>> output
pyrightconfig.json
LICENSE
test
......
any & all
any - 检查可迭代对象,只要有一个为真则返回True,否则返回False
all - 检查可迭代对象,全部为真则返回True,否则返回False
# 源码
def all(*args, **kwargs): # real signature unknown
"""
Return True if bool(x) is True for all values x in the iterable.
If the iterable is empty, return True.
"""
pass
def any(*args, **kwargs): # real signature unknown
"""
Return True if bool(x) is True for any x in the iterable.
If the iterable is empty, return False.
"""
pass
while...continue <=> for...if
# while循环
a = 1
while a < 10:
if a % 2:
print(a)
a += 1
continue
print(f'{a} is even number')
a += 1
# for循环
for a in range(10):
if a % 2:
print(a)
else:
print(f'{a} is even number')
>>> output
1
2 is even number
3
4 is even number
5
6 is even number
7
8 is even number
9
# 注意⚠️
# 无continue while循环依然继续,但是if循环之后会继续往下走,产生bug
# continue,在此处的作用时结束if循环,重新回到while大循环中
a = 1
while a < 10:
if a % 2:
print(a)
a += 1
# continue
print(f'{a} is even number')
a += 1
python私有变量
“单下划线” 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量
“双下划线” 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据,但依然可以通过如:a._A__a方式访问
class A:
def __init__(self):
self.a = 'a'
self._a = '_a'
self.__a = '__a'
a = A()
a.a
Out[66]: 'a'
a._a
Out[67]: '_a'
a.__a
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-68-52cb5731dd97>", line 1, in <module>
a.__a
AttributeError: 'A' object has no attribute '__a'
a._A__a
Out[69]: '__a'
获取当前类名和方法名
参考:https://www.cnblogs.com/yoyoketang/p/9231320.html
import sys
import inspect
# inspect模块动态获取当前运行的函数名(或方法名称)
def get_cur_func_name_2():
return inspect.stack()[1][3]
class A:
def get_cul_cls_name(self):
print(self.__class__.__name__)
@staticmethod
def get_cul_func_name():
print(sys._getframe().f_code.co_name)
print(f'cur_func_name: {get_cur_func_name_2}')
父类调用子类重写的方法
import inspect
def get_cur_func_name():
return inspect.stack()[1][3]
class A:
def __init__(self):
self.a = 'a'
self._a = '_a'
self.__a = '__a'
@staticmethod
def t():
print(f'cul_func_name_by_method 1: {sys._getframe().f_code.co_name}: ')
print(f'cul_func_name_by_method 2: {get_cur_func_name()}')
def tt(self):
# TODO: 此时父类直接调用的是子类中重写的t()方法?
self.t()
print(self.__class__.__name__)
class B(A):
def __init__(self):
super().__init__()
self.b = 'b'
self._b = '_b'
self.__b = '__b'
def t(self):
super().t()
ab_a_b = self.a + self.b + self._a + self._b
# 子类无法访问父类中`__`开头的属性或方法,除非这样访问`self._A__a`
# __a__b = self.__a + self.__b
print(
f'ab_a_b = {ab_a_b}\n',
# f'__a__b = {__a__b}'
)
if __name__ == '__main__':
b = B()
b.tt()
python图像比较
参考:https://www.jianshu.com/p/0c3ac46af8fd
SSIM的值范围[-1, 1],1代表完全相同
hook特性
非常nice的逻辑
__str__ & __repr__
https://baijiahao.baidu.com/s?id=1596817611604972751&wfr=spider&for=pc
读源码 - stagesepx的更多相关文章
- [一起读源码]走进C#并发队列ConcurrentQueue的内部世界
决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写.前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列Concurren ...
- Java读源码之ReentrantLock
前言 ReentrantLock 可重入锁,应该是除了 synchronized 关键字外用的最多的线程同步手段了,虽然JVM维护者疯狂优化 synchronized 使其已经拥有了很好的性能.但 R ...
- Java读源码之ReentrantLock(2)
前言 本文是 ReentrantLock 源码的第二篇,第一篇主要介绍了公平锁非公平锁正常的加锁解锁流程,虽然表达能力有限不知道有没有讲清楚,本着不太监的原则,本文填补下第一篇中挖的坑. Java读源 ...
- Java读源码之CountDownLatch
前言 相信大家都挺熟悉 CountDownLatch 的,顾名思义就是一个栅栏,其主要作用是多线程环境下,让多个线程在栅栏门口等待,所有线程到齐后,栅栏打开程序继续执行. 案例 用一个最简单的案例引出 ...
- 阅读源码很重要,以logback为例,分享一个小白都能学会的读源码方法
作为一个程序员,经常需要读一些开源项目的源码.同时呢,读源码对我们也有很多好处: 1.提升自己 阅读优秀的代码,第一可以提升我们自身的编码水平,第二可以开拓我们写代码的思路,第三还可能让我们拿到大厂 ...
- 读源码【读mybatis的源码的思路】
✿ 需要掌握的编译器知识 ★ 编译器为eclipse为例子 调试准备工作(步骤:Window -> Show View ->...): □ 打开调试断点Breakpoint: □ 打开变量 ...
- 跟大佬一起读源码:CurrentHashMap的扩容机制
并发编程——ConcurrentHashMap#transfer() 扩容逐行分析 前言 ConcurrentHashMap 是并发中的重中之重,也是最常用的数据结构,之前的文章中,我们介绍了 put ...
- 跟着大彬读源码 - Redis 1 - 启动服务,程序都干了什么?
一直很羡慕那些能读 Redis 源码的童鞋,也一直想自己解读一遍,但迫于 C 大魔王的压力,解读日期遥遥无期. 相信很多小伙伴应该也都对或曾对源码感兴趣,但一来觉得自己不会 C 语言,二来也不知从何入 ...
- 跟着大彬读源码 - Redis 3 - 服务器如何响应客户端请求?(下)
继续我们上一节的讨论.服务器启动了,客户端也发送命令了.接下来,就要到服务器"表演"的时刻了. 1 服务器处理 服务器读取到命令请求后,会进行一系列的处理. 1.1 读取命令请求 ...
随机推荐
- TCP 的三次握手和四次挥手
参考资料: 1.TCP的三次握手与四次挥手理解及面试题: 2.Http协议三次握手和四次挥手: 3.TCP通信的三次握手和四次撒手的详细流程(顿悟) 前置: 序号(也称序列号) - Sequence ...
- Java Servlet和Java Filter简介
一:简介servlet 1.什么是Servlet? Servlet可以通过多种方式进行描述,具体取决于上下文: (1)Servlet是一种用于创建web应用程序的技术 (2)Servlet是一个API ...
- Apache虚拟机的配置文件解说
1.为了方便管理虚拟主机,我决定使用一种方法,那就是修改httpd-vhosts.conf文件. 第一步首先要使扩展文件httpd-vhosts.conf生效: 1. 打开 apache/conf/h ...
- ChatterBot聊天机器人呢结构(五):ChatterBot对话流程
原文地址:http://www.bugingcode.com/blog/ChatterBot_Dialogue_process.html 创建机器人 部署机器人的各种属性,根据前面的章节里聊天机器人的 ...
- react-native start 启动错误解决方法
ERROR Error watching file for changes: EMFILE {"code":"EMFILE","errno" ...
- 在线做RAID命令
# 安装raid卡管理工具 wget http://10.12.30.102:10800/other/MegaCli-8.07.14-1.noarch.rpm -O /tmp/MegaCli-8.07 ...
- 换到GitHub 博客了
觉得还是github上面的代码风格看起来舒服些,所以决定把blog搬到github上面去了.以后这里就作为一个放资料的地方吧. github地址:http://l34rner.github.io/
- 理解 Java 内存模型的因果性约束
目录 理解 Java 内存模型的因果性约束 欢迎讨论 规范理解 例子练习 例子1 例子2 总结 理解 Java 内存模型的因果性约束 欢迎讨论 欢迎加入技术交流群186233599讨论交流,也欢迎关注 ...
- 告别ThinkPHP6的异常页面, 让我们来拥抱whoops吧
春节期间熟悉了TP6, 也写了一个TP6的博客程序,但系统的异常页面实在另外头疼,很多时候无法查看到是哪行代码出的问题. 所以就特别的想把whoops引进来,经过一系列的研究,终于找到了解决的办法: ...
- js中的0就是false,非0就是true。
在处理js代码判断真假时经常会这么写. var vale = fun();//从某个地方获取的值. if(!value){ 进入这里表示value为false或不存在 }但fun()可能得到的是数字0 ...