1. 函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段,简单来讲,函数就是一段可重复执行的代码逻辑。
1.1 函数示例
def test_func():
'''
这是一个测试函数
:return:
'''
print('这是一个测试函数')
return
解释 :
def 函数定义的关键词,函数必须以为def开头来定义。
test_func 函数名,可自行定义,一般约定为(简短、见名知意)
() 括号中用于定义参数,没有参数的时候,则为空
‘’’ ‘’’ 函数的描述(好的函数先描述函数的功能,然后每个参数的格式和代表的意义和返回值)
接下来就是函数功能逻辑,自行编写对应的代码实现
return用户返回函数执行后返回的参数,没有返回值可以不带参数。
1.2 函数调用
函数调用处处见,低头不见抬头见。例如我们在之前基础篇中使用的系统库函数,print、os.system等函数,都是函数的调用,现在的区别只在于我们调用的是我们自己实现的函数,调用方法还是一样的。
下面,我们自定义一个函数和调用这个函数:
def save_cur_time():
'''
保存当前时间
:return:
'''
localtime = time.localtime()
str_time = time.strftime("%Y-%m-%d %H:%M:%S", localtime)
fp = open('cur_time.txt', 'a+')
fp.write(str_time)
fp.write('\r\n')
fp.close()
def main():
'''
主函数
:return:
'''
save_cur_time()
if __name__ == '__main__':
main()
解释:
main() 这里是第一个函数调用,跳转到main函数中执行代码
save_cur_time() 是第二个函数调用,跳转到save_cur_time函数中执行代码逻辑,保存当前的时间到文本中。
执行结果:
1.3 函数参数
- 不可变类型参数
在 python 中,strings, tuples, 和 numbers 是不可更改的对象。
即使在函数中临时改变了参数的值,在函数执行结束后,参数的值还是原来的值。
例如:
def immutable_param(param):
'''
不可变类型参数函数
:param param: 参数值 (int)
:return:
'''
print('immutable_param param传入值为 : {}'.format(param))
param = 10
print('immutable_param param修改后的值为 : {}'.format(param))
param = 1
immutable_param(param)
print('函数结束后,param的值为: {}'.format(param))
结果:
immutable_param param传入值为 : 1
immutable_param param修改后的值为 : 10
函数结束后,param的值为: 1
- 可变类型参数
在 python 中,list,dict 等则是可以修改的对象,如果在函数中临时改变了参数的值,在函数执行结束后,参数的值就被永久的改变了。
例如:
def mutable_param(param):
'''
可变类型参数函数
:param param: 参数值 (dict)
:return:
'''
print('mutable_param param传入值为 : {}'.format(param))
del param['1key']
param['10key'] = '10value'
print('mutable_param param修改后的值为 : {}'.format(param))
param = {'1key': '1value', '2key': '2value'}
mutable_param(param)
print('函数结束后,param的值为: {}'.format(param))
结果:
mutable_param param传入值为 : {'1key': '1value', '2key': '2value'}
mutable_param param修改后的值为 : {'2key': '2value', '10key': '10value'}
函数结束后,param的值为: {'2key': '2value', '10key': '10value'}
- 默认参数
默认参数将会在函数的参数中设置一个默认值,当调用函数并且没有传递该参数的时候,则会默认给该参数设置默认值,并在函数的范围内生效。
例如:
def default_param(param1, param2 = 10):
'''
默认参数函数
:param param1: 参数1
:param param2: 默认参数,默认值为10
:return:
'''
print('default_param param1:{} param2:{}'.format(param1, param2))
default_param(1, 2)
default_param(1)
结果:
default_param param1:1 param2:2
default_param param1:1 param2:10
- 不定长参数
不定长参数函数,在我们一开始的时候就遇到了,例如神奇的main,再例如,神奇的print函数,例如print后面可以有一个参数,两个参数.....N个参数,这里我们就类似实现一个看一下,就容易理解了。
例如:
def variable_param(param1, *kwarg):
'''
可变参数函数
:param param1: 参数1
:param kwarg: 可变参数
:return:
'''
print('variable_param param1:{}'.format(param1))
for var in kwarg:
print('variable_param kwarg:{}'.format(var))
variable_param(10, 20, 30)
variable_param(10, 20, 30, 40, 50)
结果:
variable_param param1:10
variable_param kwarg:20
variable_param kwarg:30
variable_param param1:10
variable_param kwarg:20
variable_param kwarg:30
variable_param kwarg:40
variable_param kwarg:50
- 参数题外话 : (一般项目团队都会做的一些约束)
- 参数默认不超过5个(超过5个会进行压栈)
- 所有外部输入参数,都需要做参数类型、有效值校验
2. 装饰器
装饰器,理解起来,有点费力, 需要层层深入,如果看完之后没看懂,那就,在看一遍,还是不懂,多动手练习几次,其义自见。
2.1 万物皆对象
对象这个概念,是变相对象编程语言中的概念,如果对这个概念不太熟悉,可以先看下一章”类”这一块。
在编程语言中,除了int、string、dict等这项变量申明出来的是对象外,函数也是一个对象,函数名对应的就是一个函数地址。
例如:
def func_obj():
'''
函数对象测试函数
:return:
'''
print('这是一个函数')
print('func_obj函数对象: {}'.format(func_obj))
结果:
func_obj函数对象: <function func_obj at 0x7f9b6143f578>
解释:
func_obj函数本身也是一个对象,存储在内存中的地址为0x7f9b6143f578。
接上面示例:
func_obj()
func_test = func_obj
func_test()
结果:
这是一个函数
这是一个函数
解释:
func_obj() :正常的函数调用
func_test = func_obj : 将函数地址复制给func_test,这个和C里面的函数指针是一样的
func_test() : 执行函数func_obj
参考代码 :
https://github.com/minlixia/python (advanced/01_func.py)
2. 装饰器
装饰器,理解起来,有点费力, 需要层层深入,如果看完之后没看懂,那就,在看一遍,还是不懂,多动手练习几次,其义自见。
可能下面前几个章节关联性并不是那么强,可以单独来理解,但是每个小章节优势必须要了解的,因为最后完整的理解装饰器的时候,需要这些小章节知识的结合汇总理解。
2.1 万物皆对象
对象这个概念,是变相对象编程语言中的概念,如果对这个概念不太熟悉,可以先看下一章”类”这一块。
在编程语言中,除了int、string、dict等这项变量申明出来的是对象外,函数也是一个对象,函数名对应的就是一个函数地址。
例如:
def func_obj():
'''
函数对象测试函数
:return:
'''
print('这是一个函数')
print('func_obj函数对象: {}'.format(func_obj))
结果:
func_obj函数对象: <function func_obj at 0x7f9b6143f578>
解释:
func_obj函数本身也是一个对象,存储在内存中的地址为0x7f9b6143f578。
接上面示例:
func_obj()
func_test = func_obj
func_test()
结果:
这是一个函数
这是一个函数
解释:
func_obj() :正常的函数调用
func_test = func_obj : 将函数地址复制给func_test,这个和C里面的函数指针是一样的
func_test() : 执行函数func_obj
2.2 函数中的函数(子函数)
顾名思义,函数的中的函数,即使在函数中再定义一个子函数,子函数的有效范围只在当前函数内。
例如:
def internal_func():
'''
子函数示例函数
:return:
'''
print('子函数示例')
def hello():
print('this is hello function')
def test():
print('this is test funcion')
hello()
internal_func()
结果:
子函数示例
this is hello function
解释:
def hello(): 在函数internal_func中定义一个子函数, 只能在internal_func 函数内部中被调用。
虽然还定义了test函数,但是没有调用,就不会执行test函数中的代码。
2.3 将函数作为参数传递给另外一个函数
既然万物接对象,那函数对象也可以作为参数传递给另外一个函数。
例如:
def func_param_func(func_param):
'''
执行func_param对应的参数
:param func_param: 函数对象
:return:
'''
print('执行{}函数'.format(func_param))
func_param()
func_param_func(func_obj)
结果:
执行<function func_obj at 0x7f9d1c527578>函数
这是一个函数
解释:
func_param() : 其实这行代码和上面”万物皆对象”里面的示例代码一样
func_obj()
func_test = func_obj
func_test()
2.4 装饰器函数
有了上面的知识储备后,我们可以开始写一个装饰器了,装饰器其实和”将函数作为参数传递给另外一个函数”原理是一样的。
示例:
def func_trace(func):
'''
装饰器函数,用于func函数名
:param func: 函数对象
:return:
'''
def wrapper(*args, **kwargs):
print('[func_trace]: enter {}()'.format(func.__name__))
return func(*args, **kwargs)
return wrapper
@func_trace
def add_func(a, b):
'''
整数相加
:param a:
:param b:
:return:
'''
sum = a + b
return sum
sum = add_func(1, 2)
print('add_func(1, 2) = {}'.format(sum))
结果:
[func_trace]: enter add_func()
add_func(1, 2) = 3
解释:
def func_trace(func) : 定义一个装饰器函数, func为函数对象
def wrapper(*args, **kwargs): 包装器,args、kwargs是func函数的参数。
接下来时装饰器函数自己的逻辑代码
return func(*args, **kwargs) : 执行func函数。
@func_trace
def add_func(a, b):
定义了一个add_func函数,@func_trace为装饰器,@func_trace相当于:
func_trace(add_func)
wrapper中的args = (1,2)
所以,return func(*args, **kwargs)就变成了:
return add(1,2)
2.5 装饰器类
装饰器类和装饰器函数实现的效果差不多是一样的,但是类相对于函数来说能够更加内聚,在类的内部能够实现对应的成员函数和成员变量。
为了将装饰器定义成一个实例,你需要确保它实现了 __call__() 和 __get__() 方法。 例如,下面的代码定义了一个类,它在其他函数上放置一个简单的记录层。
例如:
class Decorate(object):
'''
'''
def __init__(self):
'''
初始化
'''
print('Decorate init')
def __call__(self, func):
'''
:param func:
:return:
'''
def wrapper(*args, **kwargs):
print('[Decorate]: enter {}()'.format(func.__name__))
return func(*args, **kwargs)
return wrapper
@Decorate()
def sub_func(a, b):
'''
a - b
:param a:
:param b:
:return:
'''
return a - b
sum = sub_func(10, 2)
print('sub_func(10, 2) = {}'.format(sum))
结果:
[Decorate]: enter sub_func()
sub_func(10, 2) = 8
参考代码 :
https://github.com/minlixia/python (advanced/02_decorator.py)