Python之函数、参数解构、返回值和作用域

九:函数、参数及参数解构、返回值、作用域

知识前导总结:

  1. 内置函数callable():判断某个对象是否可调用!

总结:

  1. 混合使用参数时,可变参数要放到参数列表的最后,普通参数需要放到参数列表前面,位置可变参数需要在关键字可变参数之前
  2. 参数列表参数一般顺序是:
    普通参数–>缺省参数–>可变位置参数–>keyword-only参数–>可变关键字参数
    add(3, y=4)#正确
    add(y=4, 3)#错误
    def add(username, *args, **kwargs)#正确
    def add(passwd, username='tom', *args)#正确
    def add(username, **kwargs, *args)#错误
    def add(name='tom', passwd)#错误
  1. 参数解构:给函数提供实参的时候,可以在集合类型前使用或者*,把集合类型的结构解开,提取出所有元素作为函数的实参

1,函数:

Python函数:

  1. 由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元
  2. 组织代码完成复杂任务

函数的作用:

  1. 结构化编程对代码的最基本的封装,一般按照功能组织一段代码
  2. 封装的目的为了复用,减少冗余代码,让代码可读易懂

函数的分类:

内建函数:如max()、reversed()等
库函数:如math.ceil()

    函数的定义和调用:
        格式:
            def 函数名(形参列表):
                函数体
                [return 返回值]
        1,函数名就是标识符
        2,语句块必须缩进,约定4个空格
        3,Python的函数没有给return语句时,隐式返回一个None值
        4,定义中的参数列表称为形式参数,只是一种符号表达,简称形参

        函数调用:
            1,函数定义,只是声明了一个函数,它不会自动执行,需要调用
            2,调用的方式,就是函数名加上小括号,括号内给出参数
            3,调用时写的参数是实际参数,简称实参
        例如:
            def add(x, y):
                result = x + y
                return result
            调用函数
            print(add(4, 5))
    函数参数:
        1,参数调用时传入的参数要和定义的个数相匹配(可变参数例外)
        重点:
            1,实参:位置参数必须在关键字参数之前传入,且位置参数是按位置对应的
                不能给同一个形参传入2次的实参!
                add(x=3,4)#错误
                add(4, x=4)#正确
            2,形参:
        位置参数:
            def add(x, y)调用时使用:add(4, 5)
            1,位置参数必须要给出相同的个数,即定义多少个形参,就必须给出多少个实参
            2,传参的同时,是按照定义的顺序传入的
        关键字参数:
            def add(x, y)调用时使用:add(x=4, y=5)
            1,如果使用了形参名字,传参顺序就可以和定义的顺序不一致
        参数默认值:
            def add(x, y=5)调用时使用:add(4);x必须给出实参,y可以不给
            1,参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值
            2,参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用

    可变参数:一个形参可以匹配任意个参数
        位置可变参数:
            def add(*nums)调用时使用:add(4, 6, 9)
            1,在形参前使用*号表示该形参是可变参数,可以接收多个实参
            2,收集多个实参封装为一个tuple
        关键字可变参数:
            def showconfig(**kwargs)调用时使用:showconfig(a=1, b=2)
            1,形参前使用**两个星号,表示可以接收多个关键字参数
            2,收集的实参名称和值封装成一个字典
    可变参数混合使用:
        def add(username, *args, **kwargs):

    keyword-only参数:
        Python3加入了keyword-only参数!
        介绍:如果在一个星号参数后,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通的参数了,而是keword-only参数!
        例如:
            def add(*, x, y):
            def add(*args, x, y):
        重点:*之后的普通形参都变成了必须给出的keyword-only参数

            def add(**kwargs, x, y)#错误
            解释:因为无论如何给出x和y等于几,函数不知道应该给谁!

2,参数解构:

  1. 给函数提供实参的时候,可以在集合类型前使用或者*,把集合类型的结构解开,提取出所有元素作为函数的实参
  2. 非字典类型使用*解构成位置参数
  3. 字典类型使用**解构成关键字参数
  4. 提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配
例如:
    def add(x, y):
        return x + y
    调用:
        add(*(4, 5))#解构元组
        add(*[4, 5])#解构列表
        add(*{4, 5})#解构集合
        add(**{'x':5, 'y':6})#按照字典的key对应形参的x,y
        add(**{'a':5, 'b':6})#错误,因为形参里面没有a,b

3,函数返回值:

  1. Python函数使用return语句返回”返回值”
  2. 所有函数都有返回值,如果没有给出return语句,默认隐式调用return None
  3. return语句并不一定是函数的语句块的最后一条语句
  4. 一个函数可以存在多个return语句,但是只有一条可以被执行
  5. 如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其它语句就不会被执行了
  6. 作用:结束函数调用、返回值
例如:
def add(x):
    print(x)
    return x+1
    print(x + 1)#不会被执行,因为return语句结束了整个函数

