python全栈开发中级班全程笔记(第二模块)第 二 部分:函数基础(重点)

时间:2022-05-10 15:13:26

python学习笔记第二模块         第二部分    :    函数(重点)

一、函数的作用、定义 以及语法

1、函数的作用

python全栈开发中级班全程笔记(第二模块)第 二 部分:函数基础(重点)

2、函数的语法和定义

函数:来源于数学,但是在编程中,函数这个概念与数学中大不相同,在不同的编程语言里,有不同的叫法。

在 python 里叫函数,是指将一个语句的集合,通过一个名字(函数名)封装起来,执行时,调用函数名即可

特点:

(1)减少重复代码(简洁)

(2)使程序变得可扩展(更广泛)

(3)让程序变得易维护(好维护)

python全栈开发中级班全程笔记(第二模块)第 二 部分:函数基础(重点)

3、函数的基本语法(pycharm实现)

例:
#实现函数语法:
def sayhi(): #注意,冒号和小括号一定要有不能忘记
print("hello world!")
print("python好简单")
print("学会挣大钱")
print("hello my name is Guoyilong age :25")
print(sayhi) #不带括号,会出现一个内存地址,也就是函数名的内存地址
sayhi() #直接写名字,执行的时候就会出现函数内容 执行后效果:
<function sayhi at 0x00000286F8393EA0> #打印不带括号的函数名会出现函数的内存地址
hello world!
python好简单
学会挣大钱
hello my name is Guoyilong age :25

4、函数内的参数(pycharm实现)

  函数名的括号内,可以写进去很多参数,实现不同的功能。下面代码实现下简单参数的作用

例:
#函数内参数
def sayhi(name): #括号里面的“name”就是参数,在这里设置什么,执行前就要穿进去对应的值
print("hello",name)
print("hello my name is Lin Da age :25")
sayhi("GuoYilong") #上边设置了参数,这边就要写进对应的值,否则会报错提示没有对应的值 #执行后: hello GuoYilong #填进去参数会自动生成
hello my name is Lin Da age :25

5、函数内简单的计算参数:

   数学计算,也可以用函数来实现,而且利用函数,还可以实现自定制输入不同参数,计算不同结果),

  下面代码实现:

例:
def calc(x,y): #定义两个参数
res = x**y
print(res)
calc(5,7) #需输入两个参数,输入参数不同,产生结果不同
calc(3,6) #参数作用就是产生一定程度的自定制 #执行后输出: 78125
729

以上就是函数的基本方法和函数内简单的参数实现方法

下面分析下它的几个特性

1、减少代码重复:这个一看就很明显,直接调用函数名,比之前挨个编写节省很多空间,很简洁。

2、使用程序变得可扩展:不用函数,要写很多重复的,而且容易出错,现在只需要写一个就可以全部实现,修改也方便

3、使程序变的易维护:方便维护,检索一个地方,不繁杂,好维护。

二、函数内的参数

定义:参数可以让函数更灵活啊,不只能做默认参数的事情,还可以根据调用时传入参数的不同,来决定函数内部的执行流程

参数 包括 形参变量  和  实参变量

1、形参变量

形参,参数内部占位,只能在函数内部使用,函数调用结束,返回主函数后,就不能再使用该形参变量,

