note
函数的定义和意义
(1)函数是一种封装
(2)函数是输入经过一些变换后到输出的一种映射
(3)过程化 VS 结构化
(4)函数是一个对象
返回 return, yield
def foo(num):
for i in range(num):
yield i
g1 = foo(9) #返回一个generator对象
type(g1)
next(g1)
函数的参数
语法: func(positional_args, keyword_args, *tuple_nonkw_args, **dict_kw_args)
(1)位置参数(定位参数, 非关键字参数):位置非常重要不能缺省
#位置参数,对位置敏感,传递时不用指定参数名
def func1(name, age):
print(name, age)
func1('zxl', 23)
'''output
zxl 23
'''
(2)关键字参数
def func2(name, age, sex='male'):
print(name, age, sex)
func2('zxl', 23)#不传关键字参数,函数依旧可以被调用,采用默认值
func2('zxl', 23, sex='secret')#传关键字参数,覆盖默认值
'''output
zxl 23 male
zxl 23 secret
'''
(3)位置参数包裹及使用*号(*tuple_nonkw_args),一次传入不定长个位置参数
def func3(*args):
print(type(args)) #tuple
return sum(args)
func3(1,2,3,4)
'''output
<class 'tuple'>
10
'''
l1 = [1,2,3,4,5]
func3(*l1)# 将l1打散成一个包裹,而不是一个参数
'''output
<class 'tuple'>
15
'''
(4)关键字参数包裹及使用**号(**dict_kw_args),一次性传入不定长关键字参数
def func4(**args):
print(type(args)) #dict
print(args)
for key, value in args.items():
print(key,':',value)
func4(name='zxl', age=23)
'''output
<class 'dict'>
{'name': 'zxl', 'age': 23}
name : zxl
age : 23
'''
d1 = {'name': 'zyq', 'age':1}
func4(**d1)#将d1打散成一个包裹
'''output
<class 'dict'>
{'name': 'zyq', 'age': 1}
name : zyq
age : 1
'''
(5)接受的参数包裹解包的顺序
首先拆位置参数包裹,按顺序给必选,默认,可变,再拆关键字参数包裹
(6)传递参数是使用包裹,加*号或者**号
def func5(name, age, sex='male', *args, **kwargs):
print('basic information:', name, age, sex)
print('other information:', args)
print('other information:', kwargs)
func5('zxl', 23, 'secret', 'His favorite NBA star is Andre Iguodala.', 'zyq is his son.', lucky_num = 9, address='xt')
'''output
basic information: zxl 23 male100%
other information: ('His favorite NBA star is Andre Iguodala.', 'zyq is his son.')
other information: {'lucky_num': 9, 'address': 'xt'}
'''
#传递参数时使用包裹-位置参数
l1=[1,5,6,7,2,5,3.5,9,6,3,4]
(7)值传递参数和指针传递参数(可变与不可变对象)
值传递,参数本身不会被修改,值传递时,变量传递给函数后,函数复制一份,不会影响原有变量。
指针传递参数,会修改参数本身,指针(或引用)传递时,变量传递给函数的是其引用,该引用可以改变原变量
def func7a(name, age):
name += '001'
age -= 1
print(name, age)
name = 'zxl'
age = 23
func7a(name, age)
print(name, age)
'''output:
zxl001 22
zxl 23
'''
def func7b(name, age):
name[0] = 'zxl001'
age[0] -= 1
#age -= 1 #报错,python的list不支持整体算数运算,numpy的array可以
print(dict(zip(name,age)))
names = ['zxl', 'zyq']
ages = [23,1]
func7b(names, ages)
print(dict(zip(names, ages)))
'''output:
{'zxl001': 22, 'zyq': 1}
{'zxl001': 22, 'zyq': 1}
'''
变量的作用域
偏函数 Partial function application
(1)使用场景: 如果一个函数的参数很多, 而在每次调用的时候有一些又经常不需要被指定时, 就可以使用偏函数(近似理解为默认值)
(2)语法: partial(func, *args, **kwargs)
(3)使用:from functools import partial
(4)原理:创建一个新函数, 固定住原函数的部分参数(可以为位置参数,也可以是关键字参数)
a = int('1000', base=10)
b = int('1000', base=16)
c = int('1000', base=2)
print(a,b,c)
'''output:十进制的数:
1000 4096 8
'''
#例如我们要定义一个函数将传进来的16进制的字符串,转换为10进制的
def hex2int(num):
return int(str(num),base=16)#base为关键字参数,这个在调用int这个函数时,固定给16。因为这个函数就是用来转换16进制到10进制
hex2int('F')#这时调用,相当于实际上会把16作为*args的一部分自动加到左边,也就是:int('F',base=16),这样就少写了一个参数
'''output:
15
'''
#这时也可以使用偏函数,固定int函数的关键字参数base,可以这样定义:
import functools
hex2int2=functools.partial(int,base=16)
hex2int2('A')
'''output:
10
'''
#偏函数用来固定位置参数
max100=functools.partial(max,100)#定义一个叫max100的偏函数,将这个偏函数的第一个值固定为100
max100(101)#这时调用它,传入的值,都会与100进行比较反并返回。结果是101
type(max100)#偏函数的类型与普通函数不一样.结果是:functools.partial
递归
在函数内部调用自身
#阶乘
def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
factorial (5)
'''output:
120
'''
匿名函数
#匿名函数
print(type(lambda a,b:a**b )) #结果为<class 'function'>
#定义 llambda 参数列表 : 函数体
#不用写return
#使用1:作为正常函数使用,不推荐
foo=lambda x,y:x+y #不用写return
#lambda
print(foo(5,6)) #结果为11
#使用2:lambda关键字定义在高阶函数的参数位上
d1={'china':15,'India':9,'USA':2,'Japan':1.5}
print(sorted(d1.items(),key=lambda x:(x[0],x[1])))#按d1.items()第0个元素升序,国家名
print(sorted(d1.items(),key=lambda x:(x[1])))#按d1.items()第1个元素升序,人口数
'''output:
[('India', 9), ('Japan', 1.5), ('USA', 2), ('china', 15)]
[('Japan', 1.5), ('USA', 2), ('India', 9), ('china', 15)]
'''
高阶函数
python函数也是对象,函数名只是指向这个对象的一个变量
函数可以接受一个函数对象的变量名
def func8(nums, func): #新建一个函数对象,并用func8这个变量名对其进行引用
return func(nums)
func8([1,2,3,4], max) #输出: 4
func8([1,2,3,4], sum) #输出: 10
#函数名本质即变量,同一个函数对象可以被多个变量引用
a = b = func8
a([1,2,3,4], min) #输出: 1
del func8 #对函数对象的引用可以删除
b([1,2,4,3], sorted) #输出: [1, 2, 3, 4]
BIFs中的高阶函数filter,map,reduce
filter语法:filter(function,list)
函数 function 的作用是对每个元素进行判断,返回 True或 False,
filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
def myfilter(x):
if x>60:
return True
else:
return False
l1=[1,-12, 61, 100]
list(filter(myfilter,l1)) #输出: [61, 100]
l2=[1,-12, 61, 100, [1,2,3], 'aa', 'b']
list(filter(lambda x:True if type(x)==str else False,l2)) #输出: ['aa', 'b']
map语法:map(function, list)
让list的每一个元素依次调用function函数,并获取返回值存入一个新的list中。
l3 = [['aa', 'bb', 'cc'], ['a', 'b', 'c'], ['aa', 'b', 'c']]
list(map(lambda x:(x,x.count('aa')),l3))
'''output
[(['aa', 'bb', 'cc'], 1), (['a', 'b', 'c'], 0), (['aa', 'b', 'c'], 1)]
'''
reduce语法:reduce(function, list)
函数function必须包含两个参数,optional可选,如果存在则表示初值为optional
reduce()对list的每个元素反复调用函数f,并返回最终结果值。
from functools import reduce
reduce(lambda a,b:a+b,[1,2,3,4,5,6,7,8]) # 输出; 36
闭包,函数的嵌套
def foo1(nums_in_function):
print('nums_in_function此时在foo1中,可以被 访问:',nums_in_function)
def foo2():
return max(nums_in_function)#虽然没有给foo2传入任何参数,但foo2却能访问到foo1中的变量nums_in_function
return foo2
#调用
foo1([5,3,8])()
'''output
nums_in_function此时在是foo1中,可以被 访问: [5, 3, 8]
8
'''
装饰器
定义:以函数作参数并返回一个替换函数的可执行函数
简单理解: 装饰器的作用就是为已存在的对象添加额外功能,为一个函数增加一个装饰(用另一个函数装饰),本质上就一个返回函数的高阶函数
应用:给函数动态增加功能(函数)
#现有如下 三个函数
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
#现在想为每一个函数都添加一个打印当前时间的功能
#一种解决办法是一个一个修改,在底部添加代码,但问题是,太麻烦了~
import datetime
def foo1():
print ('this is foo1 function')
print(datetime.datetime.now())
def foo2():
print ('this is foo2 function')
print(datetime.datetime.now())
def foo3():
print ('this is foo3 function')
print(datetime.datetime.now())
#另一种办法是,写一个函数,负责打印时间,然后修改那三个函数
import datetime
def printtime():
print(datetime.datetime.now())
def foo1():
print ('this is foo1 function')
printtime()
def foo2():
print ('this is foo2 function')
printtime()
def foo3():
print ('this is foo3 function')
printtime()
#虽然不那么麻烦了,但还是每个函数都要修改,依旧很麻烦。
#我们可以这样解决
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
def extrafoo(func):
print(datetime.datetime.now())
return func
decorated=extrafoo(foo2)
decorated()
'''output:
2017-12-02 16:35:43.417014
this is foo2 function
'''
#这样每次调用还是有点麻烦,要先写一个函数接收,再调用。OK,再弄简单一些
#我们可以这样解决
import datetime
def extrafoo(func):
def inner():
print('from inner to execute:',func.__name__)
print('the',func.__name__,'result:',func())
print('extra:',datetime.datetime.now())
return inner
@extrafoo#装饰器特性,被装饰的函数定义之后立即运行。
def foo1():
return 'this is foo1 function--'
#@是python装饰器的简便写法,也叫语法糖
#装饰器语法糖在要被包裹的函数前声明。@后面的函数名,是包裹下边函数的函数名extrafoo
#该语法糖省略了
#decorated=foo(test)
#decorated()
# 装饰器在Python使用如此方便都要归因于
# Python的函数能像普通的对象一样能作为参数传递给其他函数
# 可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
foo1()
'''output:
extra: 2017-12-03 20:44:15.281196
from inner to execute: foo1
the foo1 result: this is foo1 function--
'''