x 6什么意思python_python (六)函数

一、函数的形成

需求1:来测试一下‘hello word’ 的长度

# 在没有函数的时候,我们可以用for循环实现

s1= "hello world"length= 0

for i ins1:

length= length+1print(length)

再增加一个需求2:再来测试一下另外一个字符串的长度:‘hello china’

然后需求1和需求2的代码就变成下边这样

s1 = "hello world"length= 0

for i ins1:

length= length+1print(length)

s2= "hello china"length= 0

for i ins2:

length= length+1print(length)

上边的代码确实可以实现需求,但是有缺点:代码重复,可读性差。 我们将上面的代码称之为面向过程的方式

为了解决这种问题就出现了函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

二、函数的格式和调用

def mylen(): # 定义一个函数mylen

'''计算s1的长度'''

s1= "hello world"length= 0

for i ins1:

length= length+1print(length)

mylen() # 函数调用

def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。

def是固定的,不能变,他就是定义函数的关键字。

空格为了将def关键字和函数名分开,必须空(四声)

函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能

括号:是必须加的

注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。

调用:就是 函数名()

二、函数的返回值

1、什么是函数的返回值

在使用内置函数len()方法时,得到的结果会赋值给一个变量,然后得到结果:

str_len = len('hello,world')

print(str_len)

但是自己写的这个函数mylen(),并不会得到这样的结果,如何让他和len函数一样,有返回值呢?

那就是在函数的最后加上一个return,return 后面写你需要的返回值就可以了。

#函数定义

def mylen():"""计算s1的长度"""s1= "hello world"length= 0

for i ins1:

length= length+1

returnlength

#函数调用

str_len=mylen()

print('str_len : %s'%str_len)

return返回值

2、return关键字的作用

1、函数中遇到return终止函数。

2、返回值 返回给了函数的调用者

3、return返回值的的三种情况

第一种:没有return   返回None

def mylen():

s1= "hello world"length= 0

for i ins1:

length= length+1str_len=mylen()

print(str_len) # 因为没有返回值,此时的str_len为None

第二种:return后没有返回值

return的其他用法,就是一旦遇到return,结束整个函数。

def ret_demo():

print(111) # 此行代码执行return# 直接种植代码

print(222) # 此行不会输出

ret=ret_demo()

print(ret) # 因为return后没有任何值, 所以此处结果为None

第三种:单个值  返回单个值

#函数定义

def mylen():"""计算s1的长度"""s1= "hello world"length= 0

for i ins1:

length= length+1

returnlength

#函数调用

str_len=mylen()

print(str_len) # 返回这个字符串的长度,结果为11

第四种:多个值  返回一个由这多个值组成的元组

可以返回任意多个、任意数据类型的值

def ret_demo1():'''返回多个值'''

return 1, 2, 3, 4def ret_demo2():'''返回多个任意类型的值'''

return 1, ['a', 'b'], 3, 4print(ret_demo1()) # 结果为(1, 2, 3, 4)

print(ret_demo2()) # 结果为(1, ['a', 'b'], 3, 4)

def ret_demo2():return 1, ['a', 'b'], 3, 4#返回多个值,用一个变量接收

ret2=ret_demo2()

print(ret2) # (1, ['a', 'b'], 3, 4)

#返回多个值,用多个变量接收

a, b, c, d=ret_demo2()

print(a, b, c, d) #1 ['a', 'b'] 3 4#用多个值接收返回值:返回几个值,就用几个变量接收

a, b, c, d=ret_demo2()

print(a, b, c, d) #1 ['a', 'b'] 3 4

四、函数的参数

1.什么是参数

之前我们使用len函数的时候得是length = len("hello world"),但是这个函数,只能计算一个“hello world”的长度,换一个字符串就需要写多个函数,很不方便

def mylen(s1): # 定一个一个参数s1"""计算s1的长度"""length= 0

for i ins1:

length= length+1

returnlength

str_len= mylen("hello world") # 将hello world传递给s1

print(str_len)

我们告诉mylen函数要计算的字符串是谁,这个过程就叫做 传递参数,简称传参,我们调用函数时传递的这个“hello world”和定义函数时的s1就是参数。

