图像相关
10个Python图像处理工具,非常全了!
图像的RGB 色彩模式
RGB 三个颜色通道的变化和叠加得到各种颜色,其中
R 红色,取值范围,0-255
G 绿色,取值范围,0-255
B 蓝色,取值范围,0-255
一幅图像上的所有像素点的信息就完全可以采用矩阵来表示,通过矩阵的运算实现更加复杂的操作
网络图片读取
1 2 3 4 5 6 7 8 def get_url_img_io (url: str ) -> BytesIO: """ 获取网络图片的io流 """ return BytesIO(requests.get(url).content) def get_url_img (url: str ): """ 获取网络图片,并转为np.array """ return np.asarray(bytearray (get_url_img_io(url).read()), dtype="uint8" )
plt.imshow()
函数负责对图像进行处理,并显示其格式
plt.show()
则是将plt.imshow()处理后的函数显示出来
PIL Python图像库(PIL(Python Image Library) )是一个第三方Python包,为Python解释器添加了图像处理功能,允许处理照片并执行许多常见的图像文件操作,官方教程
打开图像:返回一个PIL.JpegImagePlugin.JpegImageFile对象
1 2 3 4 5 6 7 8 9 10 11 12 13 import requestsfrom PIL import Imageimg_path = r'frame.jpg' img_url = r'https://pic.hycbook.com/i/hexo/post_cover/蕾姆10.webp' im = Image.open (img_path) img = Image.open (get_url_img_io(img_url))
JpegImageFile对象常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import matplotlib.pyplot as plthistogram = image.histogram() plt.hist(histogram, bins=len (histogram)) plt.xlabel('Histogram' ) plt.show() cropped = image.crop((40 , 590 , 979 , 1500 )) img = im.resize((240 ,240 )) img.rotate(90 ).show()
使用过滤器:Pillow包含有几个过滤器,可以将其应用于图像。以下是当前支持的筛选器
BLUR
CONTOUR
DETAIL
EDGE_ENHANCE
EDGE_ENHANCE_MORE
EMBOSS
FIND_EDGES
SHARPEN
SMOOTH
SMOOTH_MORE
1 2 3 from PIL import ImageFilterblurred_image = image.filter (ImageFilter.BLUR)
显示图片
1 2 3 4 im = Image.open (img_path) im.show()
保存图像
1 2 3 4 infile = "in.jpg" outfile = "output.jpg" with Image.open (infile) as im: im.save(outfile)
类型转换
1 2 3 4 5 np.asanyarray(im) img = Image.fromarray(arr)
cv2 在计算机视觉项目的开发中,OpenCV 作为较大众的开源库,拥有了丰富的常用图像处理函数库,采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上,能够快速的实现一些图像处理和识别的任务。此外,OpenCV还提供了Java、python、cuda等的使用接口、机器学习的基础算法调用,从而使得图像处理和图像分析变得更加易于上手,让开发人员更多的精力花在算法的设计上
打开图像:cv2.imread(filepath, flags)
,返回一个np.array对象
flags:读入图片的标志
cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道
cv2.IMREAD_GRAYSCALE:读入灰度图片
cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道
1 2 3 4 5 6 7 8 9 img_path = r'frame.jpg' img_url = r'https://pic.hycbook.com/i/hexo/post_cover/蕾姆10.webp' img = get_url_img(img_url) image = cv2.imread(img_path)
打开视频
常见操作
resize
:
cv2.resize(InputArray src, OutputArray dst, Size, fx, fy, interpolation)
fx, fy
沿x轴,y轴的缩放系数
interpolation
插入方式
INTER_NEAREST
最近邻插值
INTER_LINEAR
双线性插值(默认设置)
INTER_AREA
使用像素区域关系进行重采样。
INTER_CUBIC
4x4像素邻域的双三次插值
INTER_LANCZOS4
8x8像素邻域的Lanczos插值
1 2 img_test = cv2.resize(img, (0 , 0 ), fx=0.25 , fy=0.25 , interpolation=cv2.INTER_NEAREST) img_test = cv2.resize(img_test, (0 , 0 ), fx=4 , fy=4 , interpolation=cv2.INTER_NEAREST)
RGB转灰度:
1 img2 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
灰度转RBG:
1 img3 = cv2.cv2Color(img, cv2.COLOR_GRAY2RGB)
显示图片
1 2 cv2.imshow("local pic" , image) cv2.waitKey(0 )
保存图像
1 cv2.imwrite(outfile, image)
时间相关库 协调世界时(Coordinated Universal Time, UTC)是一种标准的时间表述方式,它与时区无关
有些计算机,用某时刻与UNIX时间原点之间相差的秒数,来表示那个时刻所对应的时间 对于这些计算机来说,UTC是一种非常好的计时方式
Python提供了两种时间转换方式
小结 :
如果一定要使用time模块,那就只应该用它在UTC与宿主计算机的当地时区之间进行转换
对于其他类型的转换来说,还是使用datetime模块比较好
常见的时间模块
time : Python内置时间库,通过时间戳或元组表示时间,功能简约但实用
datetime : 内置日期库,处理日期时间对象和属性
dateutil : 基于datetime库的实用拓展,增强了对时间间隔和时间序列的处理
time库的使用
time
— Time access and conversions
time库是Python中处理时间的标准库
计算机时间的表达
提供获取系统时间并格式化输出功能
提供系统级精确计时功能,用于程序性能分析
时间获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 >>>time.time() 1568506809.169575 >>>time.ctime() 'Sun Sep 15 08:20:16 2019' >>>time.gmtime() time.struct_time(tm_year=2019 , tm_mon=9 , tm_mday=15 , tm_hour=0 , tm_min=21 , tm_sec=40 , tm_wday=6 , tm_yday=258 , tm_isdst=0 ) >>>time.mktime(time.localtime()) 1568508316.0
struct_time元组的属性如下
序号
属性
值
0
tm_year
2008
1
tm_mon
1 到 12
2
tm_mday
1 到 31
3
tm_hour
0 到 23
4
tm_min
0 到 59
5
tm_sec
0 到 61 (60或61 是闰秒)
6
tm_wday
0到6 (0是周一)
7
tm_yday
1 到 366(儒略历)
8
tm_isdst
-1, 0, 1, -1是决定是否为夏令时的旗帜
时间格式化
对象转字符串: time.strftime(format, obj)
字符串转结构化: time.strptime(time_str, format)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 >>>t = time.gmtime() >>>time.strftime("%Y-%m-%d %H:%M:%S" , t) '2019-09-15 00:24:23' >>>timeStr = '2018-01-26 12:55:20' >>>time.strptime(timeStr, "%Y-%m-%d %H:%M:%S" ) time.struct_time(tm_year=2019 , tm_mon=9 , tm_mday=15 , tm_hour=0 , tm_min=25 , tm_sec=50 , tm_wday=6 , tm_yday=258 , tm_isdst=-1 ) >>>time.mktime(time.localtime()) 1668562455.0 >>>time.localtime(time.time()) time.struct_time(tm_year=2022 , tm_mon=11 , tm_mday=16 , tm_hour=9 , tm_min=37 , tm_sec=9 , tm_wday=2 , tm_yday=320 , tm_isdst=0 )
常用格式(年月日、时分秒)
| 格式化字符串 | 日期/时间说明 | 值范围和实例 | | —————— | ——————— | ——————————————— | | %Y | 年份 | 0000~9999,例如:1900 | | %y | 去掉世纪的年份 | 00~99 | | %m | 月份 | 01~12,例如:10 | | %B | 月份名称 | January~December,例如:April | | %b | 月份名称缩写 | Jan~Dec,例如:Apr | | %H | 小时(24h制) | 00~23,例如:12 | | %h | 小时(12h制) | 01~12,例如:7 | | %M | 分钟 | 00~59,例如:26 | | %S | 秒 | 00~59,例如:26 |
其他格式
| 格式化字符串 | 日期/时间说明 | 值范围和实例 | | —————— | —————————— | ——————————————— | | %w | 星期中的第几天 | 0~6,0对应星期天 | | %d | 日期,一月中的第几天 | 01~31,例如:25 | | %j | 一年中的第几天 | 001~366 | | %A | 星期 | Monday~Sunday,例如:Wednesday | | %a | 星期缩写 | Mon~Sun,例如:Wed | | %p | 上/下午 | AM, PM,例如:PM | | %Z | 时区的名字 | |
将时间以合理的方式展示出来
格式化:类似字符串格式化,需要有展示模板
展示模板由特定的格式化控制符组成
strftime()方法
程序计时: 测量起止动作所经历时间的过程
测量时间:perf_counter()
产生时间:sleep()
1 2 3 4 5 6 7 8 9 10 11 >>>start = time.perf_counter() 318.66599499718114 >>>end = time.perf_counter() 341.3905185375658 >>>end - start 22.724523540384666 time.sleep(5 )
datetime 模块 python 处理日期和时间的标准库,常用 datetime 类,及 date 类 和 time 类,可做计算之类的操作
time模块比较底层,能完成的功能相对有限,这个时候就需要更高级的datetime模块来参与了
可以简单理解为,datetime模块是对time模块进行了更高一层的封装
基本定义和属性方法
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 32 33 34 import datetimeimport sysfrom typing import Tuple from dateutil import relativedeltafrom dateutil.parser import parsedef fn_basic () -> Tuple : """ 基本定义和属性方法 """ d_now = datetime.datetime.now() d_utc_now = datetime.datetime.utcnow() d_free = datetime.datetime(year=2022 , month=11 , day=11 ) print ("d_now " , d_now) print (f"d_now的详细信息: year:{d_now.year} month:{d_now.month} day:{d_now.day} " ) print (f"d_now的详细信息: hour:{d_now.hour} minute:{d_now.minute} second:{d_now.second} microsecond:{d_now.microsecond} " ) print ("d_free" , d_free) d = d_free.date() t = d_free.time() dt = datetime.datetime.combine(date=d, time=t) ts = d_free.timestamp() print ("ts " , ts) print (sys._getframe().f_code.co_name, "=" * 60 , '\n' ) return d_now, d_free d_now 2022 -11 -15 16 :59 :45.447093 d_now的详细信息: year:2022 month:11 day:15 d_now的详细信息: hour:16 minute:59 second:45 microsecond:447093 d_free 2022 -11 -11 00 :00 :00 ts 1668096000.0 fn_basic ============================================================
日期时间差异
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def fn_dif (d_now, d_free ): """ 日期时间差异 """ dif = d_now - d_free print ("d_free+dif==d_now is" , d_free + dif == d_now) d_dif = d_free + relativedelta.relativedelta(months=1 , days=-1 , hours=9 , minutes=-10 ) print ("d_dif " , d_dif) d_dif_abs = d_free + relativedelta.relativedelta(month=1 , day=5 , hour=9 , minute=10 ) print ("d_dif_abs " , d_dif_abs) print (sys._getframe().f_code.co_name, "=" * 60 , '\n' ) d_free+dif==d_now is True d_dif 2022 -12 -10 08:50 :00 d_dif_abs 2022 -01-05 09:10 :00 fn_dif ============================================================
日期时间的格式化
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 32 def fn_format_transform (): """ 日期时间的格式化 """ date_format_str = "%Y-%m-%d %H:%M:%S" date_format_str_2 = "{:%Y-%m-%d %H:%M:%S}" d_now = datetime.datetime.now() date_string = d_now.strftime(date_format_str) print ("date_string:" , date_string) date_string_2 = date_format_str_2.format (d_now) print ("date_string_2:" , date_string_2) d_from_str = datetime.datetime.strptime(date_string, date_format_str) print ("d_from_str:" , d_from_str) d_parse = parse(date_string) print ("parse:" , d_parse) print ("parse('Jan 31, 2021 10:45 PM'): " , parse('Jan 31, 2022 10:45 PM' )) print ("parse(str(d_now)): " , parse(str (d_now))) print (sys._getframe().f_code.co_name, "=" * 60 , '\n' ) date_string: 2022 -11 -15 16 :59 :45 date_string_2: 2022 -11 -15 16 :59 :45 d_from_str: 2022 -11 -15 16 :59 :45 parse: 2022 -11 -15 16 :59 :45 parse('Jan 31, 2021 10:45 PM' ): 2022 -01-31 22 :45 :00 parse(str (d_now)): 2022 -11 -15 16 :59 :45.447093 fn_format ============================================================
产生指定范围内的日期时间
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 def gen_date_times (): """ 产生指定范围内的日期时间 """ def date_time (p_start_time, p_end_time, p_format: str = '%Y-%m-%d' ): while p_start_time < p_end_time: select_time = p_start_time.strftime(p_format) print (select_time) p_start_time += datetime.timedelta(days=1 ) format_ = '%Y-%m-%d' end_time = datetime.datetime.now() start_time = end_time + relativedelta.relativedelta(days=-10 ) date_time(p_start_time=start_time, p_end_time=end_time, p_format=format_) 2022 -11 -052022 -11 -062022 -11 -072022 -11 -082022 -11 -092022 -11 -10 2022 -11 -11 2022 -11 -12 2022 -11 -13 2022 -11 -14 2022 -11 -15
calendar库的使用
提供与日历相关功能,如:为给定的月份或年份,打印文本日历
1 2 3 4 5 6 7 8 9 10 11 12 13 import calendarc = calendar.month(2019 , 9 ) print (c) September 2019 Mo Tu We Th Fr Sa Su 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
random库的使用
random库是使用随机数的Python标准库
伪随机数: 采用梅森旋转算法生成的(伪)随机序列中元素
random库主要用于生成随机数
使用random库: import random
主要方法
基本随机数函数: seed(), random()
扩展随机数函数: randint(), getrandbits(), uniform(), randrange(), choice(), shuffle()
基本随机数函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 >>>random.seed(10 ) >>>random.random() 0.5714025946899135 >>> state = random.getstate()>>> random.setstate(state)a = np.arange(10 ) b=['A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ] state=random.getstate() random.shuffle(a) print (a)random.setstate(state) random.shuffle(b) print (b)[9 4 5 0 1 2 6 8 7 3 ] ['J' , 'E' , 'F' , 'A' , 'B' , 'C' , 'G' , 'I' , 'H' , 'D' ]
扩展随机数函数
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 >>>random.randint(10 , 100 ) 64 >>>random.randrange(10 , 100 , 10 ) 80 >>>random.getrandbits(16 ) 37885 >>>random.uniform(10 , 100 ) 13.096321648808136 >>>random.choice([1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ]) 8 >>> s=[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ];>>> random.shuffle(s);>>> print (s)[3 , 5 , 8 , 9 , 6 , 1 , 2 , 7 , 4 ]
函数
描述
randint(a, b)
生成一个[a, b]之间的整数
randrange(m, n[, k])
生成一个[m, n)之间以k为步长的随机整数
getrandbits(k)
生成一个k比特长的随机整数
uniform(a, b)
生成一个[a, b]之间的随机小数
choice(seq)
从序列seq中随机选择一个元素
shuffle(seq)
将序列seq中元素随机排列,返回打乱后的序列
命令行脚本传参
命令行运行Python脚本时传入参数的三种方式
如果在运行python脚本时需要传入一些参数,例如gpus
与batch_size
,可以使用如下三种方式。
1 2 3 python script.py 0 ,1 ,2 10 python script.py --gpus=0 ,1 ,2 --batch-size=10 python script.py --gpus=0 ,1 ,2 --batch_size=10
这三种格式对应不同的参数解析方式,分别为sys.argv
, argparse
, tf.app.run
前两者是python自带的功能,后者是tensorflow
提供的便捷方式。
sys.argv sys
模块是很常用的模块, 它封装了与python解释器相关的数据,例如sys.modules
里面有已经加载了的所有模块信息,sys.path
里面是PYTHONPATH
的内容,而sys.argv
则封装了传入的参数数据
使用sys.argv
接收上面第一个命令中包含的参数方式如下:
1 2 3 4 5 6 import sysgpus = sys.argv[1 ] batch_size = sys.argv[2 ] print gpusprint batch_size
argparse
官方文档
使用argparse从命令行接收bool类型的参数
Python argparse库用法总结
速览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import argparseparser = argparse.ArgumentParser(prog='我的解析对象' ) parser.add_argument('--doc_path' , '-dp' ) parser.add_argument('-tip' , '--tp' ) opt = parser.parse_args() print (opt.tp, opt.doc_path)
可以用python arg.py -h
获取帮助
ArgumentParser 1 class argparse .ArgumentParser(prog=None , usage=None , description=None , epilog=None , parents=[], formatter_class=argparse.HelpFormatter, prefix_chars='-' , fromfile_prefix_chars=None , argument_default=None , conflict_handler='error' , add_help=True , allow_abbrev=True , exit_on_error=True )
创建一个新的ArgumentParser
对象,所有的参数都应当作为关键字参数传入,每个参数在下面都有它更详细的描述
prog - 程序的名称 (默认值: os.path.basename(sys.argv[0])
)
usage - 描述程序用途的字符串(默认值:从添加到解析器的参数生成)
description - 在参数帮助文档之后显示的文本 (默认值:无)
epilog - Text to display after the argument help (by default, no text)
parents - 一个 ArgumentParser
对象的列表,它们的参数也应包含在内
formatter_class - 用于自定义帮助文档输出格式的类
argparse.RawDescriptionHelpFormatter :表示 description 和 epilog 已经被正确的格式化
argparse.RawTextHelpFormatter :保留所有种类文字的空格,包括参数的描述
argparse.ArgumentDefaultsHelpFormatter :自动添加默认的值的信息到每一个帮助信息的参数中:
argparse.MetavarTypeHelpFormatter :每一个参数中使用 type 的参数名当作它的显示名
prefix_chars - 可选参数的前缀字符集合(默认值: ‘-‘),许多命令行会使用 -
当作前缀,比如 -f/--foo
。如果解析器需要支持不同的或者额外的字符,比如像 +f
或者 /foo
的选项,可以在参数解析构建器中使用 prefix_chars=
参数
fromfile_prefix_chars - 当需要从文件中读取其他参数时,用于标识文件名的前缀字符集合(默认值: None
)
argument_default - 参数的全局默认值(默认值: None
)
conflict_handler - 解决冲突选项的策略(通常是不必要的)
add_help - 为解析器添加一个 -h/--help
选项(默认值: True
),有时候可能会需要关闭额外的帮助信息
allow_abbrev - 如果缩写是无歧义的,则允许缩写长选项 (默认值:True
)
exit_on_error - 正常情况下,当你向 ArgumentParser
的 parse_args()
方法传入一个无效的参数列表时,它将会退出并发出错误信息。如果用户想要手动捕获错误,可通过将 exit_on_error
设为 False
来启用该特性
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 32 33 34 35 36 37 38 39 40 41 42 43 import argparseparser = argparse.ArgumentParser(prog="hyc_prog" , usage='%(prog)s [options]' , description='[%(prog)s] 参数解析描述,用于演示' , epilog="description 参数后显示额外的对程序的描述" , formatter_class=argparse.RawDescriptionHelpFormatter, prefix_chars='-+' , argument_default=argparse.SUPPRESS, ) with open ('args.txt' , 'w' , encoding=sys.getfilesystemencoding()) as fp: fp.write('-f\nbar' ) parser = argparse.ArgumentParser(fromfile_prefix_chars='@' ) parser.add_argument('-f' ) parser.parse_args(['-f' , 'foo' , '@args.txt' ]) parser = argparse.ArgumentParser(prog='PROG' , conflict_handler='resolve' ) parser.add_argument('-f' , '--foo' , help ='old foo help' ) parser.add_argument('--foo' , help ='new foo help' ) parser.print_help() >>> usage: PROG [-h] [-f FOO] [--foo FOO]options: -h, --help show this help message and exit -f FOO old foo help --foo FOO new foo help parser = argparse.ArgumentParser(exit_on_error=False ) parser.add_argument('--integers' , type =int ) try : parser.parse_args('--integers a' .split()) except argparse.ArgumentError: print ('Catching an argumentError' )
add_argument 1 ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type ][, choices][, required][, help ][, metavar][, dest])
定义单个的命令行参数应当如何解析,每个形参都在下面有它自己更多的描述,长话短说有:
name or flags - 一个命名或者一个选项字符串的列表,例如 foo 或 -f, —foo
action - 当参数在命令行中出现时使用的动作基本类型
nargs - 命令行参数应当消耗的数目
const - 被一些 action 和 nargs 选择所需求的常数
default - 当参数未在命令行中出现并且也不存在于命名空间对象时所产生的值
type - 命令行参数应当被转换成的类型
choices - A sequence of the allowable values for the argument.
required - 此命令行选项是否可省略(仅选项可用),只能用于可选参数(optional arguments)
help - 一个此选项作用的简单描述
metavar - 在使用方法消息中使用的参数值示例
dest - 被添加到parse_args()所返回对象上的属性名
name or flags
name就是指命令行参数中没有’-‘的参数名字例如’myname’,而flags就是指前面有’-‘的参数名,例如’-a’、’—age’
其中name对应位置参数 ,而flags对应可选参数 ,name在命令行必须输入,并按照顺序喂给程序
命令行传入参数时,对于位置参数我们直接给出其值,对于可选参数需要给出其flags。argparse会先将可选参数进行解析,对于剩余未解析的参数,传给位置参数
1 2 3 4 5 6 7 8 9 10 11 import argparseparser = argparse.ArgumentParser(description='a test' ) parser.add_argument('--age' ,'-a' ) parser.add_argument('myname' ) parser.add_argument('sex' ) args = parser.parse_args('tom boy --age 22' .split()) print (args)
命令行传入参数时,先写位置参数,再写可选参数
action: 指定了参数是如何被处理的,支持额操作如下
store:这个只是简单的存储这个参数值,这也是默认操作
store_const: 存储const指定的值,配合const参数
store_false和store_true: 分别对应存储False和True值,它们是store_const的特例
append:保存为列表格式,将每个参数的值添加到这个列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import argparseparser=argparse.ArgumentParser() parser.add_argument('--foo' ,action='store_const' ,const=42 ) parser.parse_args('--foo' .split()) Out[0 ]: Namespace(foo=42 ) parser.parse_args('' .split()) Out[1 ]: Namespace(foo=None ) parser.add_argument('--bar' , action='store_false' ) parser.parse_args('' .split()) Out[2 ]: Namespace(bar=True , foo=None ) parser.parse_args('--bar' .split()) Out[3 ]: Namespace(bar=False , foo=None ) parser = argparse.ArgumentParser() parser.add_argument('--foo' , action='append' ) parser.parse_args('--foo 1 --foo 2' .split()) Out[5 ]: Namespace(foo=['1' , '2' ])
nargs: nargs的意思就是输入参数的个数
N—某正整数 : 指定好后,不能输入多了,也不能输入少了
‘?’: 这时代表parser会读取0个或1个参数,具体遵循下面的原则 :
如果给出了1个参数,照常读取这个参数保存起来
如果只给出了flags,比如‘—age’后面未给出具体值,则保存const参数的值(如果const未给出则为None)
如果什么都没给,则保存default参数的值(如果default未给出则为None)
‘*‘: 不确定具体个数,那么可以用nargs=*
‘+’: 要求参数的个数必须大于
如果不给flags,parser会用default的值;如果只给flags,不给值,此时会报错
而当nargs=’*’时,就算只给flags不给值,也不会报错,会得到一个空列表参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import argparseparser = argparse.ArgumentParser(description='a test' ) parser.add_argument('name' ) parser.add_argument('--age' ,'-a' , nargs='?' ,const=16 ,default=18 ) args = parser.parse_args('tom -a 15' .split()) print (args) args = parser.parse_args('tom -a' .split()) print (args) args = parser.parse_args('tom' .split()) print (args)
const: 多是配合其它参数出演的配角
action参数为 ‘store_const’ 时或是 ‘append_const’ 时
nargs参数为 ‘?’ 时
default
当命令行完全没有提到某个参数时,default参数就会发挥作用,default的默认值为None
type
这个类型参数可以约束输入参数的类型 ,当类型转换合法时,会自动帮我们进行类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import argparsedef str2bool (v ): if v.lower() in ('yes' , 'true' , 't' , 'y' , '1' ): return True elif v.lower() in ('no' , 'false' , 'f' , 'n' , '0' ): return False else : raise argparse.ArgumentTypeError('Unsupported value encountered.' ) parser = argparse.ArgumentParser(description='a test' ) parser.add_argument('name' ) parser.add_argument('--age' ,'-a' ,type =int , default='17' ) args = parser.parse_args('tom' .split()) print (args) parser.add_argument('--is_del_aft' , type =str2bool, default=False )
choices
这个选项参数可以使用列表约束输入参数的取值范围。 如果输入参数不在候选参数列表中,程序会报错
1 2 3 4 5 6 7 8 9 10 11 import argparseparser = argparse.ArgumentParser(description='a test' ) parser.add_argument('name' ,choices=['tom' ,'Jim' ,'Bob' ]) parser.add_argument('--age' ,'-a' ,type =int , default='17' ) args = parser.parse_args('Jim' .split()) print (args) args = parser.parse_args('Toy' .split()) print (args)
在参数获取阶段,约束好用户输入的参数范围,可以防止意想不到的参数带来的未知后果
metavar: 这个参数的功能也是个性化显示帮助信息
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 import argparseparser = argparse.ArgumentParser(description='a test' ) parser.add_argument('name' ,metavar='haha' ) parser.add_argument('--age' ,'-a' ,type =int , default='17' ,metavar='hahahaha' ) parser.parse_args('-h' .split()) >>> usage: pydevconsole.py [-h] [--age hahahaha] hahaa test positional arguments: haha optional arguments: -h, --help show this help message and exit --age hahahaha, -a hahahaha parser.add_argument('--age' ,'-a' ,type =int , default='17' ) >>> usage: pydevconsole.py [-h] [--age AGE] hahaa test positional arguments: haha optional arguments: -h, --help show this help message and exit --age AGE, -a AGE
dest
每个参数待parser处理完毕后,都会以‘属性名-属性’ 的形式保存起来
为了使得属性名合法,parser还会将单词中间 的短横杠变为下划线
但如果,你不想用上述方法自动生成的属性名,你想自己指定属性名,就可以设定dest参数来指定。(只能指定可选参数的属性名)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import argparseparser = argparse.ArgumentParser(description='An example of using argparse' ) parser.add_argument('--input' , dest='input_file' , help ='Input file path' ) parser.add_argument('--output' , dest='output_file' , help ='Output file path' ) args = parser.parse_args('--input 输入 --output 输出' .split()) input_path = args.input_file output_path = args.output_file print (f'Input file path: {input_path} ' )print (f'Output file path: {output_path} ' )>>> Input file path: 输入 Output file path: 输出
可以看到,如果不指定dest,年龄的属性名是age。若此时指定了dest=’myage’,那么年龄的属性名就人为设定成了myage
实际例子 脚本运行命令python script.py -gpus=0,1,2 --batch-size=10
中的--batch-size
会被自动解析成batch_size
parser.add_argument
方法的type
参数理论上可以是任何合法的类型,但有些参数传入格式比较麻烦
例如list,所以一般使用bool
, int
, str
, float
这些基本类型就行了,更复杂的需求可以通过str
传入,然后手动解析
bool
类型的解析比较特殊,传入任何值都会被解析成True
,传入空值时才为`False
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import argparsedef str2bool (v ): if v.lower() in ('yes' , 'true' , 't' , 'y' , '1' ): return True elif v.lower() in ('no' , 'false' , 'f' , 'n' , '0' ): return False else : raise argparse.ArgumentTypeError('Unsupported value encountered.' ) if __name__ == '__main__' : parser = argparse.ArgumentParser(description='manual to this script' ) parser.add_argument('--zook_host' , type =str , default='127.0.0.1:2181' ) parser.add_argument('--num_of_task' , type =int , default=10 ) parser.add_argument('--is_del_aft' , type =str2bool, default=False ) args = parser.parse_args() many_tasks_schedule_performance(zook_host=args.zook_host, num_of_task=args.num_of_task, is_del_aft=args.is_del_aft)
tf.app.run
tensorflow也提供了一种方便的解析方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import tensorflow as tftf.app.flags.DEFINE_string('gpus' , None , 'gpus to use' ) tf.app.flags.DEFINE_integer('batch_size' , 5 , 'batch size' ) FLAGS = tf.app.flags.FLAGS def main (_ ): print FLAGS.gpus print FLAGS.batch_size if __name__ == "__main__" : tf.app.run() >>> python script.py --gpus=0 ,1 ,2 --batch_size=10
有几点需要注意
tensorflow
只提供以下四种方法:tf.app.flags.DEFINE_string
, tf.app.flags.DEFINE_integer
,
tf.app.flags.DEFINE_boolean
, tf.app.flags.DEFINE_float
分别对应str
, int
,bool
,float
类型的参数
这里对bool
的解析比较严格,传入1会被解析成True
,其余任何值都会被解析成False
脚本中需要定义一个接收一个参数的main
方法:def main(_):
,这个传入的参数是脚本名,一般用不到, 所以用下划线接收。
以batch_size
参数为例,传入这个参数时使用的名称为--batch_size
,也就是说,中划线不会像在argparse
中一样被解析成下划线。
tf.app.run()
会寻找并执行入口脚本的main
方法。也只有在执行了tf.app.run()
之后才能从FLAGS
中取出参数。 从它的签名来看,它也是可以自己指定需要执行的方法的,不一定非得叫main
:
1 run(main=None , argv=None )
tf.app.flags
只是对argpars
的简单封装。
代码见https://github.com/tensorflow/tensorflow/blob/r1.2/tensorflow/python/platform/flags.py
位运算
背景知识
🍅二进制
在Python中可以通过以”0b”或者”-0b”开头的字符串来表示二进制
1 2 3 print (bin (5 ))>>> 0b101
🥬原码、反码、补码
原码 : 将一个整数转换成二进制
形式,就是其原码。例如6的原码就是0110
;-18 的原码就是1000 0000 0001 0010
通俗的理解,原码就是一个整数本来的二进制形式
反码 : 对于正数,它的反码就是其原码(原码和反码相同);负数的反码是将原码中除符号位以外
的所有位(数值位)取反
补码 : 对于正数,它的补码就是其原码(原码、反码、补码都相同);负数的补码是其反码加1
位运算
应用场景
判断奇数还是偶数
使用&运算,与1进行&,如果为1,那么该数为奇数;如果为0,那么该数是偶数
交换两个数值
第一行,a = a ^ b,很容易理解
第二行, b = b ^ a = b ^ a ^ b,由于 b ^ b = 0,所以 b = a ^ 0,即 b = a
第三行, a = a ^ b ,由于a在第一步重新赋值,所以,a = a ^ b ^ a = b,完成了数值交换
寻找数据列表中的独一无二
有一个数据列表(2N+1个整数),只有一个数出现了1次,其余N个数都出现了2次。如何找到这个独一无二的数据
1 2 3 4 5 from functools import reducelst = [1 ,5 ,6 ,4 ,2 ,6 ,4 ,2 ,1 ] reduce(lambda a,b : a^b, lst) >>> 输出5
计算一个数值的二进制数中有多少个1
1 2 3 4 5 6 def count_ones (x ): count = 0 while x: count = count + 1 x = x & (x-1 ) return count
在一堆数字中找出只出现一次的两个数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def split_res (res, lst ): tmp = 1 num_0, num_1 = 0 , 0 while not tmp & res: tmp <<= 1 for i in lst: if i & tmp: num_0 ^= i else : num_1 ^= i return num_0, num_1 from functools import reducelst = [1 ,5 ,6 ,4 ,2 ,6 ,4 ,2 ,1 ,7 ] res = reduce(lambda a,b : a^b, lst) num_0, num_1 = split_res(res, lst)
路径
Python路径操作模块pathlib,看这篇就够了!
pathlib和os常用操作对比 通过常用路径操作的对比,可以更深刻理解pathlib和os的区别,便于在实际操作中做对照,也便于进行使用替代,详细对比如下:
pathlib操作
os及os.path操作
功能描述
Path.resolve()
os.path.abspath()
获得绝对路径
Path.chmod()
os.chmod()
修改文件权限和时间戳
Path.mkdir()
os.mkdir()
创建目录
Path.rename()
os.rename()
文件或文件夹重命名,如果路径不同,会移动并重新命名
Path.replace()
os.replace()
文件或文件夹重命名,如果路径不同,会移动并重新命名,如果存在,则破坏现有目标。
Path.rmdir()
os.rmdir()
删除目录
Path.unlink()
os.remove()
删除一个文件
Path.unlink()
os.unlink()
删除一个文件
Path.cwd()
os.getcwd()
获得当前工作目录
Path.exists()
os.path.exists()
判断是否存在文件或目录name
Path.home()
os.path.expanduser()
返回电脑的用户目录
Path.is_dir()
os.path.isdir()
检验给出的路径是一个文件
Path.is_file()
os.path.isfile()
检验给出的路径是一个目录
Path.is_symlink()
os.path.islink()
检验给出的路径是一个符号链接
Path.stat()
os.stat()
获得文件属性
PurePath.is_absolute()
os.path.isabs()
判断是否为绝对路径
PurePath.joinpath()
os.path.join()
连接目录与文件名或目录
PurePath.name
os.path.basename()
返回文件名
PurePath.parent
os.path.dirname()
返回文件路径
Path.samefile()
os.path.samefile()
判断两个路径是否相同
PurePath.suffix
os.path.splitext()
分离文件名和扩展名
配置文件解读
python配置文件INI/TOML/YAML/ENV的区别
ini ini 文件可能是我们可以使用的最直接的配置文件。ini 文件非常适合较小的项目,主要是因为这些文件仅支持1级深的层次结构,ini 文件本质上是平面文件,但变量可以属于组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [APP] ENVIRONMENT = developmentDEBUG = False [DATABASE] USERNAME: root PASSWORD: p@ssw0rd HOST: 127.0.0.1 PORT: 5432 DB: my_database [LOGS] ERRORS: logs/errors.log INFO: data/info.log [FILES] STATIC_FOLDER: static TEMPLATES_FOLDER: templates
python解析ini 文件代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import configparserconfig = configparser.ConfigParser() path = r'Q:\pyCharmWS\object_detection\test.ini' cfg = config.read(path) config['DATABASE' ]['HOST' ] Out[6 ]: '127.0.0.1' config.get('DATABASE' , 'HOST' ) Out[7 ]: '127.0.0.1' config.getboolean('APP' , 'DEBUG' ) Out[8 ]: False config.get('APP' , 'DEBUG' ) Out[9 ]: 'False'
configparser 还有许多其他类型检查方法,例如getint()
,getfloat()
等等
toml TOML 文件似乎与ini 文件共享某些 语法相似之处,但支持更广泛的数据类型以及值本身之间的关系
如表中所示,TOML支持嵌套表 的概念,该[environments]
表后面带有多个子表,通过使用点符号,我们能够创建表的关联,这意味着它们是同一元素的不同实例
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 32 33 34 35 36 37 38 title = "My TOML Config" [project] name = "Faceback" description = "Powerful AI which renders the back of somebody's head, based on their face." version = "1.0.0" updated = 1979 -05 -27 T07:32 :00 Z author = "Todd Birchard" [database] host = "127.0.0.1" password = "p@ssw0rd" port = 5432 name = "my_database" connection_max = 5000 enabled = true [environments] [environments.dev] ip = "10.0.0.1" dc = "eqdc10" [environments.staging] ip = "10.0.0.2" dc = "eqdc10" [environments.production] ip = "10.0.0.3" dc = "eqdc10" [[testers]] id = 1 username = "JohnCena" password = "YouCantSeeMe69" [[testers]] id = 3 username = "TheRock" password = "CantCook123"
同样有趣的是概念表列 ,如下表中的[[testers]]
,双括号中的表会自动添加到数组中,其中数组中的每个项目都是具有相同名称的表,等价于下下面JSON所表达的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 { "testers" : [ { "id" : 1 , "username" : "JohnCena" , "password" : "YouCantSeeMe69" } , { "id" : 2 , "username" : "TheRock" , "password" : "CantCook123" } ] }
python解析toml的代码如下
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import tomlpath = r'Q:\pyCharmWS\object_detection\test.toml' cfg = toml.load([path]) cfg['project' ] cfg.get('project' ) cfg['project' ]['author' ] cfg.get('project' ).get('author' ) print (cfg){ 'title' : 'My TOML Config' , 'project' : { 'name' : 'Faceback' , 'description' : "Powerful AI which renders the back of somebody's head, based on their face." , 'version' : '1.0.0' , 'updated' : datetime.datetime(1979 , 5 , 27 , 7 , 32 , tzinfo = < toml.tz.TomlTz object at 0x000001AE244933D0 > ), 'author' : 'Todd Birchard' }, 'database' : { 'host' : '127.0.0.1' , 'password' : 'p@ssw0rd' , 'port' : 5432 , 'name' : 'my_database' , 'connection_max' : 5000 , 'enabled' : True }, 'environments' : { 'dev' : { 'ip' : '10.0.0.1' , 'dc' : 'eqdc10' }, 'staging' : { 'ip' : '10.0.0.2' , 'dc' : 'eqdc10' }, 'production' : { 'ip' : '10.0.0.3' , 'dc' : 'eqdc10' } }, 'testers' : [{ 'id' : 1 , 'username' : 'JohnCena' , 'password' : 'YouCantSeeMe69' }, { 'id' : 3 , 'username' : 'TheRock' , 'password' : 'CantCook123' }] }
yaml 系统变量 1 2 3 4 from os import environenviron.get('ComSpec' ) Out[0 ]: 'C:\\WINDOWS\\system32\\cmd.exe'
流