zoukankan      html  css  js  c++  java
  • python的函数

    一、函数介绍

    1、函数是什么?

    函数一词来源于数学,编程中的"函数"与数学中的函数有很大的不同。
      (BASIC中叫subroutine,C中叫function,java中叫method)

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

    2、为什么要使用函数?

    (1)减少重复代码:否则遇到重复的功能只能重复编写实现代码,代码冗余

    (2)使程序变得可扩展:否则功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大 

    (3)使得程序变得易维护:否则代码的组织结构不清晰,可读性差

    3、函数分类

    (1)内置函数:针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max()。

    (2)自定义函数:很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可

    二、函数的参数

      参数的作用:可以让函数更灵活,不只能做死动作,还可以根据调用时传参的不同来决定函数内部的执行流程。

    # 无参函数
    def sayhi(): # 函数名(小写即可)
        print("Hello,I'm nobody!")
    
    sayhi()   # 调用函数,函数名指向上述代码指向的内存位置,加上括号才是执行代码
    print(sayhi)   # 函数sayhi指向的内存地址
    
    # 单个参数的函数
    def sayhi(name):
        print("hello",name)
        print("my name is black girl....", name)
    sayhi("tracy")
    
    # 多个参数函数
    def calc(x,y):   # 定义算数函数
        res = x**y
        return res   # 返回函数执行结果
    a,b = 5,8
    c = calc(a,b)    # 结果赋值给变量c
    print(c)
    calc(2,10)       # 直接写入参数

    1、形参

      只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

    2、实参

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

    def calc(x,y):   # 形参
        res = x**y
        return res
    a,b = 3,5
    c = calc(a,b)    # 实参
    print(c)
    d = calc(2,3)    # 实参

    3、默认参数

    def stu_register(name,age,country,course):
        print("注册学生信息".center(50,'-'))
        print("姓名:",name)
        print("age:" ,age)
        print("国籍",country)
        print("课程",course)
    
    stu_register("山炮",22,"CN","python_devops")
    stu_register("丰收",23,"CN","linux")
    
    '''
        由于很多人国籍都是中国,可以将country设置为默认参数
        默认参数:
    '''
    def stu_register(name,age,course,country="CN"):  # 非默认参数不能跟在默认参数后面
        print("registration info".center(50,'-'))
        print(name,age,country,course)
    
    stu_register("jack",22,'c++')     # 实参和形参按顺序一一对应
    stu_register("rain",32,'dance','Korean')
    stu_register("Alfa",21,'python')

    4、关键字参数

      应用场景:正常情况下,给函数传参数要按顺序,不想按顺序可以用关键参数
      定义:指定了参数名的参数就叫关键参数
         关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后

    def stu_register(name,age,course,country='CN'):
        print("注册学生信息".center(50,'-'))
        print("姓名:",name)
        print("age:" ,age)
        print("国籍",country)
        print("课程",course)
    
    stu_register("绮珊",course='Python',age=22,country='JP')  # 后三个均为为关键参数置于name位置参数之后
    # stu_register("杉树",course='Python',22,country='JP')    # 22为位置参数不能放在关键参数course之后
    # stu_register("曼玉",22,age=25,country='JP')    # age获得多个赋

    5、非固定参数(动态参数)

      形式参数中出现*,传递的参数就可以不再是固定个数,会将传过来的所有参数打包为元组。

    def send_alert(msg,*users):
        for u in users:
            print('报警发送给',u)
    
    # 方式一:
    # 报警,十个运维人员
    send_alert('注意系统资源别浪了','Alex','jack','tracy','wood')
    
    
    # 方式二:
    # send_alert('注意内存紧张',['alex','jack','tracy','wood'])  # 传入的参数是数据
    send_alert('注意内存紧张',*['alex','jack','tracy','wood'])   # 传入的参数是数组内的元素
    # 传入的参数由(['alex','jack','tracy','wood']) ————>('alex','jack','tracy','wood')

      如果动态参数后还有参数

    # 方法一:
    def send_redalert(msg,*users,age):
        for u in users:
            print('CPU紧张',u)
    # send_redalert("alex","rain",22)   # 22也会传递给*users
    send_redalert("alex","rain",age=22)
    
    #  方法二:
    def func(name,*args,**kwargs):
        print(name,args,kwargs)
    
    func('Alex',22,'tesla','500w',addr='湖北',num=123332313)
    # Alex (22, 'tesla', '500w') {'addr': '湖北', 'num': 123332313}
    
    d = {'degree':'primary school'}
    func('Peiqi',**d)
    • *args代表位置参数,它会接收任意多个参数并把这些参数作为元组传递给函数。
    • **kwargs代表的关键字参数,允许你使用没有事先定义的参数名。
    • 位置参数一定要放在关键字参数的前面。

      优点:使用*args和**kwargs可以非常方便的定义函数,同时可以加强扩展性,以便日后的代码维护。 

    三、函数的返回值

      返回值:函数外部的代码要想获取函数的执行结果,可以在函数里用return语句把结果返回。
    注意:
      1、函数在执行过程中只要遇到return语句,就会停止执行并返回结果,可以理解return语句代表着函数的结束
      2、如果未在函数中指定return,那这个函数的返回值为None

    def stu_register(name,age,course='PY',country='CN'):
        print("注册学生信息".center(50,'-'))
        print("姓名:", name)
        print("age:", age)
        print("国籍", country)
        print("课程", course)
        if age > 22:
            return False
        else:
            return True
    
    registration_status = stu_register('阿斯顿',22,course="全栈开发",country='JP')
    
    if registration_status:
        print("注册成功".center(50,'-'))
    else:
        print("too old to be a student.")
    
    '''
        执行到return语句后,停止执行函数并返回结果
    '''
    def stu_register(name,age,course):
        print(name,age,course)
        #
        # if age > 22:
        #     return 'sdfsf'  # 返回值可以是任意值
        # else:
        #     return True
        #
        # return None      # 到return语句后,停止执行函数并返回结果
        # print('hahah')
        # return 1
        return [name,age]
    status = stu_register('Peiqi',29,'安保')
    print(status)

    四、全局和局部变量

    局部变量:函数内定义的变量,只能在局部生效
    全局变量:定义在函数外部一级代码的变量,整个程序可用(由上到下可用)
          在函数内部可以引用全局变量。
    变量查找顺序:如果全局和局部都有一个变量,函数查找变量的顺序是由内而外的。两个函数间互不可见

    name = "Black girl"       # 全局变量
    
    def change_name():
        # global name         # (不建议使用global)在函数内修改全局变量,不能放在函数内局部变量后面
        name = "黑色的姑娘"     # 局部变量
        print("",name,"里面...",id(name))
    
    change_name()
    print(name,id(name))   # 与函数内的变量内容完全不同
    '''
    输出结果:
        在 黑色的姑娘 里面... 4302993904
        Black girl 4316351984
    '''

      函数内可以修改字典、列表、集合、对象、类、元组内的列表

    names = ['Alex','Black Girl','Peiqi']
    def change_name():
        names = ['Alex']
        del names[2]      # names整体的内存地址不能修改只能引用,但其内部的元素是可以修改的
        names[1] = "黑姑娘"
        print(names)
    
    change_name()
    print(names)
    '''
    输出结果:
        ['Alex', '黑姑娘']
        ['Alex', '黑姑娘']
    '''
    • 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
    • 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数。
    • 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。

    五、作用域(scope)

      作用域定义:一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

    • python中一个函数就是一个作用域,局部变量放置在其作用域中
    • C# Java中作用域{}
    • 代码定义完成后,作用域已经完成,作用域链向上查找
    age = 18
    def func1():
        age = 73
        def func2():
            age = 84
            print(age)
    
        return 666
    
    val = func1()
    print(val)
    '''
    输出:666
    '''

    # 函数名可以当作返回值 age = 18 def func1(): age = 73 def func2():... return func2 # 返回一个函数名# val = func1() print(val) ''' 输出:<function func1.<locals>.func2 at 0x101462598> ''' # 代码写完之后作用域已经生成,不管函数名传到哪里,只要执行都回回定义的地方往上找 age = 18 def func1(): age = 73 def func2(): print(age) return func2 # 返回一个函数名不带括号 val = func1() val() ''' 输出结果:73 '''

    六、嵌套函数

      嵌套函数,就是指在某些情况下,您可能需要将某函数作为另一函数的参数使用。

    1、函数定义完成之后,没有通过名字调用,内部代码永远不会执行

    def func1():
        print('alex')
    
        def func2():
            print('eric')
    
    func1()
    '''
    输出:alex
    '''
    
    def func1():
        print('alex')
    
        def func2():
            print('eric')
    
        func2()
    
    func1()
    '''
    输出:
        alex
        eric
    '''

      总结:

    • 函数内部可以再次定义函数

    • 执行函数需要被调用

    2、嵌套函数寻找变量,优先自己函数,再找父级、爷爷级等,没有就找全局变量(一层一层往上找)

    age = 19
    def func1():
        age = 73
        print(age)   # 寻找变量,先找自己的函数内,没有就找全局变量(一层一层往上找)
        def func2():
            age = 84
            print(age)   # 寻找变量,优先自己函数、再找父级、爷爷级,最后找全局变量
        func2()
    func1()    # 输出:73  84
    
    # 测试二: age1 = 19 def func1(): age1 = 73 def func2(): print(age1) # 按顺序往上找,找到父级的age=73 func2() func1() # 输出:73

    3、局部变量位置调整

    age = 19
    def func1():
        def func2():
            print(age)
        age = 73
        func2()
    func1()
    """
    输出:
        73
    """
    
    age = 19
    def func1():
        def func2():
            print(age)
        func2()
        age = 73
    func1()
    '''
        执行报错:free variable 'age' referenced before assignment in enclosing scope
        73在func2后面,func2不知道该取哪个参数
    '''
    

      为了避免这种情况,声明变量尽量写在前面。

    4、全局变量设置

    age = 19
    def func1():
        global age   # 此时已经拿到age=19,age=73还没有执行
        def func2():
            print(age)
        func2()
        age = 73    # 此时修改全局age=73
    func1()
    print(age)
    """
    输出:
        19
        73
    """
    
    age = 19
    def func1():
        global age
        def func2():
            print(age)
        age = 73   # 将全局变量age改为73,再执行func2,函数没有在func2func1中找到age,继续到全局找age,但全局已经修改为73
        func2()
    func1()
    print(age)
    """
    输出:
        73
        73
    """
    

      第一个程序,在global age时,函数已经拿到age=19,但此时age=73还没有执行,此时执行func2函数,打印age=19。随后修改全局变量age=73,直接打印age,因此输出73.

      第二个程序,在global age时,函数拿到age=19,随后修改全局变量age=73,接着执行func2函数,打印age=73,打印此时的全局变量age,也同样输出73.

  • 相关阅读:
    FreeCommander 学习手册
    String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
    StringBuffer 详解 (String系列之3)
    StringBuilder 详解 (String系列之2)
    java io系列26之 RandomAccessFile
    java io系列25之 PrintWriter (字符打印输出流)
    java io系列24之 BufferedWriter(字符缓冲输出流)
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
  • 原文地址:https://www.cnblogs.com/xiugeng/p/8463305.html
Copyright © 2011-2022 走看看