2.认识实参和形参

我们调用函数时传递的这个“hello world”被称为实际参数,因为这个是实际的要交给函数的内容,简称实参。

定义函数时的s1,只是一个变量的名字,被称为形式参数,因为在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。

3.参数的传递

第一种:可以传递字符串,前边已经举例

第二种:可以传递列表

l1 = [1, 2, 34, 55, 66]

def my_len(s): # 形參s接收到实参l1的值

c= 0

for i ins:

c+= 1

returnc

ret=my_len(l1) # 将字符串l1传递给函数

print(ret)

4.按照实参角度传參

第一种:位置参数:从前至后 一一对应

def mymax(x, y): # x接收10,y接收20

the_max= x if x > y elseyreturnthe_max

ma= mymax(10, 20)

print(ma)

第二种:关键字传參:不用按照顺序,按变量名一一对应

def mymax(x, y): # 此时x = 20,y = 10the_max= x if x > y elseyreturnthe_max

ma= mymax(y = 10, x = 20)

print(ma)

第三种:混合传參:位置参数一定在前面

def mymax(x, y): # 此时x = 10,y = 20the_max= x if x > y elseyreturnthe_max

ma= mymax(10, y = 20) # 位置参数一定要在关键字参数前面

print(ma)

小总结:位置参数必须在关键字参数的前面

对于一个形参只能赋值一次

5.按照形參角度传參

第一种:位置传参: 按照顺序,一一对应,未给形參传值会报错

def func1(a, b, c, d):

print(a, b, c)

func1(1, 2, 3) # 结果会报错, 没有给位置参数d传值

第二种:默认传参: 如果不传,则默认使用默认参数,传参则覆盖。

为什么要有默认参数:将变化比较小的值设置成默认参数

def func2(name, age, sex='男'): # sex接收传来的参数'女'print(name, age, sex)

func2('大锤', 18, sex='女') # 结果:大锤 18 女

利用默认传參可以设置默认输入

def wfile(name, age, sex='男'): # 定义函数wfile,形參name、age,默认参数sex"""建立登记表函数,由于班中大部分学生都是男生,

所以设置默认参数sex的默认值为'男'

