Python笔记 Day7

一、动态参数

    当我们有很多参数时,一个一个的去写形参,很感觉很麻烦,哪有什么简便的万能形参吗?答案是有的,那就是我们的动态参数!!!

    昨天我们站在形参的角度可以把参数分为:位置参数和默认参数,今天我们将学习第三种:动态参数

   1、动态接受位置参数

      首先我们回顾一下位置参数,位置参数,按照位置进行传参(一定要注意实参与形参一一对应)

def chi(quality_food, junk_food):    
    print("我要吃", quality_food, junk_food) 

chi("⼤⽶饭", "⼩米饭")    # "⼤米饭"传递给quality_food   "小米饭"传递给junk_food 按照位置传

现在问题来了. 我想吃任意的食物. 数量是任意的, 食物也是任意的. 这时我们就要用到 动态参数了. 在参数位置编写*表示接收任意内容 

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


需要注意的是这里将说有的位置参数打包成一个人元组赋值给food,所以打印food得到一个元组 动态接收参数的时候要注意: 动态参数必须在位置参数后面 def chi(*food, a, b): print("我要吃", food, a, b) chi("⼤米饭", "⼩米饭", "⻩瓜", "茄⼦") # 这里是要报错的,因为动态参数将所有位置参数接受完了 报错代码: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'

    1.2、默认参数,运用关键字参数给出形参,当需要调用修改时才去修改      

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("⾹蕉", "菠萝", "葫芦娃", "口罩")    # ⾹蕉 菠萝  ('葫芦娃', '口罩')  娃哈哈  默 认值⽣效

   2、动态接收关键字参数:

     在python中可以动态的位置参数, 但是*这种情况只能接收位置参数⽆法接收关键字参数.在python中使⽤用**来接收动态关键字参数

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},将传入的数据转换为字典



需要注意顺序的是:如果先给出关键字参数,则整个参数列表会报错
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="胡辣汤")

  2.1、动态参数的另一种传参方式(聚合与打散)

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} 
dic_ = {'g':1,'c':3}
fun(**dic,**dic_)      # 结果{'a': 1, 'b': 2, 'g': 1, 'c': 3},就是把传入的打散 ,实参上打散,把外皮剥了

  3、函数的注释:(对函数的功能注释)

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

二、命名空间

   1、在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. 内置命名空间

  

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

      全局作⽤域: 包含内置命名空间和全局命名空间. 在整个⽂件的任何位置都可以使用(遵循 从上到下逐⾏执⾏).

    局部作⽤域: 在函数内部可以使⽤.             

    作⽤域命名空间:

                   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 = 100 
def func():
    global a    # 加了个global表示不再局部创建这个变量了. ⽽是直接使⽤全局的a        
    a = 28
    print(a)      #z注意再次调用的是全局的a,修改时同步到的

func() 
print(a)        # 28



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():
        global 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,2,3



再看看nonlocal的代码:
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

    

  

猜你喜欢

转载自www.cnblogs.com/double-W/p/9452598.html