一、函数
函数是可以重复执行的语句块,可以重复调用,提高代码的利用效率。
(一)作用:
用于封装可重复执行的语句,提高语句的可重用性
定义用户级别的函数
(二)语法:
def 函数名(参数列表):
语句块(代码块)
语法说明:
1. 函数的名字就是语句块的名称
2. 函数名的命名规则与变量名命名规则相同(必须为标识符),函数名首字母不能大写
3. 函数名是一个变量(不要轻易对其赋值)
4. 函数的自己的命字空间,在函数内部可以访问外部的变量,但外部的语句不能访问函数内部的变量
5. 函数如果不需要传入参数,则参数列表可以为空
6. 语句部分不能为空,如果为空需要填充pass语句
(三)函数调用:
函数名(实际调用传递参数)
注:实际调用传递参数 简称"实参"
调用说明:
1. 函数调用是一个表达式
2. 如果函数需要返回其它的对象,需要用到return语句。return后一行及之后的语句不会被执行,return后面没东西相当于return None
3 如果没有return语句,函数执行完比后返回None对象
4.函数调用能返回一个对象的引用
5.返回多个数据可以用return (a,b,…)或return a,b,…。实际上是返回了一个元组tuple。另一方面,可以直接用多个变量一次性接收函数返回的tuple,但变量个数应该与len(tuple)一致。
(四)python函数的参数传递
(1)传递方式:
位置传参
序列传参
关键字传参
字典关键字传参
(2)位置传参:
实际调用参数(实参) 的对应关系与形式参数(形参)的对应关系是按位置来依次对应的
def fx(a, b, c):
pass
fx( 1, 2, 3)
(3)序列传参:
序列传参是在函数调用过程中,用 * 将序列拆解后按位置进行传递的传参方式
实参和形参通过序列传递和匹配
def fx(a, b, c):
pass
s1 = [11, 22, 33] # 列表
fx(*s1) # 将s1序列拆解后按位置传入fx中
(4)关键字传参
是指传参时,按着形参的名称给形参赋值
实参和形参按名称进行匹配
示例:
def fx(a, b, c):
pass
fx(b=22, c=33, a=11)
注:实参和形参按形参名进行匹配,可以不按位置进行匹配
(5)字典关键字传参:
实参为字典,用**拆解字典后再进行关键字传参
示例:
def fx(a, b, c):
pass
d = {'c': 33, 'b': 22, 'a': 11}
fx(**d) # 拆解字内再依次按关键字传参
说明:
字典的键名和形参名必须一致
字典的键名必须为字符串
字典的键名要在形参中存在
(6)综合传参:
函数的传参方式在能确定形参能唯一匹配到相应实参的情况下可以任意组合
注:通常位置传参和序列传参先传递,其次是关键字传参和字典关键字传参
示例:
def fx(a, b, c, d, e, f):
pass
fx(10, *[20, 30], e=50, **{'d':40, 'f':60})
# 以下是错误做法
fx(e=50, **{'d':40, 'f':60}, 10, *[20, 30])
(五)函数的缺省参数
语法:
def 函数名(形参名1=默认实参1, 形参名2=默认实参2, ...):
语句
示例:
def info(name, age=1, address="不详"):
print("我叫", name, '我今年:', age, '岁, 家庭住址:', address)
info("张飞", 30, "中原")
info("Tara", 10)
info("赵云")
说明:
缺省参数必须自右至左依次存在
缺省参数可以有0个,1个,多个,甚至全部都有缺省参数
缺省参数的绑定对象存在于函数内,同函数的生命周期一致
(六)函数的形参定义
(1)方式:
1. 位置形参
2. 星号元组形参
3. 命名关键字形参
4. 双星号字典形参
(2)位置形参:
def 函数名(形参名1, 形参名2, ....):
语句块
(3)星号元组形参:
语法:
def 函数名(*元组形参名):
语句块
作用:收集多余的位置传参
(4)命名关键字形参
语法:
def 函数名(*, 命名关键字形参):
语句块
或
def 函数名(*args, 命名关键字形参):
语句块
作用:
所有的命名关键字形参都强制调用者采用关键字传参或字典关键字传参的方式传递
(5)双星号字典形参:
语法:
def 函数名(**字典形参名):
语句块
作用:收集多余的关键字传参
注:字典形参名通常叫 kwargs
(6)函数参数说明:
位置形参,缺省参数,星号元组形参,命名关键字形参,双星号字典形参可以混合使用
函数参数自左至右的顺序为:
1. 位置形参
2. 星号元组形参
3. 命名关键字形参
4. 双星号字典形参
示例:
def fn(a, b, *args, c, **kwargs):
pass
fn(100, 200, 300, 400,*"AB", **{'d':"D"}, c=100)
fn(100, 200, 300, 400,*"AB", **{'d':"D", "c":"C"}, e=100)
(7)可以接收任意位置传参和关键字传参的函数:
def fn(*args, **kwargs):
psss
(七)函数变量
(1)函数名是变量,它在创建函数时绑定一个函数
def f1():
print("hello")
def f2():
print("world")
f1, f2 = f2, f1
f1()
-->world
(2)一个函数可以作为另一个函数的参数传递
def say_hello():
print("hello world")
def f2(f):
print(f)
f() # 调用f变量绑定的函数
f2(say_hello)
--><function say_hello at 0x7f959c33cf28>
-->hello world
(3)函数可以作为另一个函数的返回值:
def get_op():
s = input("请输入你的操作: ")
if s == "求最大":
return max
elif s == '求最小':
return min
L = [2, 4, 6, 8, 10]
f = get_op()
print(f(L))
(八)函数的嵌套:
函数嵌套是指一个函数里用def语句来创建其它的函数的情况
(九)全局变量和局部变量
(1)局部变量
定义在函数内部的变量称为局部变量(函数的形参也是局部变量)
局部变量只能在函数内部使用
局部变量在函数调用时被自动创建,在函数调用之后会自动销毁
(2)全局变量
定义在函数外部,模块内部的变量称为全局变量
全局变量,所有函数都可以直接访问(但函数内不能将其直接赋值)
(3)在函数中修改全局变量
1.如果是可变类型,可以执行修改变量的值
2.如果是全局变量不可变类型,在函数中修改,本质在是修改变量的引用,必须使用global语句
可变类型:值可以修改(内存地址不变但是值变化了),引用可以修改(内存地址变化了)
不可变类型:值不可以修改,可以修改变量的引用(=赋值号)
(十)python作用域
作用域也叫命名空间,是访问变量时查找变量名的范围空间
作用域
英文解释
英文简写
局部作用域(函数内)
Local Function
L
外部嵌套函数作用域
Enclosing function locals
E
函数定义所在模块的作用域
Global(module)
G
Python 内置模块的作用域
Builtin(Python)
B
变量名的查找规则:
在访问变量时,先查找本地变量,然后是包裹此函数外部函数内的变量,之后是全局变量,最后是内置变量
L -> E -> G -> B
说明:
在默认的情况下,变量赋值会创建或者修改本地作用域的变量
补充:
查看内建模块:dir(__builtin__)
查看全局变量:globals()
查看局部变量:locals()
(十一)global语句
作用:
告诉解释器,global语句声明的一个或多个变量,这些变量的作用域为模块级的作用域,也称作全局变量
全局声明(global)将赋值变量映身到模块文件内部的作用域
语法:
global 变量1, 变量2, ...
说明:
1. 全局变量如果要在函数内部被赋值,则必须经过全局声明(否则会被认为是局部变量)
2. 全局变量在函数内部不经过声明就可以直接访问(如果变量已经存在且关联一个对象)
3. 不能先声明局部变量,再用global声明为全局变量,此做法不附合规则
4. global变量列表里的变量名不能出现在此作用域的形参列表里
练习:
写一个函数hello(name),部分代码如下:
call_count = 0
def hello(name):
print("你好:", name)
global call_count
call_count += 1 #让call_count 来记录此函数调用的次数
hello("Tara")
hello("world")
print("hello函数被调用了", call_count, "次")
(十二)nonlocal 语句
作用:
告诉解释器, nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量
语法:
nonlocal 变量名1, 变量名2, ...
示例见:
nonlocal.py
说明:
1. nonlocal语句只能在被嵌套的函数内部进行使用
2. 访问nonlocal变量将对外部嵌套函数作用域内的变量进行操作
3. 当有两层或两层以上函数嵌套时,访问nonlocal变量只对最近的一层变量进行操作
4. nonlocal语句的变量列表里的变量名,不能出现在此函数的参数列表中
(十三)globals() 和 locals() 函数
globals() 返回当前全局作用域内的变量的字典
locals() 返回当前局部作用域内的变量的字典
(十四)eval函数 和 exec函数
(1)eval 函数:
作用:
把一个字符串当成一个表达式来执行,返回表达式执行后的结果
格式:
eval(source, globals=None, locals=None)
示例:
a = eval("x+y", None, {"x": 1, "y": 2})
print(a) # 3
(2)exec函数:
作用:
把一个字符串当成程序来执行
格式:
exec(source, globals=None, locals=None)
(十五)lambda 表达式 (又称匿名函数)
作用:
创建一个匿名函数对象
同 def 类似,但不提供函数名
语法:
lambda [形参名1, 形参名2, ...] : 表达式
注:[]内的内容可省略
示例:
myadd = lambda x, y: x + y
myadd(10,20)
语法说明:
1. lambda 只是一个表达式,它用来创建一个函数对象
2. 当lambda表达式执行时,返回的是冒号后(:),表达式的值
3. lambda表达式创建的函数只能包含一条语句
4. lambda 比函数简单且可以随时创建和销毁,有利于减少程序的偶合度
二、函数式编程
是指用一系列函数解决问题
(一)python语言,函数是一等公民
函数本身可以赋值给变量,赋值后变量绑定函数
允许将函数本身作为参数传入另一个函数
允许函数返回一个函数
好处:
每一个函数完成细小的功能,一系列函数的任意组合可以解决大问题
函数仅接收输入并产生输出,不包含任何可以影响输出的内部状态
(二)函数式编程的要求:
def 创建的函数最好不要访问局部作用域以外的变量,这样可以保证返回结果的唯一性(可重入性)
可重入性是指,输入一定.结果必然一定
三、高阶函数 high order function
(一)什么是高阶函数
满足下面两个条件之一的就为高阶函数:
1. 函数接受一个或多个函数作为参数传入
2. 函数返回一个函数
(二)python 内置(builtins)的高阶函数:
map, filter, sorted
(三)map函数:
map(func, *iterables) 用函数对可迭代对象中的每一个元素作为参数计算出新的可迭代对象.当最短的一个迭代器完成迭代后此迭代器生成结束
示例1:
def power2(x):
return x**2
m = map(power2, range(1, 10))
示例2:
L=[x for x in map(pow, range(1, 5),
[4,3,2,1], range(5, 10))]
解释:1**4%5==1
2**3%6==2
3**2%7==2
4**1%8==4
(四)filter 函数:
格式:
filter(function, iterable)
作用:
筛选可迭代对象iterable中的数据,返回一个可迭代对象,此可迭代对象将对iterable生成的数据进行筛选
函数function 将对iterable中的每个元素进行处理,返回False则将此数据丢弃,返回True,则保留此数据
示例:(生成奇数列表)
def isodd(x):
return x % 2 == 1
odd = [x for x in filter(isodd, range(10))]
或
odd = [x for x in filter(lambda x: x % 2 != 0, range(100))]
(五)sorted 函数
格式:
sorted(iterable, key=None, reverse=False)
作用:
将原可迭代对象的数据进行排序,生成排序后的列表
说明:
iterable 可迭代对象
key 函数是用来提供一个值,这个值将作为排序的依据
reverse 标志用来设置是否降序排序
示例:
L = sorted(L, key=abs) # [0, 1, -2, 3, -4, 5]
L = sorted(names, key=len) ['Tom', 'Tyke', 'Jerry', 'Spike']
(六)递归函数 recursion
函数直接或间接的调用自身
递归说明:
递归一定要控制递归的层数,当符合某一条件时要终止递归调用
几乎所有的递归都能用while循环来代替
示例1:
def fn(n):
print(n)
if n == 5: #终值
return
fn(n + 1) #递推关系
fn(1) #实现打印1,2,3,4,5
示例2:
def factorial(n):
if n == 1: # 初值(1的阶乘是1)
return 1
return n * factorial(n-1) # 递推关系
print(factorial(5)) # 实现了用递归求5!
递归的优点:递归可以把问题简单化,让思路更为清晰,代码更简洁
递归的缺点:递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果