tqdm
""" #【tqdm】 显示循环的进度条,再也不用担心程序跑到哪里还要跑多久了 #tqdm 可以直接包裹iterable对象 from tqdm import tqdm,trange from time import sleep
text = "" for char in tqdm(['a','b','c','d']): text += char sleep(1)
#trange(i)相当于tqdm(range(i)) from tqdm import tqdm,trange from time import sleep for i in trange(100): sleep(0.01)
#可以在循环外预先定义tqdm对象 pbar = tqdm(['a','b','c','d','e','f','g','aaa']) for char in pbar: pbar.set_description("Processing %s" % char) #Processing aaa: 100%|██████████| 8/8 [00:00<00:00, 14260.28it/s]
''' 有两个参数比较有用,desc(str)和leave(bool) desc可以指定这个循环的的信息,以便区分。上面的set_description(str)和这个应该是一样的。 leave则表示进度条跑完了之后是否继续保留 '''
from tqdm import tqdm,trange from time import sleep
for i in tqdm(range(3),desc='1st loop'): for j in trange(5,desc='2nd loop',leave=False): sleep(0.1) ''' leave == True 1st loop: 0%| | 0/3 [00:00<?, ?it/s] 2nd loop: 0%| | 0/5 [00:00<?, ?it/s] 2nd loop: 20%|██ | 1/5 [00:00<00:00, 9.96it/s] 2nd loop: 40%|████ | 2/5 [00:00<00:00, 9.82it/s] 2nd loop: 60%|██████ | 3/5 [00:00<00:00, 9.78it/s] 2nd loop: 80%|████████ | 4/5 [00:00<00:00, 9.76it/s] 2nd loop: 100%|██████████| 5/5 [00:00<00:00, 9.73it/s] 1st loop: 33%|███▎ | 1/3 [00:00<00:01, 1.94it/s] 2nd loop: 0%| | 0/5 [00:00<?, ?it/s] 2nd loop: 20%|██ | 1/5 [00:00<00:00, 9.94it/s] 2nd loop: 40%|████ | 2/5 [00:00<00:00, 9.81it/s] 2nd loop: 60%|██████ | 3/5 [00:00<00:00, 9.78it/s] 2nd loop: 80%|████████ | 4/5 [00:00<00:00, 9.76it/s] 2nd loop: 100%|██████████| 5/5 [00:00<00:00, 9.74it/s] 1st loop: 67%|██████▋ | 2/3 [00:01<00:00, 1.95it/s] 2nd loop: 0%| | 0/5 [00:00<?, ?it/s] 2nd loop: 20%|██ | 1/5 [00:00<00:00, 9.86it/s] 2nd loop: 40%|████ | 2/5 [00:00<00:00, 9.75it/s] 2nd loop: 60%|██████ | 3/5 [00:00<00:00, 9.69it/s] 2nd loop: 80%|████████ | 4/5 [00:00<00:00, 9.67it/s] 2nd loop: 100%|██████████| 5/5 [00:00<00:00, 9.67it/s] 1st loop: 100%|██████████| 3/3 [00:01<00:00, 1.94it/s] leave == False 1st loop: 0%| | 0/3 [00:00<?, ?it/s] 2nd loop: 0%| | 0/5 [00:00<?, ?it/s] 2nd loop: 20%|██ | 1/5 [00:00<00:00, 9.85it/s] 2nd loop: 40%|████ | 2/5 [00:00<00:00, 9.69it/s] 2nd loop: 60%|██████ | 3/5 [00:00<00:00, 9.63it/s] 2nd loop: 80%|████████ | 4/5 [00:00<00:00, 9.68it/s] 2nd loop: 100%|██████████| 5/5 [00:00<00:00, 9.67it/s] 1st loop: 33%|███▎ | 1/3 [00:00<00:01, 1.93it/s] 2nd loop: 0%| | 0/5 [00:00<?, ?it/s] 2nd loop: 20%|██ | 1/5 [00:00<00:00, 9.55it/s] 2nd loop: 40%|████ | 2/5 [00:00<00:00, 9.69it/s] 2nd loop: 60%|██████ | 3/5 [00:00<00:00, 9.68it/s] 2nd loop: 80%|████████ | 4/5 [00:00<00:00, 9.64it/s] 2nd loop: 100%|██████████| 5/5 [00:00<00:00, 9.68it/s] 1st loop: 67%|██████▋ | 2/3 [00:01<00:00, 1.93it/s] 2nd loop: 0%| | 0/5 [00:00<?, ?it/s] 2nd loop: 20%|██ | 1/5 [00:00<00:00, 9.60it/s] 2nd loop: 40%|████ | 2/5 [00:00<00:00, 9.70it/s] 2nd loop: 60%|██████ | 3/5 [00:00<00:00, 9.68it/s] 2nd loop: 80%|████████ | 4/5 [00:00<00:00, 9.65it/s] 2nd loop: 100%|██████████| 5/5 [00:00<00:00, 9.66it/s] 1st loop: 100%|██████████| 3/3 [00:01<00:00, 1.93it/s] '''
''' 如果要在Jupyter Notebook上面使用,那么要把tqdm换成tqdm_notebook,trange换成tnrange 在Jupyter Notebook里面没有这个问题,还能用print()。
from tqdm import tnrange, tqdm_notebook from time import sleep
for i in tqdm_notebook(range(10), desc='1st loop'): for j in tnrange(100, desc='2nd loop', leave=False): sleep(0.01) '''
如果要在终端运行期间打印什么,用tqdm.write(str)
from tqdm import tqdm,trange from time import sleep
for i in trange(10): tqdm.write(str(i)) sleep(0.1) ''' 千奇百怪的结果 1⃣️ 0 1 2 3 4 5 6 7 8 80%|████████ | 8/10 [00:00<00:00, 9.65it/s]9 90%|█████████ | 9/10 [00:00<00:00, 9.67it/s]100%|██████████| 10/10 [00:01<00:00, 9.66it/s] 2⃣️ 0 0%| | 0/10 [00:00<?, ?it/s]1 10%|█ | 1/10 [00:00<00:00, 9.70it/s]2 20%|██ | 2/10 [00:00<00:00, 9.70it/s]3 40%|████ | 4/10 [00:00<00:00, 9.65it/s]4 5 50%|█████ | 5/10 [00:00<00:00, 9.60it/s]6 60%|██████ | 6/10 [00:00<00:00, 9.61it/s]7 70%|███████ | 7/10 [00:00<00:00, 9.60it/s]8 80%|████████ | 8/10 [00:00<00:00, 9.60it/s]9 90%|█████████ | 9/10 [00:00<00:00, 9.62it/s]100%|██████████| 10/10 [00:01<00:00, 9.63it/s] 3⃣️ 0 1 10%|█ | 1/10 [00:00<00:00, 9.48it/s]2 30%|███ | 3/10 [00:00<00:00, 9.54it/s]3 4 40%|████ | 4/10 [00:00<00:00, 9.61it/s]5 60%|██████ | 6/10 [00:00<00:00, 9.61it/s]6 7 70%|███████ | 7/10 [00:00<00:00, 9.61it/s]8 80%|████████ | 8/10 [00:00<00:00, 9.60it/s]9 100%|██████████| 10/10 [00:01<00:00, 9.66it/s] 4⃣️ 0 10%|█ | 1/10 [00:00<00:00, 9.71it/s]1 2 20%|██ | 2/10 [00:00<00:00, 9.73it/s]3 40%|████ | 4/10 [00:00<00:00, 9.72it/s]4 5 50%|█████ | 5/10 [00:00<00:00, 9.69it/s]6 60%|██████ | 6/10 [00:00<00:00, 9.67it/s]7 80%|████████ | 8/10 [00:00<00:00, 9.67it/s]8 90%|█████████ | 9/10 [00:00<00:00, 9.65it/s]9 100%|██████████| 10/10 [00:01<00:00, 9.64it/s] 5⃣️ 0 0%| | 0/10 [00:00<?, ?it/s]1 10%|█ | 1/10 [00:00<00:00, 9.49it/s]2 40%|████ | 4/10 [00:00<00:00, 9.56it/s]3 4 50%|█████ | 5/10 [00:00<00:00, 9.59it/s]5 6 70%|███████ | 7/10 [00:00<00:00, 9.59it/s]7 8 90%|█████████ | 9/10 [00:00<00:00, 9.58it/s]9 100%|██████████| 10/10 [00:01<00:00, 9.59it/s] 等等。。。。 '''
"""
【inspect】 关于python中inspect模块的一些探究
标签: Python
前言
我在学习到实战Day5 - python教程 - 廖雪峰的官方网站时,遇到了inspect模块,之前对这个inspect模块一无所知啊,所以本着打破砂锅问到底的精神,决定对inspect模块做一些探究。
根据度娘搜到的,inspect模块主要提供了四种用处:
(1). 对是否是模块,框架,函数等进行类型检查。
(2). 获取源码
(3). 获取类或函数的参数的信息
(4). 解析堆栈
我在这次课程中,只用到了第三种用处,即获取类或函数的参数的信息,下面我来探究一下。
探究
结合我正在学习的课程,我自己也对inspect做了一些探究。根据在课程中用到的一些函数及方法,我做了一个python脚本。
test
import inspect def a(a, b=0, *c, d, e=1, **f): pass aa = inspect.signature(a) print("inspect.signature(fn)是:%s" % aa) print("inspect.signature(fn)的类型:%s" % (type(aa))) print("\n")
bb = aa.parameters print("signature.paramerters属性是:%s" % bb) print("ignature.paramerters属性的类型是%s" % type(bb)) print("\n")
for cc, dd in bb.items(): print("mappingproxy.items()返回的两个值分别是:%s和%s" % (cc, dd)) print("mappingproxy.items()返回的两个值的类型分别是:%s和%s" % (type(cc), type(dd))) print("\n") ee = dd.kind print("Parameter.kind属性是:%s" % ee) print("Parameter.kind属性的类型是:%s" % type(ee)) print("\n") gg = dd.default print("Parameter.default的值是: %s" % gg) print("Parameter.default的属性是: %s" % type(gg)) print("\n")
ff = inspect.Parameter.KEYWORD_ONLY print("inspect.Parameter.KEYWORD_ONLY的值是:%s" % ff) print("inspect.Parameter.KEYWORD_ONLY的类型是:%s" % type(ff)) 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 执行以上脚本,将得到如下输出:
inspect.signature(fn)是:(a, b=0, *c, d, e=1, **f) inspect.signature(fn)的类型:<class 'inspect.Signature'>
signature.paramerters属性是:OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b=0">), ('c', <Parameter "*c">), ('d', <Parameter "d">), ('e', <Parameter "e=1">), ('f', <Parameter "**f">)]) ignature.paramerters属性的类型是<class 'mappingproxy'>
mappingproxy.items()返回的两个值分别是:a和a mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:POSITIONAL_OR_KEYWORD Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
mappingproxy.items()返回的两个值分别是:b和b=0 mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:POSITIONAL_OR_KEYWORD Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: 0 Parameter.default的属性是: <class 'int'>
mappingproxy.items()返回的两个值分别是:c和*c mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:VAR_POSITIONAL Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
mappingproxy.items()返回的两个值分别是:d和d mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:KEYWORD_ONLY Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
mappingproxy.items()返回的两个值分别是:e和e=1 mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:KEYWORD_ONLY Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: 1 Parameter.default的属性是: <class 'int'>
mappingproxy.items()返回的两个值分别是:f和**f mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:VAR_KEYWORD Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
inspect.Parameter.KEYWORD_ONLY的值是:KEYWORD_ONLY inspect.Parameter.KEYWORD_ONLY的类型是:<enum '_ParameterKind'> 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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 总结
inspect.signature(fn)将返回一个inspect.Signature类型的对象,值为fn这个函数的所有参数
inspect.Signature对象的paramerters属性是一个mappingproxy(映射)类型的对象,值为一个有序字典(Orderdict)。
这个字典里的key是即为参数名,str类型
这个字典里的value是一个inspect.Parameter类型的对象,根据我的理解,这个对象里包含的一个参数的各种信息
inspect.Parameter对象的kind属性是一个_ParameterKind枚举类型的对象,值为这个参数的类型(可变参数,关键词参数,etc)
inspect.Parameter对象的default属性:如果这个参数有默认值,即返回这个默认值,如果没有,返回一个inspect._empty类。
【from inspect import Signature】【获取参数信息】
""" #练习1 #rfind 返回最后次出现的位置,参数一是开始查找位置,参数二是结束查找位置 str1 = 'admin minad entend' print(str1.rfind(' ',0,6)) #5 print(str1.rfind(' ',0,2)) #-1 print(str1.rfind(' ',2)) #11 print(str1.find(' ',2)) #5
print(str1[:5].rstrip()) #admin """ #练习2 def clip(text,max_len=80): '''在max_len前面或后面的第一个空格处截断文本,前面有则从前面的空格处截断,前面没有则从后面的空格处截断''' end = None if len(text) > max_len: space_before = text.rfind(' ',0,max_len) if space_before > 0: end = space_before else: space_after = text.find(' ',max_len) if space_after > 0: end = space_after if end is None: end = len(text) return text[:end].rstrip() #提取关于函数参数的信息 print(clip.defaults) #(80,) print(clip.code) #<code object clip at 0x0000000001DA5930, file "C:/Users/wangxue1/PycharmProjects/python2/methodIsObj/init.py", line 13> print(clip.code.co_varnames) #('text', 'max_len', 'end', 'space_before', 'space_after') print(clip.code.co_argcount) #2 #提取函数的签名 from inspect import signature sig = signature(clip) print(sig) #(text, max_len=80) print(str(sig)) #(text, max_len=80) for name,param in sig.parameters.items(): print(param.kind,':',name,'=',param.default) ''' POSITIONAL_OR_KEYWORD : text = <class 'inspect._empty'> POSITIONAL_OR_KEYWORD : max_len = 80 ''' #【备注】 ''' kind 属性的值是 _ParameterKind 类中的 5 个值之一,列举如下。 POSITIONAL_OR_KEYWORD 可以通过定位参数和关键字参数传入的形参(多数 Python 函数的参数属于此类)。 VAR_POSITIONAL 定位参数元组。 VAR_KEYWORD 关键字参数字典。 KEYWORD_ONLY 仅限关键字参数(Python 3 新增)。 POSITIONAL_ONLY 仅限定位参数;目前, Python 声明函数的句法不支持,但是有些使用 C 语言实现且 不接受关键字参数的函数(如 divmod)支持 ''' #吧tag函数的签名绑定到一个参数字典上 #...准备工作 def tag(name,*content,cls=None,**attrs): if cls is not None: attrs['class'] = cls if attrs: attr_str = ''.join() attrs = {'class':'sidebar'} print('%s="%s' % (attr,value) for attr,value in sorted(attrs.items())) #<generator object <genexpr> at 0x000000000220A830> print(''.join('%s="%s' % (attr,value) for attr,value in sorted(attrs.items()))) #class="sidebar print(''.join('%s="%s' % (attr,value) for attr,value in (attrs.items()))) #class="sidebar print(attrs.items()) #dict_items([('class', 'sidebar')]) print(sorted(attrs.items())) #[('class', 'sidebar')] #...tag函数 def tag(name,*content,cls=None,**attrs): '''生成一个或多个HTML标签''' if cls is not None: attrs['class'] = cls if attrs: attr_str = ''.join(' %s="%s' % (attr,value) for attr,value in sorted(attrs.items())) else: attr_str = '' if content: return '\n'.join('<%s%s>%s</%s>' % (name,attr_str,c,name) for c in content) else: return '<%s%s />' % (name,attr_str)
sig = signature(tag) my_tag = {'name':'img','title':'Sunset Boulevard','src':'sunset.jpg','cls':'framed'} bound_args = sig.bind(**my_tag) print(bound_args) #<BoundArguments (name='img', cls='framed', attrs={'title': 'Sunset Boulevard', 'src': 'sunset.jpg'})> for name,value in bound_args.arguments.items(): print(name,'=',value) ''' name = img cls = framed attrs = {'title': 'Sunset Boulevard', 'src': 'sunset.jpg'} ''' #del my_tag['name'] #bound_args = sig.bind(**my_tag) #TypeError: missing a required argument: 'name'
【inspect】 名称 含义 POSITIONAL_ONLY 必须为位置参数,python没有明确定义位置参数的语法 POSITIONAL_OR_KEYWORD 可以为位置参数或者关键字参数 VAR_POSITIONAL 位置参数的元素没有绑定到任何其他参数,对应python函数定义中的args(可变参数) KEYWORD_ONLY 值必须作为关键字参数提供,只有关键字参数是指出现在或者*args之后的参数(命名关键字参数) VAR_KEYWORD 没有绑定到任何其他参数的关键字参数的字典,对应参数定义的**kwargs(关键字参数) 上面就是各参数类型的含义,下面来个例子:
import inspect
def foo(a, b, *args,c, **kwargs): pass
sig = inspect.signature(foo) for name, param in sig.parameters.items(): print('参数:%s的类型为:%s' % (name, param.kind))
输出结果如下:
参数:a的类型为:POSITIONAL_OR_KEYWORD 参数:b的类型为:POSITIONAL_OR_KEYWORD 参数:args的类型为:VAR_POSITIONAL 参数:c的类型为:KEYWORD_ONLY 参数:kwargs的类型为:VAR_KEYWORD
前言
我在学习到实战Day5 - python教程 - 廖雪峰的官方网站时,遇到了inspect模块,之前对这个inspect模块一无所知啊,所以本着打破砂锅问到底的精神,决定对inspect模块做一些探究。
根据度娘搜到的,inspect模块主要提供了四种用处:
(1). 对是否是模块,框架,函数等进行类型检查。
(2). 获取源码
(3). 获取类或函数的参数的信息
(4). 解析堆栈
我在这次课程中,只用到了第三种用处,即获取类或函数的参数的信息,下面我来探究一下。
探究
结合我正在学习的课程,我自己也对inspect做了一些探究。根据在课程中用到的一些函数及方法,我做了一个python脚本。 test
import inspect def a(a, b=0, *c, d, e=1, **f): pass aa = inspect.signature(a) print("inspect.signature(fn)是:%s" % aa) print("inspect.signature(fn)的类型:%s" % (type(aa))) print("\n")
bb = aa.parameters print("signature.paramerters属性是:%s" % bb) print("ignature.paramerters属性的类型是%s" % type(bb)) print("\n")
for cc, dd in bb.items(): print("mappingproxy.items()返回的两个值分别是:%s和%s" % (cc, dd)) print("mappingproxy.items()返回的两个值的类型分别是:%s和%s" % (type(cc), type(dd))) print("\n") ee = dd.kind print("Parameter.kind属性是:%s" % ee) print("Parameter.kind属性的类型是:%s" % type(ee)) print("\n") gg = dd.default print("Parameter.default的值是: %s" % gg) print("Parameter.default的属性是: %s" % type(gg)) print("\n")
ff = inspect.Parameter.KEYWORD_ONLY print("inspect.Parameter.KEYWORD_ONLY的值是:%s" % ff) print("inspect.Parameter.KEYWORD_ONLY的类型是:%s" % type(ff)) 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 执行以上脚本,将得到如下输出:
inspect.signature(fn)是:(a, b=0, *c, d, e=1, **f) inspect.signature(fn)的类型:<class 'inspect.Signature'>
signature.paramerters属性是:OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b=0">), ('c', <Parameter "*c">), ('d', <Parameter "d">), ('e', <Parameter "e=1">), ('f', <Parameter "**f">)]) ignature.paramerters属性的类型是<class 'mappingproxy'>
mappingproxy.items()返回的两个值分别是:a和a mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:POSITIONAL_OR_KEYWORD Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
mappingproxy.items()返回的两个值分别是:b和b=0 mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:POSITIONAL_OR_KEYWORD Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: 0 Parameter.default的属性是: <class 'int'>
mappingproxy.items()返回的两个值分别是:c和*c mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:VAR_POSITIONAL Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
mappingproxy.items()返回的两个值分别是:d和d mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:KEYWORD_ONLY Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
mappingproxy.items()返回的两个值分别是:e和e=1 mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:KEYWORD_ONLY Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: 1 Parameter.default的属性是: <class 'int'>
mappingproxy.items()返回的两个值分别是:f和**f mappingproxy.items()返回的两个值的类型分别是:<class 'str'>和<class 'inspect.Parameter'>
Parameter.kind属性是:VAR_KEYWORD Parameter.kind属性的类型是:<enum '_ParameterKind'>
Parameter.default的值是: <class 'inspect._empty'> Parameter.default的属性是: <class 'type'>
inspect.Parameter.KEYWORD_ONLY的值是:KEYWORD_ONLY inspect.Parameter.KEYWORD_ONLY的类型是:<enum '_ParameterKind'>
总结
inspect.signature(fn)将返回一个inspect.Signature类型的对象,值为fn这个函数的所有参数
inspect.Signature对象的paramerters属性是一个mappingproxy(映射)类型的对象,值为一个有序字典(Orderdict)。
这个字典里的key是即为参数名,str类型
这个字典里的value是一个inspect.Parameter类型的对象,根据我的理解,这个对象里包含的一个参数的各种信息
inspect.Parameter对象的kind属性是一个_ParameterKind枚举类型的对象,值为这个参数的类型(可变参数,关键词参数,etc)
inspect.Parameter对象的default属性:如果这个参数有默认值,即返回这个默认值,如果没有,返回一个inspect._empty类。
来源:oschina
链接:https://my.oschina.net/u/4306387/blog/3876274