zoukankan      html  css  js  c++  java
  • 10. 前方高能-函数的进阶

    本节主要内容:

    1.函数参数—动态传参

    2.名称空间,局部名称空间,全局名称空间,作用域,加载顺序

    3.函数的嵌套

    4.gloabal,nonlocal关键字

    一.函数参数—动态传参

    之前我们说过了传参,如果我们需要一个函数传参,而参数又不确实的,或者我给一个函数传很多参数,我的形参就要写很多,很麻烦,那怎么办呢,我们可以考虑使用动态参数。

    形参的第三种:动态参数

    动态参数分为两种:

    1.动态接受为止参数

    首先我们先回顾一下为止参数,位置参数,按照位置进行传参

    def chi(quality_food,junk_food):
        print("我要吃",quality_food,junk_food)
    chi("大米饭","小米饭")  #“大米饭”传递给quality_food "小米饭"传递给junk_food按照位置传

    现在问题来了,我想吃任意食物,数量是任意的,食物也是任意的,这时我们就要用到动态参数了。

    在参数位置编写*表示接收任意内容

    def chi(*food):
        print("我要吃",food)
    chi("大米饭","小米饭")
    结果:
    我要吃("大米饭""小米饭"#多个参数传递进去,收到的内容是元祖tuple

    动态接受参数的时候要注意:动态参数必须在位置参数后面

    def chi(*food, a, b):
     print("我要吃", food, a, b)
    chi("大米饭", "小米饭", "黄瓜", "茄子")

    这时候程序会报错,因为前面传递进去的所有位置参数都被*food接受了,a和b永远接受不到参数

    Traceback (most recent call last):
     File "/Users/sylar/PycharmProjects/oldboy/fun.py", line 95, in <module>
     chi("大米饭", "小米饭", "黄瓜", "茄子")
    TypeError: chi() missing 2 required keyword-only arguments: 'a' and 'b'

    所以必须修改成下面代码:

    def chi(*food,a,b):
        print("我要吃",food,a,b)
    chi("大米饭","小米饭",a="黄瓜",b="茄子")#必须用关键字参数来指定

    这时候a和b就有值了,但是这样写呢位置参数就不能用了,所以,我们要先写位置参数,然后再用动态参数

    def chi(a,b,*food):
        print("我要吃",a,b,food)
    chi("大米饭","小米饭","馒头","面条") #前面两个参数用位置参数来接受,后面的参数用动态参数接受

    那默认值参数呢?

    def chi(a,b,c="馒头",*food):
        print(a,b,c,food)
    chi("香蕉","菠萝") #香蕉 菠萝 馒头 ()默认值生效
    chi("香蕉","菠萝","葫芦娃") #香蕉 菠萝 葫芦娃() 默认值不生效
    chi("香蕉","菠萝","葫芦娃","口罩") #香蕉 菠萝 葫芦娃("口罩",)默认值不生效

    我们发现默认值参数写在动态参数前面,默认值只有一种情况可能会生效。

    def chi(a,b,*food,c="娃哈哈"):
        print(a,b,food,c)
    chi("香蕉","菠萝")  #香蕉 菠萝 ()娃哈哈 默认值生效
    chi("香蕉","菠萝","葫芦娃") #香蕉 菠萝 ("葫芦娃",) 娃哈哈 默认值生效
    chi("香蕉","菠萝","葫芦娃","口罩") #香蕉 菠萝 ("葫芦娃","口罩")娃哈哈  默认值生效

    这时候我们发现所有的默认值都生效了,这时候如果不给出关键字传参,那么你的默认值是永远都生效的。

    顺序:位置参数,*动态参数,默认值参数 ,**kwargs

    顺序: 位置参数  *args  默认值参数 **kwargs

    2.动态接收关键字参数

    在python中可以动态的位置参数,但是*args这种情况只能接收位置参数无法接受关键字参数。

    在python中使用**kwargs来接收动态关键字参数

    def func(**kwargs):
        print(kwargs)
    func(a=1,b=2,c=3)
    func(a=1,b=2)
    结果:
    {'a': 1, 'b': 2, 'c': 3}
    {'a': 1, 'b': 2}

    这个时候接收的是一个dict字典

    顺序的问题,在函数调用的时候,如果先给出关键字参数,则整个参数列表会报错。

    def func(a, b, c, d):
     print(a, b, c, d)
    # 关键字参数必须在位置参数后面, 否则参数会混乱
    func(1, 2, c=3, 4)

    最终顺序(*)

    位置参数>*args>默认值参数>**kwargs

    这四种参数可以任意的进行使用。

    如果想要接收所有的参数:

    def func(*args,**kwargs):
        print(args,kwargs)
    func("麻花藤","马云",wtf="胡辣汤")

    动态参数的另一种传参方式:

    def fun(*args):
        print(args)
    lst = [1,4,7]
    fun(lst[0],lst[1],lst[2])
    fun(*lst)  #可以使用*把一个列表顺序打散
    s="成妾做不到"
    fun(*s)   #字符串也可以打散,(可迭代对象)

    在实参位置上给一个系列,列表,可迭代对象前面加个*表示把这个序列按顺序打散。

    在形参的位置上的*表示把接收到的参数组合成一个元祖

    如果是一个字典,那么也可以打散,不过需要两个*

    def fun(**kwargs):
        print(kwargs)
    dic= {"a":1,"b":2}
    fun(**dic)

    函数的注释:

    def chi(food,drink):
        """
        这里是函数的注释,先写一下当前这个函数是干什么的,比如我这个函数就是一个吃
        :param food:   参数food是什么意思
        :param drink:   参数drink是什么意思
        :return:   返回的是什么东东
        """
        print(food,drink)
        return "very good"

    二.命名空间

    在python解释器开始执行之后,就会在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间的关系记录下来,但是当遇到函数定义的时候,解释器只是把函数名读入内存,表示这个函数存在了,至于函数内部的变量和逻辑,解释器是不关系的,也就是说一开始的时候函数只是加载进来,仅此而已,只有当函数被调用和访问的时候,解释器才会根据函数内部声明的变量 来进行开辟变量的内部空间,随着函数执行完毕,这些函数内部变量占用的空间也会随着函数执行完毕而被清空。

    def fun():
        a =10
        print(a)
    fun()
    print(a)   #a不存在了已经

    我们给存放名字和值的关系的空间起了一个名字:命名空间,我们的变量在存储的时候就是存储在这片空间中的。

    命名空间的分类:

    1.全局命名空间-->我们之间在py文件中的,函数外声明的变量都属于全局命名空间

    2.局部命名空间-->在函数中声明的变量会放在局部命名空间

    3.内置命名空间 -->存放python解释器为我们提供名字list,tuple,str,int这些都是内置命名空间

    加载顺序:

    1.内置命名空间

    2.全局命名空间

    3.局部命名空间(函数执行的时候)

    取值顺序

    1.局部命名空间

    2.全局命名空间

    3.内置命名空间

    a = 10
    def dunc():
        a = 20
        print(a)
    dunc()  #20

    作用域:作用域就是作用范围,按照生效范围来看分为全局作用域和局部作用域

    全局作用域:包含内置命名空间和全局命名空间,在整个文件的任何位置都可以使用(遵循从上到下逐行执行).局部作用域:在函数内部可以使用。

    作用域名空间:

    1.全局作用域:全局命名空间+内置命名空间

    2.局部作用域:局部命名空间

    我们可以通过globals()函数来查看全局作用域的内容,也可以通过locals()来查看局部作用域中的变量和函数信息

    a = 10
    def func():
        a = 40
        b = 20
        def abc():
            print("哈哈")
        print(a,b)    # 这里是有的局部作用域
        print(globals())  #打印全局作用域中的内容
        print(locals())   #打印局部作用域中的内容
    func()

    三.函数的嵌套

    1.只哎哟遇见了()就是函数的调用,如果没有()就不是函数的调用

    2.函数的执行顺序

    def fun1():
        print(111)
    def fun2():
        print(222)
        fun1()
    fun2()
    print(111)
    #函数的嵌套
    def fun2():
        print(222)
        def fun3():
            print(666)
        print(444)
        fun3()
        print(888)
    print(33)
    fun2()
    print(555)    

    四.关键字global 和nonlocal

    首先我们写这样一个代码,首先在全局声明一个变量,然后在局部调用这个变量,并改变这个变量的值

    # a = 10
    # def func():
    #     global a # 这里用的a是全局的
    #     a = 20
    #     print(a)
    # func()
    # print(a)    # 20  20
    
    
    
    # a = 100
    # def func():
    #     global a  #加了个global 表示不再局部创建这个变量,而是直接使用全局的a
    #     a = 28
    #     print(a)
    # func()
    # print(a)  #  28  28 

    global 表示,不再使用局部作用域中的内容,而改变全局作用域中的变量

    lst = ["麻花藤","刘嘉玲","詹姆斯"]
    def func():
        lst.append("马云云")   # 对于可变数据类型可以直接进行访问,但是不能改地址,说白了,不能赋值
        print(lst)
    func()
    print(lst)

    nonlocal 表示在局部作用中,调用父级命名空间中的变量

    a = 10
    def func1():
        a = 20
        def func2():
            nonlocal a
            a = 30
            print(a)
        func2()
        print(a)
    func1()
    
    结果:
    加了nonlocal
    30
    30
    不加nonlocal
    30
    20

    再看,如果嵌套了很多层,会是一种什么效果:

    a = 1
    def fun_1():
        a = 2
        def fun_2():
            nonlocal a
            a = 3
            def fun_3():
                a = 4
                print(a)
            print(a)
            fun_3()
            print(a)
        print(a)
        fun_2()
        print(a)
    print(a)
    fun_1()
    print(a)
    结果:
    1
    2
    3
    4
    3
    3
    1

    这样的程序如果能分析明白,那么作用域,global ,nonlocal 就没问题了

  • 相关阅读:
    js动态生成表格
    Android Studio使用小技巧:提取方法代码片段
    Android适配底部虚拟按键的方法
    Eclipse注释模板
    android7.0关于TelephonyManager.getDeviceId()返回null的问题
    在fragment中实现返回键单击提醒 双击退出
    android使用友盟实现第三方登录、分享以及微信回调无反应问题解决办法
    【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)
    WebView使用详解(二)——WebViewClient与常用事件监听
    android正则表达式隐藏邮箱地址中间字符
  • 原文地址:https://www.cnblogs.com/zhaoyang110/p/9173783.html
Copyright © 2011-2022 走看看