""" with open('登记表', encoding='utf-8', mode='a') asf1:

f1.write('{}|{}|{}\n'.format(name, age, sex)) # 格式化输入三个参数while 1: # 可以循环输入

name= input('姓名(输入Q/q退出):')if name.upper() == 'Q':break # 如果输入Q/q退出程序

age= input('年龄:')if name.startswith('王'): # 设置一个规则,如果姓名以'王'开头

wfile(name, age) # 函数只执行 name和age。sex无需执行,直接记录默认值'男'

else: # 否则(即:如果姓名不是以'王'开头) 就需要输入sex,并且执行name, age, sex

sex= input('性别:')

wfile(name, age, sex) # 这一步会把输入的sex覆盖默认值的值

默认参数是一个可变的数据类型

def func(a, l=[]): # 定义形參a,实参l=[]

l.append(a) # 将a的值添加至列表l中

print(l)

func('aaa') # ['aaa'],

func('bbb') # ['aaa', 'bbb']

func('ccc') # ['aaa', 'bbb', 'ccc']

6.万能参数

万能参数也叫动态参数:*args   **kwargs也叫不定长传参

需要传给函数的参数很多,不定个数,那这种情况下,你就用*args,**kwargs接收

l1 = [1, 2, 3]

l2= [11, 22, 33]

l3= (55, 66, 77)

dic= {'name': 'alex'}

dic1= {'age': '12'}def func4(*args, **kwargs):print(args)print(kwargs)

func4(*l1, *l2, *l3, **dic, **dic1) #(1, 2, 3, 11, 22, 33, 55, 66, 77) {'name': 'alex', 'age': '12'}

func4(l1, l2, l3, dic, dic1) #([1, 2, 3], [11, 22, 33], (55, 66, 77), {'name': 'alex'}, {'age': '12'}) {}

注意1:args是元祖形式,接收除去键值对以外的所有参数,kwargs接收的只是键值对的参数,并保存在字典中。

如果未接收到传来的参数,那么就会输出空值

def func4(*args, **kwargs):

print(args) # ([1, 2, 3], [11, 22, 33], (55, 66, 77))

print(kwargs) # {},**kwargs未接收到键值对的参数,所有输出的结果是一个空的字典

func4([1, 2, 3], [11, 22, 33], (55, 66, 77))

7.位置参数、默认参数、万能参数混合使用

# 默认参数未被更改

def func5(a, b,*args, sex='男'):

print(a) #1位置参数a接收第一个参数1

print(b) #2位置参数b接收第二个参数2

print(sex) # 男 默认参数未被更改,还是默认的值

print(args) # (4, 5, 6, 7, 8, 9) 剩下的全部使用*args接收

func5(1, 2, 4, 5, 6, 7, 8, 9)

# 默认参数已被更改

def func5(a, b,*args, sex='男', **kwargs):

print(a) #1位置参数a接收第一个参数1

print(b) #2位置参数b接收第二个参数2

print(sex) # 女 默认参数已被更改,所以输出新值

print(args) # (4, 5, 6, 7, 8, 9) 剩下的全部使用*args接收

func5(1, 2, 4, 5, 6, 7, 8, 9, sex='女')

五、名称空间

先认识一下什么叫名称空间

def func1():

m= 1print(m)

func1()

print(m) # 报错 NameError: name'm' is not defined

上面为什么会报错呢?

函数被调用的时候,python解释器会再开辟一块内存来储存这个函数里面的内容,函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用

当函数执行完毕,这块内存中的所有内容也会被清空。

存放名字与值的关系的空间起了一个名字-------名称空间。

python中的名称空间:

全局名称空间:代码在运行开始,创建的存储“变量名与值的关系”的空间

临时(局部)名称空间:在函数的运行中开辟的临时的空间

内置名称空间: len print 等内置函数等等。

加载顺序: 内置名称空间  ---> 全局名称空间 ---> 函数执行时:临时(局部)名称空间

取值顺序:   函数执行时:临时(局部)名称空间 ---> 全局名称空间 ----> 内置名称空间

( 取值顺序满足就近原则 )

六、函数的作用域和嵌套

1、什么是作用域

作用域:作用域就是作用范围

全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

局部作用域:局部名称空间,只能在局部范围内生效

a = 1

print(a) #1

deffunc1():

a= 99

print(a) #99 满足就近原则,取最近的值

func1()

2、作用域中会遇到的坑

局部只能引用全局的变量但是不能修改,修改就会报错

a = 1print(a) #1def func1():

a+= 1print(a) # 会报错,不能引用全部变量a

func1()

global

可以修改全局变量

在局部空间可以声明一个全局变量

可变数据类型(list,dict,set)可以直接引用不用通过global。

# 修改全局变量

a = 1print(a) #1def func1():globala # 引用全局变量a,此时a的值为1

a+= 1print(a) #2func1()

# 声明全局变量

def func():globala # 没有全局变量的时候也可以使用,在函数内部直接声明了全局变量

a= 1func()

print(a) #1

# 引用可变的数据类型,无需global

li = [1, 2, 3]

dic= {'a': 'b'}defchange():

li.append('a') #无需global,可以直接引用

dic['q'] = 'g' ## 无需global,可以直接引用

print(dic) #{'a': 'b', 'q': 'g'}

print(li) #[1, 2, 3, 'a']

change()print(li) #[1, 2, 3, 'a']

print(dic) #{'a': 'b', 'q': 'g'}

nonlocal

不能操作全局变量

在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,且引用的哪层,从那层及以下此变量全部发生改变。

子名称空间只能引用父名称空间的变量,但是不能修改,如果修改就会报错

#只引用未修改

def func1(): #父名称空间

a = 1

def inner(): #子名称空间

print(a) #结果:1 函数执行的第二步输出

print(a) #结果:1 函数执行的第一步输出

inner()print(a) #结果:1 函数执行的第三步输出

func1()#未使用nonlocal,引用并且修改,会报错

def func1(): #父名称空间

a = 1

def inner(): #子名称空间

a += 1 #修改变量a

print(a) #会报错:local variable 'a' referenced before assignment

inner()print(a)

func1()#使用nonlocal后既可引用,也可修改

def func1(): #父名称空间

a = 1

def inner(): #子名称空间

nonlocal a #引用父名称空间的变量a

a += 1 #修改变量a,这层及以下此变量全部发生改变

print(a) #结果:2 函数执行的第二步输出

print(a) #结果:1 函数执行的第一步输出

inner()print(a) #结果:2 函数执行的第三步输出

func1()#不能修改全局变量

b = 3

def func1(): #父名称空间

a = 1

def inner(): #子名称空间

nonlocal a #引用父名称空间的变量a

a += 1 #修改变量a,这层及以下此变量全部发生改变

b += 1 #会报错,不能修改全局变量:local variable 'a' referenced before assignment

print(a) #结果:2 函数执行的第二步输出

print(a) #结果:1 函数执行的第一步输出

inner()print(a) #结果:2 函数执行的第三步输出

func1()

3.函数的嵌套

#第一种函数嵌套

def func1(): #第二步执行func1

print(111) #第三步,输出111

def func2(): #第六步执行func2

print(222) #第七步 输出222

print(333) #第四步,读到这一行,输出333

func2()#第五步执行func2

print(444) #第八步,输出444

func1()#函数执行时先读这一行

#第二种函数嵌套

def func1(): #第七步 执行func1

print(111) #第八步 输出111

def func2(): #第四步 执行func2

print(222) #第五步 输出222

func1() #第六步 读到这一行

def func3(): #第二步 执行func3

func2() #第三步,读到这一行

print(333) #第九步,输出333,因为其余内嵌的函数已经全部执行完了

func3()#函数执行时先读到这一行

4.函数的作用域

小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。

#大范围的作用域不能使用小范围的变量#第一种 大作用域f1中未定义变量,试着使用小作用域f2中的a的值,会报错

deff1():deff2():

a= 2

print(a)

f2()print(a) #第二步,f1中未定义变量a,无法取f2中的值,所以会报错 name 'a' is not defined

f1()#修改上边的报错:在大作用域f1中定义a

deff1():

a= 1

deff2():

a= 2

print(a) #先输出a的值为2

f2()print(a) #再输出a的值为1,此a是f1中的a,与f2中的a无关,只是名字相同

f1()#第二种 小范围的作用域能使用大范围的变量

deff1():

a= 1

deff2():print(a) #取的是f1中的a的值1

f2()

f1()

七、函数名的运用

1、直接输出函数名(输出函数的内存地址)

deffunc1():print(111)print(func1) #输出函数func1的内存地址

f1 = func1 #将func1的函数名传给f1

f2 = f1 #将f1的值赋值给f2

print(f2) #输出f2,既输出f1,即输出func1的内存地址,

f2() #,执行f2,即执行f1,即执行func1,结果为 111

2、函数名可以作为函数的参数

def func1(): #第五步 执行此函数

print(111) #第六步 输出111

def func2(x): #第二步 x接收传来的值func1

print(x) #第三步 输出func1的内存地址

x() #第四步 执行x函数,即执行func1

func2(func1) #第一步,代码读到这一行,将func1传给x

3、函数名可以作为函数的返回值

#当作函数的返回值#第一种

def f1(): #第四步 执行f1函数

print(111) #第五步 输出111

def func1(argv): #第二步 argv 接收到函数名f1

argv() #第三步 执行argv(),即执行f1(),第五步执行完的结果为111

return argv #第六步 将argv的函数名返回给func1

f= func1(f1) #第一步 将函数名f1传给argv,第六步执行完,func1(f1) = argv

f() #第七步 f()本质上就是argv(),执行argv()

#从第三步得知,执行argv()即执行f1,最后输出结果为111

#第二种

def func1(): #第五步,执行func1

print(111) #第六步 输出111

def func2(x): #第二步 执行func2,x接收到函数名func1, x = func1

return x #第三步 将x返回给函数的调用者func2,即将函数名func1返回给函数func2

ret= func2(func1) #第一步 执行等号后的func2(func1),将函数名func1传给x

#并将函数func2的值传给ret

#第三步执行完,此时func2(func1)的值为func1,这个等式可以写成ret = func1

ret() #第四步 执行ret(),其实就是执行func1()

4、函数名可以作为容器类数据类型的参数

#函数名作为列表中的元素#第一种 直接调用

def func1(): #第三步 执行此函数

print(111) #第四步 输出111

deffunc2():print(222)deffunc3():print(333)

li= [func1, func2, func3] #第一步,先读到这行,函数名作为列表的元素

li[0]() #第二步 li的0号元素是func1,li[0]()本质上就是func1()

#第二种 循环调用

deffunc1():print(111)deffunc2():print(222)deffunc3():print(333)

li= [func1, func2, func3] #第一步,先读到这行,函数名作为列表的元素

for i in li: #循环执行三个函数

i()#函数名作为字典中键的值#第一种 直接调用

deff1():print('111')def f2(): #第三步,代码读到这行,执行此函数

print('222') #第四步输出222

deff3():print('333')

dic= {'x': f1, 'y': f2, 'z': f3} #第一步 读到这行,函数作为了字典中键的值

dic['y']() #第二步 dic中'y'键的值是f2,dic['y']()本质上就是f2()

#第二种循环输出

deffunc1():print(111)deffunc2():print(222)deffunc3():print(333)deffunc4():print(444)

dic= { #第一步先读到这行

1: func1, #输入哪个数字,就执行哪个数字对应的函数

2: func2,3: func3,4: func4,

}while 1: #第二步 读到这行

choice = int(input('请输入数字:')) #第三步将输入的数字转化成int类型

dic[choice]() #第四步 dic[choice]()本质上就是执行输入的数字对应的 键的值 对应的函数

八、闭包

1、什么是闭包

1、闭包是嵌套在函数中的

2、闭包是内层函数对外层函数的变量(非全局变量)的引用(改变)

3、闭包需要将其作为一个对象返回,而且必须逐层返回直至最外层函数的返回值

2、闭包的格式

#闭包的基本格式

deffunc():

name= '大锤'

definner():print(name) #引用外部函数func的变量name

returninner

f=func()

f()#闭包举例#第一个 这步是闭包

deffunc1():'''此函数满足前闭包定义的前两个条件,但还不是闭包

因为没有返回值return'''name= '太白'

deffunc2():print(name)#第二个 这也不是闭包

ame = 'alex'

defwrapper():definner():print(name) #调用的是全部变量,非外层函数变量

returninner#第三个 这是闭包

defwrapper():

name= '太白'

definner():print(name)returninner#第四个 这个也是闭包

defwrapper(name):definner():print(name)returninner

n1= 'wusir'wrapper(n1)

3、 怎么样判断是不是闭包

#输出的__closure__有cell元素 :是闭包函数

deffunc():

name= '大锤'

definner():print(name)print(inner.__closure__)returninner

f=func()

f()#输出的__closure__为None :不是闭包函数

name = '大锤'

deffunc2():definner():print(name)print(inner.__closure__)returninner

f2=func2()

f2()

4、闭包的作用

#非闭包函数 随着函数的结束临时空间关闭

deffunc1(s1):

n= 1n+=s1print(n)

func1(5) #6

func1(5) #6

func1(5) #6

#闭包函数

defwrapper(s1):

n= 1

definner():

nonlocal n

n+=s1print(n)returninner

ret= wrapper(5)

ret()#6

ret() #11

ret() #16

小总结:

闭包的机制:python遇到闭包,产生一个空间,这个空间不会随着函数的结束而消失。

5、闭包的嵌套

def wrapper(): #第二步 执行此韩式

money = 100 #第三步

def func(): #第四步执行此函数

name = '大锤'

definner():print(name, money)returninnerreturn func #第五步 将函数名func返回给上层函数wrapper

f= wrapper() #第一步 代码读到这,第五步执行完,f=func

i = f() #第六步 执行f(),即执行func(),执行完func()后将函数名func再次传给i,此时i=func

i() #第七步 i()即func(),执行func,输出结果: 大锤 100

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值