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

时间:2022-08-28 03:21:34

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 返回另一个函数

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