函数就是最基本的一种代码抽象的方式。是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
内嵌函数
Python内置了很多有用的函数,我们可以直接调用,比如print,abs,int,type等,具体可查看官网文档
https://docs.python.org/3/library/functions.html
定义函数
使用def关键字,依次写出函数名、括号,括号中为参数、冒号:、在缩进块中编写函数体、返回值
def fun_name(params):
fun_body
实例,编写一个求 绝对值 的函数
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
mb_abs(1) # 1
mb_abs(-3) # 3
函数参数
位置参数
positional argument 也称必备参数
def square(a, b):
return a ** b
参数a,b就是位置参数
在调用函数时,必须按顺序传入这两个参数
>>> square(2,3) # 8
>>> square(3,2) # 9
>>> square(2) #TypeError: square() takes exactly two argument (1 given)
默认参数
default argument,特别的,默认参数要定义在位置参数之后,使用默认参数可以降低使用难度
def square(a, b=2):
return a ** b
调用函数时,如果没有传参数b,就使用默认值。
>>>square(2) # 4
>>>square(2, 3) # 8
>>>square(2, b=3) # 8
可变参数
也称不定长参数,参数的个数是可变的,定义在常规参数(regular param 位置参数和默认参数)之后。
实际例子:对一组数据进行求和,先看普通的参数定义方法。
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n
return sum
# 调用时候,需要先组装出一个tuple或者list
calc([1,2,3]) # 6
calc((1,2,3,)) # 6
如果改用可变参数,这些可变参数在函数调用时自动组装为一个tuple
def calc(*numbers):
sum = 0
for n in numbers: # 此处numbers是一个tuple
sum = sum + n
return sum
calc(1,2,3) # 6
calc() # 0
nums = [1,2,3]
calc(nums[0], nums[1], nums[2]) # 6
calc(*[1,2,3]) # 6
关键字参数
类比可变参数,可变参数是在函数调用时自动组装成一个tuple。可关键字参数,而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
定义时,关键字参数要定义在可变参数之后
def person(name, age, **kw):
if kw:
print(type(kw))
print('name:', name, 'age:', age, 'other:', kw)
person("tao", 20, work="QA") # name: tao age: 20 other: {'work': 'QA'}
命名关键字参数
关键字未限制输出的参数名,若需要对参数名做限制,需要命名关键字参数。
定义函数时,如果没有可变参数,需要使用特殊分隔符”*”
def person(name, age=3, *, city, job):
print('name:', name, 'age:', age, 'other:', city, job)
def person(name, age=3, *args, city, job):
print('name:', name, 'age:', age, "args", args, 'other:', city, job)
参数组合
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
函数返回值
变量的作用域
Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索
def foo():
b = 'hello'
# Python中可以在函数内部再定义函数
def bar():
c = True
print(a)
print(b)
print(c)
bar()
# print(c) # NameError: name 'c' is not defined
if __name__ == '__main__':
a = 100
# print(b) # NameError: name 'b' is not defined
foo()
- 局部作用域 : 在函数内部定义的变量
- 嵌套作用域 : 对于函数bar,变量b即为嵌套作用域
- 全局作用域 : 变量a
- 内置作用域 :
input
、print
、int
等
局部变量
def foo():
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 100,foo函数a是局部变量,不会继续去寻找全局变量,所以全局变量a不会被foo函数修改
全局变量
def foo():
global a
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 200
嵌套变量
def foo():
a = 200
def change_a():
nonlocal a #声明a为嵌套变量
a = 300
print(a)
change_a() #300
print(a) #300
if __name__ == '__main__':
a = 100
foo()
print(a) # 100
递归函数
如果一个函数在内部调用自身本身,这个函数就是递归函数。
实现阶乘
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
高阶函数
变量可以指向函数,函数名也是变量。
把函数作为参数传入,这样的函数称为高阶函数。
map
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
将
>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是: reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
>>> from functools import reduce
>>> def add(x, y):
... return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25
filter
和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
sorted
它还可以接收一个key函数来实现自定义的排序,,例如按绝对值大小排序(abs)
sorted([36, 5, -12, 9, -21], key=abs, reverse=True)
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
返回函数
闭包
注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。
另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。我们来看一个例子:
匿名函数
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
lambda [arg1 [,arg2,.....argn]]:expression
实现
sum = lambda x,y: x+y
配合高阶函数
sum = list