返回值:
    def showlist():
        return [1, 3, 5]
    def showpage():
        return 1, 3, 5
    1,函数不能同时返回多个值
    2,上面showlist函数中,return返回一个列表,是一个列表对象!
    3,上面shopage函数中,return看似返回多个值,隐式的被Python封装成了一个元组对象

4,函数作用域:

def outer():
    def inner():
        print('inner')
    print('outer')
    inner()

重点:

内部函数不能被外部直接使用,否则会抛NameError异常!

global:

  1. 使用global关键字定义变量,将函数内的变量声明为使用外部的全局作用域中定义的变量

global使用原则:

  1. 外部作用域变量让内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离
  2. 如果函数需要使用外部全局变量,请使用函数的形参传参解决
  3. 不用global

闭包:

自由变量:

  1. 未在本地作用域中定义的变量

闭包:

  1. 内层函数引用到了外层函数的自由变量,就形成了闭包!

nonlocal关键字:

  1. 使用nonlocal关键字,将变量标记为不在本地作用域定义,而在上级的某一级局部作用域中定义,但不能是全局作用域中定义!
默认值的作用域:
    def foo(x=[]):
        x.append(1)
        print(x)
    foo()#[1]
    foo()#[1, 1]

重点:

  1. 函数也是对象,Python把函数的默认值放在了属性中,这个属性就伴随着这个函数对象的整个生命周期
  2. 查看函数的属性,foo.defaults属性

默认值的作用域总结:

  1. 使用可变类类型作为默认值,就可能修改这个默认值

两种使用方法:

  1. 使用影子拷贝创建一个新的对象,永远不能改变传入的参数

  2. 通过值的判断灵活的选择创建或修改传入对象,判断对象是否是None

全局作用域:
    1,在整个程序运行环境中都可见
局部作用域:
    1,在函数、类等内部可见
    2,局部变量使用范围不能超过其所在的局部作用域

重点Python LEGB规则作用域总结:

1,命名空间:

重点内容:命名空间是对变量名的分组划分!

解释:不同组的相同名称的变量视为两个独立的变量,因此隶属于不同分组(即命名空间)的变量可以重复、同名

2,变量名是内存地址的别名,但是由于Python一切皆对象,所以在Python中变量名是字符串对象。

a = 10
表示建立字符串对象a于number对象10之间的对应关系。由于这是一种映射,所以,可以使用键-值的形式来表示,即{name:object}
Python的命名空间是一个字典,字典内保存了变量名称与对象之间的映射关系!

LEGB含义解释:
    L-Local(funciton):函数内的名字空间
    E-Enclosing funciton locals:外部嵌套函数的名字空间
    G-Global(module):函数定义所在模块(文件)的名字空间
    B-Builtin(Python):Python内置模块的名字空间
LEGB规定了查找一个名称的顺序为:Local-->Enclosing funciton locals -->Global --> Builtin

global 和 nonlocal 详解:

global 关键字用来在函数或其他局部作用域中使用全局变量
    重点:如果不修改全局变量也可以不使用global
    1,声明全局变量,如果在局部要对全局变量修改,需要在局部也要声明该去全局变量
nonlocal 关键字用来在函数或其他作用域中使用 (外层)非全局变量。
    重点:nonlocal 适用于在局部函数中的局部函数,把最内层的局部变量设置成外层局部可用,但不是全局的!

作用域程序解析:

def scope_test():
    def do_local():
        spam = 'local spam'#此函数定义了另一个spam,并且声明周期只在此函数内

    def do_nonlocal():
        nonlocal spam#把此函数内定义的spam声明为上层函数的
        spam = 'nonlocal spam'

    def do_global():
        global spam#把此函数内定义的spam声明为全局的
        spam = 'global spam'
    spam = 'test spam'

    do_local()
    print(spam)

    do_nonlocal()
    print(spam)

    do_global()
    print(spam)
scope_test()
print(spam)

5,递归函数:

  1. 函数直接或间接调用自身就是递归
  2. 递归需要有边界条件、递归前进段、递归返回段
  3. 递归一定要有边界条件,当边界条件不满足的时候,递归前进,条件满足,递归返回

递归函数定义:

def recursion():
    return recursion()

递归函数通常包含两部分:

  1. 基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值!
  2. 递归条件:包含一个或多个调用,这些调用旨在解决问题的一部分!

重点:每次调用函数时,都将为此创建一个新的命名空间,用来存放变量和对象!意味着函数调用自身时,是两个不同的函数在交流(不同命名空间的同一个函数)

例如:求阶乘
思路:
    11的阶乘是1
    2,对于大于1的数字n,其阶乘为n-1的阶乘在乘以n
def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n - 1)

6,匿名函数、高阶函数:

lambda表达式:

  1. 参数列表不需要小括号
  2. 冒号用来分割参数列表和表达式
  3. 不需要使用return,表达式的值就是匿名函数返回值
  4. lambda表达式只能写在一行上
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页