zoukankan      html  css  js  c++  java
  • Python函数学习——初步认识

    函数使用背景

    假设老板让你写一个监控程序,24小时全年无休的监控你们公司网站服务器的系统状况,

    当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,

    你掏空了所有的知识量,写出了以下代码

    从图中可以看出上述代码存在了两个问题

    1.代码冗余

    2.维护性差

    我们如何解决这个问题?请看下图

    从上图可以看出:使用函数可以带来以下好处

    1. 减少重复代码
    2. 使程序变的可扩展
    3. 使程序变得易维护

    函数定义

    函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。

    定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

    代码表现形式:

     def  函数名(参数1,参数2):

        ''' 函数注释'''

        print('函数体')

        return 返回值

            定义: def关键字开头,空格之后接函数名和圆括号,最后还要加一个冒号。

              def是固定的,不能变。

      函数名:函数名是包含字母,数字,下划线的任意组合,但是不能以数字开头。虽然函数名可以随便取名,但是一般尽量定义成可以表示函数功能的。

          

    #下面这段代码
    a,b = 5,8
    c = a**b
    print(c)
    
    
    #改成用函数写
    def calc(x,y):
        res = x**y
        return res #返回函数执行结果
    
    c = calc(a,b) #结果赋值给c变量
    print(c)

    函数参数

    使用参数可以让你的函数更灵活,根据调用时传参的不同来决定函数内部的执行流程

    1.实参和形参

    形参: 是函数定义时候定义的参数
        只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。

    实参: 调用的时候传进来的参数
       可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,
    以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

     2.参数传递

    可以传递多个参数,多个参数之间用逗号隔开。
    调用函数时传参数有两种方式:
      1.按照位置传参数
      2.按照关键字传参数
    正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),
    但记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后
    用法:1.位置参数必须在关键字参数的前面
       2.对于一个参数只能赋值一次

    def stu_register(name, age, course,country):
        print("----注册学生信息------")
        print("姓名:", name)
        print("age:", age)
        print("国籍:", country)
        print("课程:", course)
    
    stu_register("alex", 23, "python", "china")  # 按照位置传递参数
    
    stu_register("alex", 23, course = "python", country = "china")  # 按照位置和关键字传递参数
    
    # 以下两种使用方法不正确
    stu_register("alex",  "python", 23, "china")  # 位置不对
    
    stu_register("王山炮", 22, age=25,country='JP')  # age参数被定义两遍

     3.默认参数

    用法:为什么要用默认参数?将变化比较小的参数设置成默认参数(比如中国网站上注册用户功能,像国籍这种信息,就可以设置个默认值参数country=CN)

    定义:默认参数可以不传,不传的时候用的就是默认值,如果传,会覆盖默认值。

    def stu_register(name, age, course, country = "CN"):
        print("----注册学生信息------")
        print("姓名:", name)
        print("age:", age)
        print("国籍:", country)
        print("课程:", course)
    
    stu_register("alex", 23, "python")  # 使用默认参数
    
    stu_register("Bill", 23, "python", "Japan")  # 覆盖默认参数

     默认参数使用注意点——可变数据类型 (字符串,数字等)

     默认参数使用注意点——不可变数据类型(列表,字典等)

     4.动态参数

    按位置传值多余的参数都由args统一接收,保存成一个元组的形式

    按关键字传值接受多个关键字参数,由kwargs接收,保存成一个字典的形式

    元祖
    def stu_register(name, age, *args):  # *args 会把多传入的参数变成一个元组形式
        print(name,age,args)
    
    stu_register("Alex",22)
    # 输出
    # Alex 22 () #后面这个()就是args,只是因为没传值,所以为空
    
    stu_register("Jack",32,"CN","Python")
    # 输出
    # Jack 32 ('CN', 'Python')
    字典
    def stu_register(name, age, *args, **kwargs): # *kwargs 会把多传入的参数变成一个dict形式
        print(name,age,args,kwargs)
    
    stu_register("Alex",22)
    #输出
    #Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
    
    #传参数的时候:必须先按照位置传参数,再按照关键字传参数
    stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
    #输出
    # Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
    
    def fun(a,b,**kwargs):
        print(a,b,kwargs)
    
    # 按照关键字传参数
    fun(a = 10,b = 20,cccc= 30,dddd = 50)
    # 输出
    # 10 20 {'cccc': 30, 'dddd': 50}
    
    
    
    def f(a,b,*args,defult=6,**kwargs):
        #位置参数,*args, 默认参数,**kwargs
        # print(a,b,args,defult,kwargs)
        return a,b,args,defult,kwargs
    
    # 传参数的时候:必须先按照位置传参数,再按照关键字传参数
    print(f(1,2,7,8,ccc=10,der=5)) 
    # 输出
    # 1,2,(7,8),6,{'ccc':10,'der':5}
    动态参数拆包与装包

    1.*args 

    def run(a,*args):
        #第一个参数传给了a
        print(a)  # 1
        # args是一个元组,里面是2和3两个参数
        print(args)  # (2,3)
        # *args是将这个元组中的元素依次取出来
        print("对args拆包")
        print(*args) # 2 3 *args 相当于 a,b = args
        print("将未拆包的数据传给run1")
        run1(args)  # ((2, 3),) 和 (2, 3)
        print("将拆包后的数据传给run1")
        run1(*args)  # (2, 3)和2 3
    
    def run1(*args):
         print("输出元组")
         print(args)
         print("对元组进行拆包")
         print(*args)
    
    run(1,2,3) #后面的2和3

    输出结果

    1
    (2, 3)
    对args拆包
    2 3
    将未拆包的数据传给run1
    输出元组
    ((2, 3),)
    对元组进行拆包
    (2, 3)
    将拆包后的数据传给run1
    输出元组
    (2, 3)
    对元组进行拆包
    2 3
    
    """
    理解这段代码需要把握住下面几点:
    1. 形参中的*args其实真正接收数据的args,它是一个元组,把传进来的数据放在了args这个元组中。
    2. 函数体里的args依然是那个元组,但是*args的含义就是把元组中的数据进行拆包,也就是把元组中的数据拆成单个数据。
    3. 对于args这个元组,如果不对其进行解包,就将其作为实参传给其它以*args作为形参的函数时,args这个元组会看看作一个整体,作为一个类型为元组的数据传入。
    
    """

    2. **kwargs

    def run(**kwargs):
        """
        传来的 key = value 类型的实参会映射成kwargs里面的键和值
        kwargs是一个字典,将关键字参数以键值对的形式
        """
        print(kwargs)  # {'a':1,'b':2}
        print("对kwargs拆包")
        #  此处可以把**kwargs理解成对字典进行了拆包,{"a":1,"b":2}的kwargs字典又
        # 被拆成了a=1,b=2传递给run1,但是**kwargs是不能像之前*args那样被打印出来看的
        run1(**kwargs)  # 1 2
        # print(**kwargs)
    
    
    def run1(a, b):  # 此处的参数名一定要和字典的键的名称一致
        print(a, b)
    
    run(a=1, b=2)
    d = {'a':1,'b':2}
    run(**d)  # 输出结果与执行run(a=1, b=2)一样

    输出结果

    {'a': 1, 'b': 2} #run(a=1,b=2)
    对kwargs拆包
    1 2
    {'a': 1, 'b': 2} #run(**d)
    对kwargs拆包
    1 2
    
    """
    def run(**kwargs):#传来的 key = value 类型的实参会映射成kwargs里面的键和值
    # kwargs是一个字典,将未命名参数以键值对的形式
    print(kwargs)
    print("对kwargs拆包")
    # 此处可以把**kwargs理解成对字典进行了拆包,{"a":1,"b":2}的kwargs字典又
    # 被拆成了a=1,b=2传递给run1,但是**kwargs是不能像之前*args那样被打印出来看的
    run1(**kwargs)
    #print(**kwargs)
    def run1(a,b): #此处的参数名一定要和字典的键的名称一致
    
    对于kwargs这个字典,如果不对其进行解包,就将其作为实参传给其它以**kwarg作为形参的函数时,kwarg这个字典会看看作一个整体,作为一个类型为字典的数据传入
    """

    总结:

    1. *args作为形参时是用来接收多余的位置参数,而**kwargs是用来接收key=value这种类型的关键字参数,args是元组,kwargs是字典。
    2. *和**在函数体中除了拆包之外,并没有什么卵用。
    3. 装包的含义就是把位置参数和关键字参数分别放在元组或者字典中。

    函数返回值

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

    1. 首先返回值可以是任意的数据类型。

    2..函数可以有返回值:如果有返回值,必须要用变量接收才有效果

       也可以没有返回值:

        1.当不写return的时候,函数的返回值为None

        2.当只写一个return的时候,函数的返回值为None

    3. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束

    def stu_register(name,age,course):
    
        print(name, age, course) # Peiqi 29 安保
    
        return [name, age] # 返回列表形式
    
    status = stu_register('Peiqi',29,'安保')
    print(status) # ['Peiqi', 29]
    
    
    def stu_register(name,age,course):
    
        print(name, age, course) # Peiqi 29 安保
    
    status = stu_register('Peiqi',29,'安保')
    print(status) # 无返回值时,返回None
    
    def stu_register(name,age,course):
    
        print(name, age, course) # Peiqi 29 安保
        return
        print(name, age) # 此句不会执行
    
    status = stu_register('Peiqi',29,'安保')
    print(status) # return后面没有值,返回None
  • 相关阅读:
    .NET面试题系列(五)数据结构(Array、List、Queue、Stack)及线程安全问题
    一个使用 Go 的思维来帮助您构建并开发 Go 应用程序的开源框架
    UML类图学习
    服务器防攻击手段
    .NET面试题系列(四)计算机硬件知识
    .NET面试题系列(三)排序算法
    ASP.NET MVC学习(五)之MVC原理解析
    socketWriter.go
    multiWriter.go
    timeCache.go
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/8574467.html
Copyright © 2011-2022 走看看