python之路14--函数、命名空间、作用域和三元运算
函数说明:
通过使用函数,可以对程序进行更加好的组织。将一些相对独立的代码变成函数,可以提高程序的可读性和重用性。避免重复编写大量相同的代码。
在python中函数的定义
f = "www.71box.net" def my_len(): #定义函数名,函数名和变量名一样的规则,def为关键字 i = 0 for k in f: i +=1 print(i) return i #设置函数返回值 my_len() #执行函数
说明:函数定义后可以在任何需要它的地方调用,不能变,只能执行函数里面的代码;
当前函数的缺点:当前函数只可以计算变量f的长度;
函数的返回值说明
函数的返回值分为三种:
1、没有返回值 -->返回None
1、不写return默认返回None
2、只写return,不写返回什么(一个函数遇到ruturn后,return后面的代码将不在执行,结束该函数)
2、返回一个值
1、可以返回任何数据类型,只要返回就可以在函数外面用变量接收到;
2、如果在一个函数中有多个return,那么只执行第一个;
3、返回多个值
1、用多个变量接收,有多少返回值就用多少变量接收
2、如果用一个变量接收,得到的是一个元组
定义可以传参的函数
def my_len(s): #自定义函数只需要0个参数,接收参数,形式参数,简称形参 i = 0 for k in s: i += 1 return i #返回值 ret = my_len('www.71box.net') #传递参数:传参,实际参数,简称实参 ret = my_len([1,2,3,4,5]) #传递参数:传参 print(ret)
参数说明
参数:
1、没有参数
定义函数和调用函数时括号里都不写内容
2、有一个参数
传的是什么就是什么
3、有多个参数
也叫位置参数
定义一个带有位置参数的函数
def my_sum(a,b,c): print(a,b,c) res = a+b+c #result return res ret = my_sum(1,2,3) print(ret) #结果为:6
说明:按照顺序,1传给了a,2传给了b,3传给了c,所以也叫位置参数
定义一个带有默认参数的函数
def classmate(name,sex='男'): #默认参数为sex='男',如果传实参是不定义sex=,则默认为男 print('%s : %s'%(name,sex)) classmate('欧阳') #结果为欧阳:男 classmate('李四') #结果为李四:男 classmate('小七','女') #结果为小七:女
classmate(sex='女',name='小妞') #结果为小妞:女 #此为关键字传参
说明:
站在实参的角度上:
可以按照位置传参
可以按照关键字传参
混着用也可以:但是 必须先按照位置传参,再按照关键字传参数
不能给同一个变量传多个值
站在形参的角度上
位置参数:必须传,且有几个参数就传几个值
默认参数: 可以不传,如果不传就是用默认的参数,如果传了就用传的
调用函数的时候
按照位置传 : 直接写参数的值
按照关键字: 关键字 = 值
定义函数的时候:
位置参数 : 直接定义参数
默认参数,关键字参数 :参数名 = '默认的值'
定义一个带有动态参数的函数
说明:
动态参数有两种:可以接收N个参数
1、*args : 接收的是按照位置传参的值,组织成一个元组
2、**kwargs: 接受的是按照关键字传参的值,组织成一个字典
1、*args
说明:
动态参数 : 可以接受任意多个参数
参数名之前加*,习惯参数名args,
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))
2、**kwargs
说明:
动态参数,可以接收任意个关键字参数
参数名之前加**,习惯参数名kwargs
def func(**kwargs): print(kwargs) func(a = 1,b = 2,c =3) func(a = 1,b = 2) func(a = 1)
创建一个含有多种参数的函数
定义函数时形参的位置说明: 1、位置参数,2、*args,3、默认参数,4、**kwargs
def func(*args,default = 1,**kwargs): print(args,kwargs) func(1,2,3,4,5,default=2,a = 'aaaa',b = 'bbbb',)
动态参数的另一种传参形式
def func(*args): #站在形参的角度上,给变量加上*,就是组合所有传来的值。 print(args) func(1,2,3,4,5) l = [1,2,3,4,5] func(*l) #站在实参的角度上,给一个序列加上*,就是将这个序列按照顺序打散 def func(**kwargs): print(kwargs) func(a=1,b=2) d = {'a':1,'b':2} #定义一个字典d func(**d)
函数的注释
def func(): ''' 这个函数实现了什么功能 参数1: 参数2: :return: 是字符串或者列表的长度 ''' pass #函数里的代码 func() #调用函数
默认参数为可变类型的问题描述
如果默认参数的值是一个可变数据类型,那么每次调用函数的时候,如果不传值就共用这个数据类型的资源
def yisou(l = []): #定义yisou函数,形参为可变的列表 l.append(1) #往列表里追加内容(每次调用就追加一次) print(l) #打印列表内容 yisou() #调用一次,结果为:[1] yisou([]) #此次调用时传了一个空列表(即默认参数没有生效,当前的实参生效),然后追加1,结果还是:[1] yisou() #此次调用没传参数,结果为:[1, 1] yisou() #结果为:[1, 1, 1] def vip(k,l = {}): #定义函数vip(位置参数,默认参数 = {}),默认参数为一个空字典(可变类型) l[k] = 'v' #默认参数[位置参数] = 'v',即往字典里添加内容 print(l) #打印默认参数 #显示结果 vip(1) #第一次调用vip函数(1),传参为1,结果为:{1: 'v'} vip(2) #第二次调用vip函数(2),传参为2,结果为:{1: 'v', '2':'v'} vip(3) #第三次调用vip函数(3),传参为3,结果为:{1: 'v', 2: 'v', 3: 'v'}
函数的总结:
函数说明:可读性强,复用性强
定义函数:
所有的函数,只定义不调用就一定不执行(先定义后调用)
def 函数名(): 函数体 return 返回值 函数名() #调用函数、不接收返回值 返回值 = 函数名() #接收返回值
返回值:
没有返回值
不写return:默认返回None(函数内的代码执行结束,自动结束)、
只写return不写返回值:(可以结束函数)、
return None:返回结果即为None
返回一个值
结束了函数并且返回一个值(返回的这个值可以是任意值)
返回多个值
多个值之间用逗号隔开,接收的时候可以用一个变量接收(接收到的是一个元组),也可以用等量的多个变量接收(返回的是啥,接收到的就是啥),
参数:
形参
定义的函数的时候(def 函数名(形参))
形参的位置顺序:
1、位置参数(必须传),
2、*args(动态参数,可以接收任意多个按位置传入的参数),
3、默认参数(可以不传),
4、**kwargs(动态参数,可以接收任意多个按关键字传入的参数)
实参
调用函数的时候(函数名(实参))
1、按照位置传参
2、按照关键字传参(可以混用,位置参数必须在关键字传参之前、不能对一个参数重复赋值)
动态参数的名一种传参方法:
def wa(*args): print(args) l = [1,2,3,4] wa(*l) #另一种*args的调用方法
命名空间
命名空间说明:
1、内置命名空间(和python解释器有关):
就是python解释器一启动就可以使用的名字存储在内置命名空间中,内存的名字在启动解释器的时候被加载进内存里,如(print\input\len等)
在内置命名空间中:不能使用局部命名空间的名字和全局命名空间的名字
2、全局命名空间(和写的函数外的代码有关):
在程序从上到下被执行的过程中依次被加载进内存的,放置了我们设置的所有变量名和函数名
在全局命名空间:可以使用内置命名空间中的名字,但是不能用局部命名空间的名字
3、局部命名空间(和函数内的代码有关):
就是函数内部定义的名字,当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间就又消失了
在局部命名空间:可以使用全局,内置命名空间的名字
画图说明:

