一、函数的简介
我们写一个计算字符串或列表等长度的方法,方法类似len()方法,发现实现的代码几乎相同:
1 s1='1234567890' 2 def my_len(): 3 count = 0 4 for i in s1: 5 count+=1 6 print(count) 7 my_len() 8 print(len(s1))
首先,之前只要我们执行len方法就可以直接拿到一个字符串的长度了,现在为了实现相同的功能我们把相同的代码写了好多遍 —— 代码冗余
其次,之前我们只写两句话读起来也很简单,一看就知道这两句代码是在计算长度,但是刚刚的代码却不那么容易读懂 —— 可读性差
使用函数可以解决以上问题:
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print(),len()等。但你也可以自己创建函数,这被叫做用户自定义函数。
1、格式
del 关键字 函数名(设定与变量相同):
函数体
return:函数的返回值
函数名(): 执行函数
函数名会加载到内存,函数体不会执行
():调用运算符
2、return
1)遇到return,结束函数。
2)给函数的调用者(执行者)返回值。
无return 返回None
return 不写或者None 返回None
return 返回单个数
return 返回多个数 将返回的数据放在元组中返回
1 # 例1 2 def func1(): 3 print(111) 4 return 5 print(222)#此行代码不会执行 6 func1() 7 8 # 例2 9 s1='1234567890' 10 def my_len(): 11 count = 0 12 for i in s1: 13 count+=1 14 return count 15 print(my_len()) 16 17 #例3 18 s1 = '1234567890' 19 def my_len(): 20 count = 0 21 for i in s1: 22 count+=1 23 return count,111,222 24 print(my_len(),type(my_len()))#>>>(10, 111, 222) <class 'tuple'> 25 ret1,ret2,ret3=my_len()#分别赋值 26 print(ret1)#>>>10 27 print(ret2)#>>>111 28 print(ret3)#>>>222
二、函数的参数
1 #以下函数实现了len()计算元素长度的功能,但是不能动态的计算 2 s1 = '1234567890' 3 def my_len(): 4 count = 0 5 for i in s1: 6 count+=1 7 return count 8 print(my_len()) 9 print(len(s1)) 10 #修改如下,通过函数的参数,可以动态的计算元素的长度 11 s1 = '1234567890' 12 l1=[111,222,3333,'aaaa'] 13 def my_len(a):#函数的定义(形参) 14 count = 0 15 for i in a: 16 count+=1 17 return count 18 ret = my_len(s1)#函数的执行(实参) 19 print(ret)#>>>10 20 print(my_len(l1))#>>>4
1、从实参角度
1 #1.位置参数。必须一一按顺序对应 2 def func1(x,y): 3 print(x,y) 4 func1(1,2)#>>>1 2 5 6 #2.关键字参数。必须一一对应,不分顺序 7 def func2(x,y,z): 8 print(x,y,z) 9 func2(y=2,x=1,z=5)#>>>1 2 5 10 11 #练习 比较两个数大小 12 def max(x,y): 13 if x>y: 14 return x 15 else: 16 return y 17 print(max(4,2))#>>>4 18 19 #三元表达式 20 # def max(a,b):return a if a>b else b 21 22 #3.混合参数 一一对应 并且关键字参数必须在位置参数后面 23 def func2(argv1,argv2,argv3): 24 print(argv1,argv2,argv3) 25 func2(1,2,argv3=4)#>>>1 2 4
2、从形参角度
1 #1.位置参数,与实参相同 必须一一对应 按顺序 2 3 #2.默认参数,必须在位置参数后面。 4 #例:统计人员的姓名和性别,统计在文件当中 5 def register(name,sex='男'): 6 with open('register',encoding='utf-8',mode='a') as f1: 7 f1.write('{} {} '.format(name,sex)) 8 while True: 9 name = input('请输入姓名(输入/q 或者 Q 退出):') 10 if name.upper()=='Q':break 11 if 'a' in name: 12 sex = input('请输入性别:') 13 register(name, sex) 14 else: 15 register(name) 16 #3.动态参数 *args, **kwargs 万能参数 17 # 当参数个数不固定时,可以用万能参数 18 def func2(*args,**kwargs): 19 print(args)#元组(接收所有的位置参数,并一起放在元组中) 20 print(kwargs)#字典(接收所有关键字参数,并一起放在字典中) 21 func2(1,2,3,'alex',c='222',v='3333') 22 #顺序:位置参数 *args 默认参数 **kwargs, 23 def func3(a,b,*args,sex='男',**kwargs): 24 print(a) 25 print(b) 26 print(sex) 27 print(args) 28 print(kwargs) 29 func3(1,2,'hello','world','你好',sex='女',name='Lucy',age=18) 30 #>>>1 31 #>>>2 32 #>>>女 33 #>>>('hello', 'world', '你好') 34 #>>>{'name': 'Lucy', 'age': 18} 35 36 #传入3个列表,将每一个列表元素添加到args里 37 def func1(*args,**kwargs):#函数的定义:*变量 聚合功能,将所有的实参的位置参数聚合到元组里。**变量 聚合功能,将实参的所有的键值对的参数聚合到字典里。 38 print(args) 39 print(kwargs) 40 l1=[1,2,3,4] 41 l2=['a','b','c',5] 42 l3=(6,7,8,9,0) 43 func1(*l1,*l2,*l3)#函数的执行:*变量 打散功能。 44 #>>>(1, 2, 3, 4, 'a', 'b', 'c', 5, 6, 7, 8, 9, 0) 45 #>>>{} 46 dic1={'name1':'Lucy'} 47 dic2={'name2':'Lily'} 48 func1(**dic1,**dic2) 49 #>>>() 50 #>>>{'name1': 'Lucy', 'name2': 'Lily'}
三、函数的进阶
python不是内存级别的编程语言,C语言是内存级别的编程语言,有指针的概念。
我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。
等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;
在函数的运行中开辟的临时的空间叫做局部命名空间。
名称空间:包括全局名称空间,局部名称空间,内置名称空间。
全局名称空间:程序运行时,存放变量与值的关系
临时名称空间:也叫局部名称空间。存入函数里面的变量与值的关系,随着函数的执行结束,临时名称空间消失
内置名称空间:创建py文件后,就会把内置名称空间加载到内存
作用域:全局作用域:包括全局名称空间 、内置名称空间
局部作用域:局部名称空间
加载顺序:内置名称空间--->全局名称空间--->局部名称空间(函数执行时)
取值顺序:局部名称空间--->全局名称空间--->内置名称空间
1 #内置函数 2 #globals() 把全局变量和值的关系放在字典中 3 #locals() 把局部变量与值的关系放在字典中 4 name1='Lucy' 5 def func1(): 6 name2 = 'Lily' 7 print(globals()) 8 print(locals()) 9 func1() 10 #>>>{'__name__': '__main__', '__doc__': ' ', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E474CEC2B0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/28163/PycharmProjects/python21期/day3/day3笔记.py', '__cached__': None, 'name1': 'Lucy', 'func1': <function func1 at 0x000001E474DC5F28>} 11 #>>>{'name2': 'Lily'} 12 #关键字 : global nonlocal
四、关键字: global nonlocal
1、global:声明一个全局变量,更改一个全局变量
1 def func1(): 2 global name#在局部名称空间声明一个全局变量 3 name='Lucy' 4 return 5 func1() 6 print(name)#>>>Lucy 7 8 name='Lily' 9 def func1(): 10 global name#修改全局变量 11 name='Lucy' 12 return 13 func1() 14 print(name)#>>>Lucy
2、nonlocal:不能对全局变量进行引用,可以对局部作用域的变量进行引用和更改
1 def func1(): 2 name = 'Lily' 3 print('1:',name) 4 def func2(): 5 nonlocal name#修改局部变量 6 name='Lucy' 7 print('2:',name) 8 func2() 9 print('3:',name) 10 func1() 11 #>>>1: Lily 12 #>>>2: Lucy 13 #>>>3: Lucy
五、函数名
1、第一类对象(first-class object)指
1)可在运行期创建
2)可用作函数参数或返回值
3)可存入变量的实体。
2、函数是第一类对象的概念
1) 函数名 --> 函数的内存地址
2) 函数名可以作为 容器类型的元素 函数的参数、返回值 还能进行赋值 --> 变量
1 #函数名 2 # 1、可以互相赋值。 3 def func1(): 4 print('aaa') 5 f1=func1 6 f1()#>>>aaa 7 8 #2、可以当成函数的参数 9 def func1(): 10 print('aaa') 11 def func2(argv): 12 argv() 13 print('bbb') 14 func2(func1) 15 #>>>aaa 16 #>>>bbb 17 18 #3、可以当成容器类数据类型的参数 19 def func1(): 20 print('aaa') 21 def func2(): 22 print('bbb') 23 def func3(): 24 print('ccc') 25 l1=[func1,func2,func3] 26 for i in l1: 27 i() 28 #>>>aaa 29 #>>>bbb 30 #>>>ccc 31 32 #4、函数名可以当成函数的返回值 33 def func1(): 34 print('aaa') 35 def func2(argv): 36 print('bbb') 37 return argv 38 ret=func2(func1) 39 ret() 40 #>>>bbb 41 #>>>aaa