最近在搞pyExcelerator这个库,希望能对其进行更新,并且适配到Python3上来,其实这个库开发了很久了,也挺好用的,所以fork下来学习一下。

项目地址:https://github.com/Microndgt/py3Excelerator

然后看到一段代码是这样的:

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
# 多个位置参数
def accepts(*types):
def check_accepts(f):
truetruetruetrue# 检测被装饰函数的函数参数个数是否与装饰器传递参数个数相同
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
truetruetruetruetruetrue # 检测被装饰的函数的位置参数类型是不是accepts指定的类型
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
truetruetruetrue# 这里将名字改过来主要原因是以后还有可能需要调用被装饰的函数
truetruetruetrue# 但是装饰器装饰后相当于返回变成了new_f这个函数
truetruetruetrue# 带参数的装饰器,第一层函数先将参数传递进去然后返回一个函数
truetruetruetrue# 返回的这个函数才真正装饰 定义的函数
new_f.func_name = f.func_name
return new_f
return check_accepts
def returns(rtype):
def check_returns(f):
def new_f(*args, **kwds):
result = f(*args, **kwds)
truetruetruetruetruetrue# 如果为假,则会raise AssertError并且包含错误信息
assert isinstance(result, rtype), \
"return value %r does not match %s" % (result,rtype)
return result
new_f.func_name = f.func_name
truetruetruetrue# 返回之后相当于new_f代替了func,所以也就相当于new_f(*args, **kwargs)了
return new_f
return check_returns
# returns装饰的其实是accepts装饰后的new_f函数
@returns(int)
@accepts(int, (int, float))
def func(arg1, arg2):
return arg1 * arg2

其中f.func_code.co_argcount这里是Python2中函数众多属性的一个,这里值的意义是函数位置参数的个数,在Python3中是这样的f.__code__.argcount,借此下面就深入探索一下Python函数信息,当然都是基于Python3。

查看函数属性

1
2
3
4
def yes(): pass # 统一定义这个函数
yes.__dir__()
dir(yes)
yes.__name__ # 函数名称

函数编码信息__code__(属性)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 位置参数个数
yes.__code__.co_argcount
# 被其他嵌套函数引用了的yes的函数的局部变量
yes.__code__.co_cellvars
# 编译后的字节码
yes.__code__.co_code
# 函数中所有常量
yes.__code__.co_consts
# 函数定义所在的源文件路径
yes.__code__.co_filename
# 函数定义在其源文件的第一行的行号
yes.__code__.co_firstlineno
# 函数参数传递方式的编码
yes.__code__.co_flags
# 函数中所有自由变量的名称
yes.__code__.co_freevars
# 函数的名称
yes.__code__.co_name
# 函数中所有的被字节码使用到的名称,比如模块名,方法名
yes.__code__.co_names
# 函数用到的局部变量的数目
yes.__code__.co_nlocals
# 函数中所有使用的局部变量的名称,参数按顺序在最前面
yes.__code__.co_varnames

默认信息__defaults__(属性)

yes.__defaults__表示函数的参数中所有默认值

文档字符串__doc__(属性)

yes.__doc__表示函数的文档字符串

全局环境__globals__(属性)

yes.__globals__函数的全局环境

基本就这些,详细的可以查看Python文档

Python3的代码

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
from functools import wraps
def accepts(*types):
def check_accepts(f):
assert len(types) == f.__code__.co_argcount
@wraps(f)
def new_f(*args, **kwargs):
for a, t in zip(args, types):
assert isinstance(a, t), "arg %r does not match %s" %(a, t)
return f(*args, **kwargs)
return new_f
return check_accepts
def returns(rtype):
def check_returns(f):
@wraps(f)
def new_f(*args, **kwargs):
result = f(*args, **kwargs)
assert isinstance(result, rtype), 'return value %r does not match %s' % (result, rtype)
return result
return new_f
return check_returns
if __name__ == "__main__":
@returns(int)
@accepts(int, (int, float))
def func(arg1, arg2):
return arg1 * arg2
print(func(1, 1.1))