在被调用时才分配内存单元,调用结束后,即刻释放内存。(就像一个数学公式

2、实参变量:

实参,就是实际的参数,真真正正存在的值,可以是常量、变量、表达式、函数、列表、字典等,无论实参是何种变量,

在函数调用时,都必须有确定的值,以便把这些值传给形参。因此应预先赋值或现实输入等办法使参数获得确定的值。(就像公式中的值

下面代码验证下 :

形参
例:
def calc(x,y): #定义两个参数,这就是形参(占位)
res = x**y #就像是一个数学公式
print(res) #调用时分配内存单元,调用结束后即刻释放

实参 

例:
a = 4 #变量可以赋数字,也可以是列表,字典,字符串,函数等等很多类型
b = 7
calc(a,b) #括号内的 a 和 b 这就是实参
calc(b,a) #就像是公式中的具体值

3、默认参数

  默认参数,就是有一个固定的值,如果不修改,他也会填进去,如果修改,就按修改后的填

下面代码举例说明:

例:
def stu_register(name,age,country,course): #括号内为形参
print("---------注册学生信息——————")
print("姓名",name)
print("年龄",age)
print("国籍",country)
print("课程",course) stu_register("卿秀安",22,"CN","python") #括号内为实参
stu_register("灵千少",24,"CN","java")
stu_register("张旭东",20,"CN","c+")
发现大部分学生信息国籍都是中国(CN),大部分都是国内的学生,那能不能把国籍默认写成中国,其他国家的也可另外修改。
这个就用到了默认参数的作用
下面我们代码实现:
例:
def stu_register(name,age,course,country = "CN"): #注意,默认参数赋值后,必须放在最后面,不能影响位置参数的排序
print("---------注册学生信息——————")
print("姓名",name)
print("年龄",age) #打印顺序就是位置参数,如果下面填写错误,电脑是分辨不出来的,只能按照填写的运行
print("国籍",country)
print("课程",course) stu_register("卿秀安",22,"python") #一旦把默认参数放在没赋值的参数前面,系统会报错,而且会影响位置参数的显示
stu_register("灵少",24,"java")
stu_register("张旭东",20,"c+")

以上两种代码写出来的效果都是一样的

---------注册学生信息——————
姓名 卿秀安
年龄 22
国籍 CN
课程 python
---------注册学生信息——————
姓名 灵少
年龄 24
国籍 CN
课程 java
---------注册学生信息——————
姓名 张旭东
年龄 20
国籍 CN
课程 c+

4、关键参数

定义:正常情况下,给函数传参需要按照位置顺序,不想按照位置顺序就可以用关键参数。只需指定参数名即可(指定了参数名的参数就叫关键参数

  但是要求是,关键参数要放在位置参数(以位置顺序确定确定对应关系的参数)之后。

代码实现:

例:
def stu_register(name,age,course,country = "CN"):
print("---------注册学生信息——————")
print("姓名",name)
print("年龄",age)
print("国籍",country) #位置参数是这样的
print("课程",course) stu_register("卿秀安",course="python",age=18,country=“JP”) #改变了位置参数的默认顺序,但是我都指定赋值,这就是主要参数
执行结果:
---------注册学生信息——————
姓名 卿秀安
年龄 18
国籍 JP #发现位置没有改变,而且都对应
课程 python

5、函数--非固定参数

没有特殊的定义,举例说明下:

就拿刚讲的发报警的事情来说,之前给一个运维人员发报警,没什么问题,但是现在我的需求是给10个人甚至之后的更多个人发,

怎么实现这个需求呢?

代码来看:

例:
#非固定参数1(元祖型)
#发报警,1个人,是这样写的
def send_alert(msg,users):
pass
send_alert("赶紧招呼系统","Guo Yilong") #警报只发给一个人
#报警发给10个人,怎么办呢?
def send_alert(msg,*args): #只需要在原有的基础上,给users前加个 * 符号(相当于给参数内定义一个元祖),
#就能实现把多个名字打包一起赋给users(前面加个 * 这个时候,users就属于元祖类型)

for u in args:
print("报警发送给",u) #用 for 循环,把元祖循环打印,发给不同的人,这样就可以实现给10个甚至更多个人发消息 #总结,如果参数里面出现了 *users传递的参数就可以不再是固定参数,而是传过来的所有参数都会打包成元祖发送给 *usres

#方法一:
send_alert("赶紧回来,系统出问题了","Alex","Guo Yilong","Wangle","Lining","Msck","Tige") #有多少个人,就可以加多少个人
#方法二:
send_alert("赶紧回来,系统出问题了",*["Alex","Guo Yilong","Wangle","Lining","Msck","Tige"]) #这样就相当于把 * 符号后面的列表自己打包,传给 *args
#
需要注意了:带 * 符号的参数放在所有参数最后,除了用主要参数去实现,否则会报错。

上面讲了用元祖类型的参数实现非固定应用

下面我们用字典类型的参数实现非固定参数的应用:

例:
#非固定参数2(字典型)
def func(name,*args,**kwargs): #参数前加一个 * 符号,属于元祖类型,加两个 ** 符号,就属于字典类型
print(name,args,kwargs) #我们先证明数据类型
func("Guoyilong",22,"Alex","peiqi", "shanshan") #传进去多个实参
#执行效果
Guoyilong (22, 'Alex', 'peiqi', 'shanshan') {} #发现除了name有对应的值,其他值都赋给了元祖,字典是空的,

发现字典是空的,是因为传进去的实参,既没有字典的特征,也没有定义字典

**kwaegs 这个参数接收的是未定义的关键字参数

下面我们改变方法实现:

#有字典特征,实现字典内写入实参:
例:
def func(name,*args,**kwargs):
print(name,args,kwargs) func("Guoyilong",22,"Alex",adds = "peiqi",tesla = "shanshan",mck = "Wanghua") #给实参内写入字典格式,通过判断 key ,来实现如果过有 去a , 没有 去b。
执行代码结果:
Guoyilong (22, 'Alex') {'adds': 'peiqi', 'tesla': 'shanshan', 'mck': 'Wanghua'} #发现字典内已有写入的实参

 或者直接定义字典(调用时,直接定义声明,这个就是传给字典结构的)

定义型:
例:
def func(name,*args,**kwargs):
print(name,args,kwargs)
c = {"im":"Liuxin","se":"Qiqiang"} #把字典赋给变量 c
func("qiqi","lingsen",**c) #在变量前加 **
执行代码结果:
qiqi ('lingsen',) {'im': 'Liuxin', 'se': 'Qiqiang'} #成功实现了功能

 三、函数 -- 返回值

函数在外部的代码想要获取函数的执行结果,就可以在函数里用 return 语句把函数内的执行结果返回。

需要注意的是:

1、函数在执行过程中,只要遇到 return 语句,就会停止并返回结果,也可以理解为,函数里只要遇见 return 语句,代表着函数的结束。(如果在函数缩进内的 retutrn 下面再写任何代码,都不会被执行)

2、如果未在函数中定义 feturn ,这个函数会返回值 None 

注册信息的代码举例说明:

返回值的作用
例:
def stu_register(name,age,course,country = "CN"):
print("---------注册学生信息——————")
print("姓名",name)
print("年龄",age)
print("国籍",country)
print("课程",course)
if age > 22:
return False #返回值,一定要返回有用的东西
else :
return True
registriation = stu_register("灵少",24,"java")
if registriation:
print("注册成功") #返回值调用在函数外的使用
else :
print("你太老了")
执行代码结果:
---------注册学生信息——————
姓名 灵少
年龄 24
国籍 CN
课程 java
你太老了 #返回值得作用

不止能返回 False 和 True 这两个值,还可以返回列表,元祖等类型

返回元祖:
例:
def stu_register(name, age, course, country="CN"):
print("---------注册学生信息——————")
print("姓名", name)
print("年龄", age)
print("国籍", country)
print("课程", course)
return name,age #如果要返回多个值,在句尾加逗号
registriation = stu_register("灵少",24,"java")
print(registriation) #打印变量
执行代码结果:

---------注册学生信息——————
姓名 灵少
年龄 24
国籍 CN
课程 java
('灵少', 24) #它会把输入的值变成元祖返回
返回列表类型:
例:
def stu_register(name, age, course, country="CN"):
print("---------注册学生信息——————")
print("姓名", name)
print("年龄", age)
print("国籍", country)
print("课程", course)
return [name,age] #返回列表,只需要把返回值填进列表内,(多个值单词用逗号隔开)
registriation = stu_register("灵少",24,"java")
print(registriation) #打印变量
执行代码结果:
例:
---------注册学生信息——————
姓名 灵少
年龄 24
国籍 CN
课程 java
['灵少', 24] #已返回列表

四、函数 -- 局部变量

  函数内定义的变量,就叫局部变量,在函数内定义的变量,与函数外没任何关系

  下面我们代码验证下:

局部变量:
例:
name = "Guo Yilong","hello world!" #在函数外,把文字写成英文
def choice_name():
name = "郭毅龙","你好" #(局部变量)在函数内,把名字写成中文
print("内",name) #打印函数内名字
choice_name()
print("外",name)
#这函数内和函数外虽然变量名是相同的,但是他们是完全独立的,没有任何关系
执行代码结果:

内 ('郭毅龙', '你好')                  #函数内的值
外 ('Guo Yilong', 'hello world!') #函数外的值

 下面更详细的验证下相同变量名的内存地址是否相同

例:
name = "Guo Yilong","hello world!"
def choice_name():
name = "郭毅龙","你好"
print("内",name,id(name))
choice_name()
print("外",name,id(name))
执行代码结果:

内 ('郭毅龙', '你好') 2993864636857
外 ('Guo Yilong', 'hello world!') 2993864700936 #发现两个内存地址完全不同

还有一种情况就是,如果函数缩进内没有变量会调用外部变量(只能调用不可修改)

下面代码验证下:

优先级别:(由内而外)
例:
name = "Guo Yilong","hello world!"
def choice_name():
print(name,id(name)) #如果内部没有变量,会自动调用函数外变量
choice_name() #分优先级别,先调用函数缩进内变量,如果没有 ,会调用函数外变量
print("外",name,id(name))
执行代码结果:

('Guo Yilong', 'hello world!') 2176036502664
外 ('Guo Yilong', 'hello world!') 2176036502664 #这就叫由内而外,发现调用了外部变量

小结:

  1. 全局变量:定义在函数外部的一级代码变量,按照顺序全局都可调用。 
  2. 局部变量:是定义在函数缩进内的变量,只能在函数内生效,函数执行结束,局部变量全部无效。
  3. 如果全局和局部都有同名变量,函数会查找变量顺序(由内而外)优先使用函数内部变量,如果相同级别有两个函数的同名变量,它们也是独立的,函数只会优先调用函数缩进内变量,如果没有回调用全局变量,与另外一个同级别函数无关
  4. 函数内部调用全局变量,不可修改,如需修改,需重新定义变量或创建
  5. 函数内可以引用全局变量,但是全局不可以调用局部变量

五、在函数内修改全局变量

     在实际应用中,不建议在函数内修改全局变量,但如果非要修改,也还是有方法的( global ),所以还是不建议在函数内修改全局变量,因为如果养成恶习,在以后涉及 代码量大的 时候,函数内修改全局变量会导致不好调试和维护,带来很多麻烦

代码讲一下方法:

修改全局变量:
例;
name = "Guo Yilong","hello world!"
def choice_name():
global name #新语法(意思是告诉python程序要修改全局变量、列表还有其他类型的变量)
name = "郭毅龙","你好" #把变量重新修改成汉语(也可是列表、元祖、字典等等其他类型)(注意顺序,先声明,再修改
age = 52
print("内",name) choice_name()
print("外",name)
执行代码效果:

内 ('郭毅龙', '你好')
外 ('郭毅龙', '你好') #发现都改掉了

  在函数内,不只能修改字符串变量,也可修改列表、函数等等很多变量

    下面我们看修改列表变量的方法

    先尝试普通方法能否修改: 

普通方法:
例:
names = ["Alex","peiqi","liudehua","meishu"] #先设定变量
def change_names():
names = ["Guoyilong","Meiliang","Alex"] #尝试直接改是否可行
print(names)
change_names()
print(names) #打印各层
执行代码结果:

['Guoyilong', 'Meiliang', 'Alex']
['Alex', 'peiqi', 'liudehua', 'meishu'] #发现并没有修改

    因为之前讲过,列表、其他类型套列表都是不可更改整个列表的内存地址的,(当然除了 global 这个方法 )但列表内的值是可以修改的,

    下面代码实现下:

修改列表内元素:
例:
names = ["Alex","peiqi","liudehua","meishu"] def change_names(): del names[3] #修改和删除列表内的元素
names[2] = "Guoyilong"
print(names) change_names()
print(names)
执行代码结果:

['Alex', 'peiqi', 'Guoyilong']
['Alex', 'peiqi', 'Guoyilong'] #发现已经修改成功,验证了上边的话
注意:所有包含很多字符串元素的内部值,都是可以通过这样方法实现修改,唯一不能修改的是:字符串和数字(因为本事就是个内存地址,没办法修改)

六、函数--嵌套函数

   元祖、列表、字典等类型可以嵌套,函数类型也可嵌套(利用缩进)

  下面代码执行下:   

嵌套函数:
例:
age = 22 #设定全局变量
def funt1():
age = 35 #设定各层级局部变量
print(age)
def funt2(): #内部函数可以再次定义函数
age = 48
print(age) #每一层都互不干扰
def funt3():
age = 77
print(age)
funt3()
funt2() #注意缩进
funt1() #执行时,需被调用,否则,不会执行
执行代码结果:

35                     #发现嵌套内代码 全部执行
48
77

  下面分析几个情况,把变量放在不同位置,看执行哪里变量

#换位置
age = 22
def funt1():
print(age)
def funt2():
age = 35
print(age)
def funt3():
print(age) #这种情况会执行那个变量
funt3()
funt2()
funt1()
代码输出结果:

22                     #发现外边函数调用的是全局变量
35 #发现内2套函数调用的是局部变量
35 #这就总结了局部变量的调用方法,它会由最内部逐层、逐级依次向外查找变量,找到为止

六、函数 -- 作用域

定义:在 python 中,一个函数就是一个作用域,所有的局部变量,就是放置在局部变量内,代码定义完成后,作用域就已生成,调用时,就会根据作用域嵌             套关系(也可称为作用域链)由内而外层层往上找。

下面我们代码验证下:

作用域
例:
第一
age = 18
def funt1():
age = 22
def funt2():
print(age)
return 666 #设置返回值
val = funt1()
print(val)
666                #被执行会会是 return 返回值,而不是其他

第二
age = 18
def funt1():
age = 22
def funt2():
print(age)
return funt2 #设置不带括号的函数名
val = funt1()
print(val)
执行代码结果;

<function funt1.<locals>.funt2 at 0x00000259AE603F28>    #返回 funt2 的内存地址,
#理下思路:val = funt1(),
而 funt1()设置的返回值 return 返回的是funt2 的内存地址 (函数名不加括号返回函数本身的内存地址)
这就证明,其实 val = funt2 (加了括号会返回funt2 函数代码的执行结果)
第三
age = 18
def funt1():
age = 22
def funt2():
print(age)
return funt2
val = funt1()
val() #现在把val 加上括号看是否与 val = funt2()相同
执行代码结果:

22                #和 funt2()  效果相同

 七、函数--匿名函数

匿名函数,顾名思义就是没起名字的函数,定义一个函数不用名字,下面先和正常函数对比下

匿名函数:
例:
#先写一个正常的函数
def calc(x,y):
return x*y #再看匿名函数
lambda x,y:x*y #这句话叫声明一个匿名函数,
#这个公式就和上边的正常函数一个效果,但是如果使用的话还是要定义一个变量
func = lambda x,y:x*y 下面验证下执行结果
print(calc(7,8) ) #执行正常函数
print(func(7,8) ) #执行匿名函数
执行代码结果:

56
56 #发现执行结果相同,说明作用相同

那么,匿名函数还能做什么,下下面我们再来看:

例:
#下面写一个判断
def calc(x,y):
if x < y:
return x*y
else :
return x/y
#正常函数判断是没错的,但是匿名函数内是不可以写这样复杂的判断的 func = lambda x,y:x*y if x<y else x/y #但是匿名函数可以用三元运算
print(calc(16,4))
print(func(16,4))
执行代码结果:

4.0
4.0
#执行结果也相同,其实只看上面觉得匿名函数还是要赋变量名,看着还很模糊,还不如用正常的函数
#这只是在普通场景下,在很多场景下,匿名函数不是单独使用而是搭配其他语法使用

匿名函数的搭配使用:

例:
#匿名函数最常用的是搭配其他语句的使用
#下面有一个列表,需求就是把列表的每一个值自乘(1*1,2*2,3*3....循环之)
data = list(range(10)) 1、用普通的方法(for 循环)
for index,i in enumerate(data):
data[index] = i*i #比较麻烦 map()
#新语法 :括号内可以放2个值(函数,数据集合)
相当于会把数据结合内的每一个值当做一个参数,交给函数执行一遍
2、用普通的函数实现map的功能
data = list(range(10))
print(data)
#先预设一个普通函数:
def func(n):
return n*n
map(func,data)#简单的这样就是可以取到值
f = list(map(func,data))# 但是传进去的是列表所以要打印列表格式
print(f)
3、用 lambda 函数(匿名函数)实现
data = list(range(10))
print(data)
print(list(map(lambda x :x*x,data)))
****以上代码执行结果都是一样的*****
#lambda 后面就是匿名函数,我再这里使用之后就不再调用,所以只在这一个地方起作用就可以了

*** 匿名函数小结:1、节省代码量      2、看着高级 

八、函数--高阶函数

  定义:变量可以指向函数,函数的参数可以接收变量,那么一个函数就可以接收另一个函数作为参数,而这种函数就称为高阶函数。

  变量可以指向函数:

例:
f = lambda x: x*x #变量可以指向函数
print(f(8)) def calc(x,y): #变量可以指向函数
return x/y
s = calc
print(s(8,4))

函数的参数可以接收变量:

例 :

def calc(x,y):           #设置正常函数
return x+y
def func(x):
return x*x
n = calc #函数可设置成变量
a = 7
b = 13
print(n(a,b)) #函数的参数可以设置成变量

这就相当于一个函数的参数可以设置成另外一个函数(一个函数就可以接收另一个函数作为参数):

例:
def calc(x,y): #设置一个函数
return x+y def func(x): #设置另一个参数
return x f = func(calc) #相当于第一个函数被第二个函数当做参数执行,
print(f(7,5)) #因为第一个函数被当作参数,所以要传进去2个值

以上这种函数结构就叫高阶函数

还有另一种方法:(把函数当作一个参数返回)

例:
def calc(x,y): #设置一个函数
return x+y
def func():
return calc(7,5) #把上一个函数当做函数的返回值 print(func())

绝对值函数:

例:
def func2(x,y): #设置一个函数
return abs(x+y) # abs() 新语法:绝对值,就是负数绝对值后成正数返回(abs()是参数)
print(func2(-5,-8))
执行代码结果:

13                    #已经当正数返回
例:
def func2(x,y): #再设置一个参数
return abs,x,y # abs() 新语法:绝对值,就是不管正负数,都会返回正数
res = func2(7,-11) #只要函数内包含另一个函数,就被称为高阶函数
print(res)
执行代码结果:

(<built-in function abs>, 7, -11)  #只要执行的函数包含另一个函数就叫高阶函数

高阶函数查看执行结果:

例:
def func2(x,y):
return abs,x,y
res = func2(-3,-11)
print(res[0](res[1]+res[2])) #函数也是以索引为导向提取对应的值,注意括号外的是函数名,括号内的值为函数的参数
执行代码结果:

14               #这就是告诫函数,和绝对值的作用
小结:只需满足下面任意条件即是高阶函数
1、接收一个或者多个函数作为输入(参数)
2、return 返回另一个函数

———————————————————结束线———————————————————