函数续集
参数
函数的参数除了上次的位置参数,关键字参数,默认参数外,还有可变长参数和混合参数。
-
可变长参数
将形参变量前用一个 * 修饰(如 * param),则会将传入的任意数量参数作为一个元组param传入;若用两个 ** 修饰(如**kwargs),则会将显式传入的参数作为一组键值对放入字典kwargs内传入
# 变长参数 将元素放入一个元组内 要放在最后
def self_print(name,*a):
print('name是:',name)
print('a是:',a)
print(type('a的类型是',type(a)))
self_print(1,2,3,4)
# 变长参数 将元素放入一个字典内
def d_self_print(**kwargs):
print(kwargs)
print(type(kwargs))
d_self_print(last_name = 'zhang',first_name = 'san')
# 运行结果
name是: 1
a是: (2, 3, 4)
a的类型是 <class 'tuple'>
{'last_name': 'zhang', 'first_name': 'san'}
kwargs的类型是: <class 'dict'>
-
混合参数
当位置参数和可变长参数混合使用时,要严格注意放置顺序。参数顺序:位置参数->元组->字典
def mix(name,*t,**kw):
print('name是:', name,'类型是:',type(name))
print('t是:', t,'类型是:',type(t))
print('kw是:', kw,'类型是:',type(kw))
mix('zhangsan',1,2,3,gender = 'female',weight = 600)
# 运行结果
name是: zhangsan 类型是: <class 'str'>
t是: (1, 2, 3) 类型是: <class 'tuple'>
kw是: {'gender': 'female', 'weight': 600} 类型是: <class 'dict'>
参数传递方式
- 值传递(两个人是双胞胎)
参数传递的本质就是赋值操作,其中值传递就是赋值时传的是数值,python中的基本数据类型都是值传递 int,bool,string,none。
a = 5
b = a
b = 10
print(a)
# 运行结果
5
通过这个例子我们可以看到,值传递只是把自己的值复制了一份,并赋给另一个变量,而自身并没有改变。故a仍然是5。
- 引用传递(可以看作起别名)
而引用传递在赋值时,则是把自己的内存地址直接交给另一个变量,一荣俱荣,一损俱损。经过这种方式赋值的,表面是两个变量,实际上是同一个东西。
l1 = [1,2,3,4,
l2 = l1
l2[0] = 0
print(l1)
[1, 2, 3, 4, 5]
[0, 2, 3, 4, 5]
我们可以看到,把l1赋给l2,然后改变l2的值,l1也随之改变。
- 注意
若是引用类型,则需要注意,是否传入的参数在函数体执行过程中对其本体做出了修改。
关于符号 *
-
融合(在形参位置时)
这个作用我们刚刚已经看到了,一个 * 会将诸多变量融合为元组,而 ** 则会将其转化为字典。 -
拆解(其他)
与上面对应,一个 * 可以拆解元组/列表 ,而 ** 可以拆解字典 。
# * 示例
t = (1,2,3,
print(*t)
def f(*tt):
print(tt)
f(*[1,2,3,4,5])
# ** 示例
def ff(**kwargs):
print(kwargs)
ff(**{'a':'name','b':2})
# 运行结果
1 2 3 4 5
(1, 2, 3, 4, 5)
{'b': 2, 'a': 'name'}
return 返回值
在定义函数时,使用关键字return指明返回值。当有多个返回值时,则需要相应个数的变量依次来获取这些返回值。
def sum_and_avg(*numbers):
total = sum(numbers)
avg_number = total / len(numbers)
return total,avg_number
sum,avg = sum_and_avg(1,2,3,4,5,6,7,8,9,10)
print('sum是:%f'% sum)
print('avg是:%f'% avg)
# 运行结果
sum是:55.000000
avg是:5.500000
函数闭包
闭包的本质是函数嵌套函数,外层函数返回内层函数的地址(把内层函数打包)
-
函数名的本质
函数名的本质是一个地址,因此可以赋值给另一个变量(函数名)
def fun():
print("hello world!")
# 函数名的本质是函数的地址
fun_1= fun
fun_1()
# 运行结果
hello world!
-
函数嵌套
函数嵌套就是在一个函数声明体中,有另一个函数的声明。
- 内层函数可以访问外层函数的变量,但不能修改。
- 内层函数访问变量时,先从自己内部查找,如果找不到,则会层层向上。
- python中变量的作用域是以函数为单位的。
- global修饰时,说明用的是最外层的全局变量。
- nonlocal修饰时,说明使用的的是嵌套层的变量。
def outter():
a = 10
def inner():
print("---------")
a = 20
print(a)
print("hello inner!")
print(a)
return inner
outter_1 = outter()
outter_1()
# 运行结果
10
---------
20
hello inner!
递归函数
递归函数就是在自己的声明内调用自己。
- 在递归实现时,只需考虑两点:第一明确出口控制(即什么时候递归结束),第二明确递归关系。
- 递归的优点是简化思考,缺点是消耗高。
- 附例: 使用递归实现阶乘
def factorial1(n):
if n == 1: # 出口
return 1
return n * factorial1(n - 1) # 递归关系
print(factorial(5))
# 运行结果
120
高阶函数
高阶函数是这么一种函数,就是这个函数的参数或返回值仍然是一个函数的函数。
def handle(func,*param): # 第一个参数和返回值是函数func
return func(*param)
def my_sum(*prama):
sum = 0
for v in prama:
sum += v
return sum
def my_multiply(*prama):
mul = 1
for v in prama:
mul *= v
return mul
# 函数的参数是函数
print(handle(my_sum,1,2,3,4,5,6))
print(handle(my_multiply,1,2,3,4,5,6))
# 运行结果
21
720
-
函数 map(func,iterable)
该函数会把iterable中的数据一次传递给func函数处理,最后把处理的结果返回。
def power(x):
return x*x
result = map(power,[1,2,3,4,5]) #结果是一个生成器
print(list(result))
# 运行结果
[1, 4, 9, 16, 25]
试着用lambda表达式实现。
-
函数 reduce(func,iterable)
该函数为累计操作,其中func函数必须接纳两个参数,reduce把func的运行结果作为一个参数,然后从iterable中再去一个数据当做另一个参数。
from functools import reduce
li =[1,2,3,4,5]
result = reduce(lambda x,y:x*y,li)
print(result)
# 运行结果
120
-
函数 fliter(func,iterable)
该函数的作用是 过滤,根据函数func过滤iterable,True保留,否则删除。
li = [1,2,4,5,6,9,10,15]
result = list(filter(lambda x:x %2 == 1,li))
print(result)
# 运行结果
[1, 5, 9, 15]
-
函数 sort(iterable,key = None,reverse =Fales)
对数据进行排序,key用来指定排序规则,值是一个函数,reverse用来指定排序的顺序: 升序或者降序。
li = [1,-10,2,-4,12]
# rs = li.sort()#就地排序
rs = sorted(li,key= abs)
print(rs)
print(li)
# 运行结果
[1, 2, -4, -10, 12]
[1, -10, 2, -4, 12]