实操演示命名空间下变量之间的调用
1、函数调用全局命名空间的变量
1、从局部命名空间调用全局命名空间的变量 a = 1 #在全局命名空间定义变量 def budao(): #定义函数 print(a) #再函数里调用全局命名空间的变量 budao() #结果为1 2、从全局命名空间调用局部命名空间的变量会报错 def budao(): #定义函数 a = 1 #函数内容为a = 1,再局部命名空间 print(a) #再全局命名空间调用局部命名空间的变量,此时会报错
2、命名空间的调用优先级说明
说明:
在正常情况下,直接使用内置的名字,
当我们在全局定义了和内置命名空间中同样的名字时,会使用全局的名字,
当我自己有的时候,我就不找上级要了,如果我自己没有就找上级要,如果最上级也没有就再找上级,如果内置的命名空间都没有就会报错
画图说明:

实操说明:
def input(): #在全局命名空间定义一个input函数,和内置函数一样的名字 print('in input now') #函数体为这个 def func(): #在全局命名空间定义另一个函数 input() #函数体为input,此时input为全局命名空间的input,也就是上面定义的input函数 func() #此时我执行func函数,调用的是全局命名空间的函数,并不是内置命名空间的input def fun(): #在全局命名空间里定义了另一个函数 input = 1 #函数体为input = 1 print(input) #打印input的结果为1,因为我局部命名空间有input这个变量,就不去全局命名空间去找了 fun() #执行函数 func1 vip1(): #在全局命名空间定义vip1函数, a = 1 #函数主体为a = 1 func2 vip2(): #在全局命名空间定义函数vip2 print(a) #函数主体是调用vip1函数局部空间的a, vip2() #执行vip2,会报错, 说明:多个函数,每个函数拥有单独的局部命名空间,不互相共享。
作用域
作用域的种类及说明:
全局作用域:
作用在全局:内置和全局命名空间中的名字都属于全局作用域,可以用globals查看全局命名空间的变量及内置变量
局部作用域:
作用在局部:函数(局部名字空间中的名字属于局部作用域),可以用locals查看局部的命名空间的变量(locals:查看当前命名空间的变量)
a = 1 #明空间里定义变量a = 1 def func(): #定义函数func global a #global a声明a(表示当前局部命名空间的a可以作用于全局) a += 1 #修改变量a func() #执行函数 print(a) #结果为2, 说明: 对于不可变的数据类型,在局部可是查看全局作用域中变量,但是不能直接修改。 如果想要修改,需要在程序的一开始添加global生明 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效,(写代码时尽量少用global,如果想在外面调用局部变量可以用return返回) a = 1 b = 2 def func(): x = 'aaa' y = 'bbb' print(locals()) #locals:查看局部命名空间的变量 func() print(globals()) #可以查看全局命名空间的变量,和内置的变量 说明: globals:永远打印全局的名字 locals:输出什么,根据locals所在的位置,在全局就打印全局的名字,在局部就打印局部的名字
函数的嵌套
a = 1 #全局命名空间定义了变量a = 1 def outer(): #定义函数outer a = 1 #局部命名空间里定义a = 1 def inner(): #在outer函数里定义了另一个函数 b =2 #定义了变量b = 2 print(a) #此时打印变量a -->打印的时outer函数里的变量a print('inner') #打印字符串inner def inner2(): #在函数inner里定义另一个函数innner2 nonlocal a #nonlocal:声明了上层的第一个的局部变量, a += 1 #不可变的数据类型修改,需要要声明,(局部变量声明用nonlocal、全局变量声明用global) print('innner2') inner2() #结果为inner2,因为并没有输入a +=1的结果,只是做了计算 inner() #这里打印的是outer里的a,没有做修改的,结果为1 print('****',a) #这里打印的是inner2里已经做过a += 1之后的a了,a += 1时用在outer函数下的a上的,结果为2outer()#nonlocal:只能用于局部变量,找出上层中离当前函数最近的一层的局部变量、声明了nonlocal的内部函数的变量修改会影响到里当前函数最近一层的局部变量
函数名的本质
说明:
可以被引用,可以被当作容器类型的元素,,可以当作函数的参数和返回值(即可以当作普通变量使用),
第一类对象:可以在运行期创建,可以做函数参数或返回值,可存入变量实体
操作:
1、
def func(): #函数名就是内存地址, print(123) func2 = func #函数名可以赋值 func2() #执行结果为:123 rint(func,func2) #结果为:<function func at 0x0000020BF6A45AE8> <function func at 0x0000020BF6A45AE8> 两块内存地址 l = [func,func2] #函数名可以作为容器类型的元素 print(l) #结果内两块内存地址 for i in l: #循环函数名, i() #调用函数
2、
def func(): #定义func函数 print(123) #函数体 def func2(f): #定义func2函数,并设置形参f f() #调用形参,结果为123 return f #函数名可以作为函数的返回值来返回 func2(func) #执行func2函数,并将上面的func函数当实参传给func2的形参
闭包
说明:
闭包即为内部的函数调用外部函数的变量。
操作:
def outer(): #定义函数 a = 1 #函数体 def inner(): #在outer函数里又定义了一个函数,这是一个闭包 print(a) #函数体,调用上级函数里的变量了 return inner #将outer函数里的函数inner作为返回值 inn = outer() #在全局里接收返回值 inn() #在外面接收函数返回值后再外面执行outer函数下的inner函数, #说明:由于outer里定义了变量a=1,且被inner函数调用,同时inner函数被当返回值传到外面,外面调用了inner函数,这样,a = 1这个变量使用后就不会清除,而是等到整个程序结束后才清除,这样节省了这个变量的生成和清除的时间
三元运算
说明:
1、使用三元运算的条件:1、必须要有结果,2、必须要有if和else,3、只能时简单的情况,如果负责则三元运算实现不了
实操:
a = 3 #定义变量a = 3 b = 2 #定义变量b = 2 print(a) if a > b else print(b) #语法说明:条件为True的结果(这个结果可以直接打印,或变量接收等) if 条件 else 条件为False的结果

浙公网安备 33010602011771号