函数
定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
def 是固定的,不能变
函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能
括号:是必须加的
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
调用:就是 函数名() 要记得加上括号
#func --> 函数的内存地址 #函数名() 函数的调用 #函数的内存地址() 函数的调用
函数的返回值
#返回值的3种情况
# 没有返回值 —— 返回None # 不写return ----> 会默认返回一个None # 只写return:结束一个函数的继续 ------>会返回None # return None —— 不常用 # 返回1个值 # 可以返回任何数据类型 # 只要返回就可以接收到 # 如果在一个程序中有多个return,那么只执行第一个 # 返回多个值 # 用多个变量接收:有多少返回值就用多少变量接收 # 用一个变量接收: 得到的是一个元组(#python中把用逗号分割的多个值就认为是一个元组。)
函数的参数
参数可以传递多个,多个参数之间用逗号分割。
#参数
#没有参数
#定义函数和调用函数时括号里都不写内容
#有一个参数
#传什么就是什么
#有多个参数
#位置参数
#站在实参的角度上:
def classmate(name,sex):
print('%s : %s'%(name,sex))
#按照位置传参
classmate('二哥','男')
#按照关键字传参
classmate(sex='男',name = '二哥')
#混着用可以:但是 必须先按照位置传参,再按照关键字传参数
#不能给同一个变量传多个值
classmate('二哥',sex = '男')
#站在形参的角度上
def classmate(name,sex='男'):
print('%s : %s'%(name,sex))
#位置参数:必须传,且有几个参数就传几个值
#默认参数: 可以不传,如果不传就是用默认的参数,如果传了就用传的
classmate('二哥')
classmate('朗哥',sex= '女')
#只有调用函数的时候 #按照位置传 : 直接写参数的值 #按照关键字 : 关键字 = 值 #定义函数的时候: #位置参数 : 直接定义参数 #默认参数,关键字参数 :参数名 = '默认的值' #动态参数 : 可以接受任意多个参数 #参数名之前加*,习惯参数名args,接收的是按照位置传参的值,组织成一个元组 #参数名之前加**,习惯参数名kwargs(参数名 = '默认的值')接受的是按照关键字传参的值,组织成一个字典

def sum(*args): n = 0 for i in args: n+=i return n print(sum(1,2)) print(sum(1,2,3)) print(sum(1,2,3,4)) def func(**kwargs): print(kwargs) func(a = 1,b = 2,c =3) func(a = 1,b = 2) func(a = 1)
#顺序:位置参数,*args,默认参数,**kwargs

def func(*args,default = 1,**kwargs): print(args,defaut,kwargs) func(1,2,3,4,5,default =2,a = 'aaaa',b = 'bbbb',) #(1, 2, 3, 4, 5) 2 {'b': 'bbbb', 'a': 'aaaa'}

函数的注释 def func(): ''' 这个函数实现了什么功能 参数1: 参数2: :return: 是字符串或者列表的长度 ''' pass
动态参数的另一种传参方式
def func(*args): #站在形参的角度上,给变量加上*,就是组合所有传来的值。 print(args) func(1,2,3,4,5) #(1, 2, 3, 4, 5) l = [1,2,3,4,5] func(*l) #站在实参的角度上,给一个序列加上*,就是将这个序列按照顺序打散 # (1, 2, 3, 4, 5) def func(**kwargs): print(kwargs) func(a=1,b=2) #{'b': 2, 'a': 1} d = {'a':1,'b':2} #定义一个字典d func(**d) # {'b': 2, 'a': 1}
默认参数的陷阱
# 如果默认参数的值是一个可变数据类型, # 那么每一次调用函数的时候, # 如果不传值就公用这个数据类型的资源 def qqxing(k,l = {}): l.append(1) l[k] = 'v' print(l) qqxing(1) #[1] qqxing(2) #[1,1] qqxing(3) #[1,1,1]
函数的命名空间(三种)
#内置命名空间 —— python解释器
# 就是python解释器一启动就可以使用的名字存储在内置命名空间中
# 内置的名字在启动解释器的时候被加载进内存里
#全局命名空间 —— 我们写的代码但不是函数中的代码
# 是在程序从上到下被执行的过程中依次加载进内存的
# 放置了我们设置的所有变量名和函数名
#局部命名空间 —— 函数
# 就是函数内部定义的名字
# 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就又消失了
#在局部:可以使用全局、内置命名空间中的名字 #在全局:可以使用内置命名空间中的名字,但是不能用局部中名字 #在内置:不能使用局部和全局的名字的
#在正常情况下,直接使用内置的名字 #当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字 #当我自己有的时候 我就不找我的上级要了 #如果自己没有 就找上一级要 上一级没有再找上一级 如果内置的名字空间都没有 就报错 # 多个函数应该拥有多个独立的局部名字空间,不互相共享
倒置依赖性原则
globals() locals()
# 作用域两种 # 全局作用域 —— 作用在全局 —— 内置和全局名字空间中的名字都属于全局作用域 ——globals() # 局部作用域 —— 作用在局部 —— 函数(局部名字空间中的名字属于局部作用域) ——locals()
#globals 永远打印全局的名字
#locals 输出什么 根据locals所在的位置
global a
# 对于不可变数据类型 在局部可查看全局作用域中的变量 # 但是不能直接修改 # 如果想要修改,需要在程序的一开始添加global声明 # 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
函数的嵌套
#函数的嵌套定义
#内部函数可以使用外部函数的变量
nonlocal
#nonlocal 只能用于局部变量 找上层中离当前函数最近一层的局部变量
#声明了nonlocal的内部函数的变量修改会影响到 离当前函数最近一层的局部变量
# 对全局无效
# 对局部 也只是对 最近的 一层 有影响
a = 1 def outer(): a = 1 def inner(): a = 2 def inner2(): nonlocal a #声明了一个上面第一层局部变量 a += 1 #不可变数据类型的修改 inner2() print('##a## : ', a) inner() print('**a** : ',a) outer() print('全局 :',a) ##a## : 3 **a** : 1 全局 : 1
函数名的本质
def func(): print(123) func() #函数名就是内存地址 func2 = func #函数名可以赋值 func2() l = [func,func2] #函数名可以作为容器类型的元素 print(l) #[<function func at 0x004656A8>, <function func at 0x004656A8>] for i in l: i() #123 123 def func(): print(123) def wahaha(f): f() return f #函数名可以作为函数的返回值 qqxing = wahaha(func) # 函数名可以作为函数的参数 qqxing() # 123 123
sdggsf