zoukankan      html  css  js  c++  java
  • python学习7

    一、动态传参

    动态传参用到 *args 和 **kwargs ,*号表示接收位置参数,args是参数名;**表示接收关键字参数,kwargs是参数名

    复制代码
     1 def chi(*food):
     2     print(food)    #('胡辣汤', '油条', "豆浆")
     3     print(*food)   #'胡辣汤', '油条', "豆浆
     4 chi("胡辣汤","油条","豆浆")
     5 
     6 
     7 def chi(**food):
     8     print(food)   
     9 
    10 chi(food1="胡辣汤",food2 = "油条",food3="豆浆")
    11 #结果  {'food1': '胡辣汤', 'food2': '油条', 'food3': '豆浆'}
    复制代码

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

    无敌传参:可以接收任何参数

    1 #无敌传参示例
    2 def func(*args, **kwargs):   #可以是任何参数
    3        pass
    4 
    5 func("位置参数",kw ="关键字参数")

    注意:*号在形参位置表示聚合,在实参位置表示打散  ,字典打散用两个**

    复制代码
    def func(*args): #形参位置  聚合
        print(args)
    lst = [1,2,3]
    t = (22,33)
    func(*lst,*t)  #实参位置 将列表和元组打散了
    #结果  (1, 2, 3, 22, 33)
    
    def fun(**kwargs):  #形参位置,聚合
         print(kwargs)
    
    dic1 = {"name":"alex","gender":"男"}
    dic2 = {"age":"1000"}
    fun(**dic1,**dic2)    #实参位置, 字典打散
    # 结果 {'name': 'alex', 'gender': '男', 'age': '1000'}
    
    dic1 = {"name":"alex","age":"30"}
    dic2 = {"age":"1000"}
    fun(**dic1,**dic2)  #这是会报错,因为两个字典中有重复的key,一个key对应多个值
    复制代码

    二、命名空间和作用域

    在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来,

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

    分为内置命名空间、全局命名空间、局部命名空间

    内置空间存储python解释器内置的东西,全局空间放py文件中函数外声明的变量,局部空间放函数内声明的变量

    顺序:

    文件加载时

      先加载内置空间,再全局,最后局部(函数调用时才用到)

    在取值的时

    先从局部空间找,然后是全局空间,最后是内置空间

    作用域

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

    全局作用域: 内置空间+全局空间的变量

    局部作用域:局部空间的变量

    查看作用域:

      globals()  查看全局作用域中的变量名字

      locals() 查看当前作用域中的变量名字  (可以用在全局也可以用在局部)

    三、函数的嵌套

    1. 注意函数的执行顺序

    2. 只要遇到了()就是函数的调用. 如果没有()就不是函数的调用

    四、golbal和nonlocal关键字

    golbal关键字  表示引入全局变量 arg,如果全局变量中没有arg就在局部声明这个变量为全局变量

    nonlocal关键字  表示在局部 引入上一层空间的变量,如果上一层没有继续找上一层,都没有时报错。

    a = 100
    def func():
    print(a) # 取值时可以取全局变量,逐层往上找
    func()

    def func():
    a = 28 # 想要修改时会报错,局部空间不能直接修改全局变量
    print(a)
    func()
    --------------
    a = 100
    def func():
    global a # 加了个global表示不在局部创建这个变量了. 而是直接使用全局的a
    print(a) #100
    a = 28 #这时就能在局部空间修改全局变量了
    print(a) #28
    func()
    print(a) #28

    golbal

    a = 10
    def func1():
    a = 20
    def func2():
    nonlocal a #找上一层的a a = 20
    a = 30 #将a =20 修改为 a =30
    print(a) #30
    func2()
    print(a) #10
    func1()

    nonlocal

    函数默认参数的初始化问题

    函数的默认参数使得函数的调用变得简单。实际上,默认参数的值只在定义时计算一次,因此每次使用默认参数调用函数时,得到的默认参数值是相同的。我们看一个例子。

    复制代码
    import datetime as dt
    from time import sleep
    
    def log_time(msg,time = dt.datetime.now()):
        sleep(1)
        print("%s:%s"%(time.isoformat(),msg))
    
    log_time("msg 1")
    log_time("msg 2")
    log_time("msg 3")
    复制代码

    结果:

    三次调用函数得到的默认值是一模一样,而且中间让程序睡眠了1秒,可以排除是程序运行太快的因素,因此这足以说明函数的默认值只在定义的时候计算了一次,以后每次调用用到默认值时都是用的定义时计算的值。

    可变参数与不可变参数

    当默认参数是可变参数时:

    复制代码
    1 def bad_append(new_item,a_list =[]):   #列表是可变数据类型
    2     print("address of a_list:",id(a_list))
    3     a_list.append(new_item)
    4     return a_list
    5 
    6 print(bad_append("1"))  # ["1"]
    7 print(bad_append("2"))   # ["1","2"]
    复制代码

    我们期待结果是["1"] 和 ["2"],但实际是["1"]和["1","2"],这是因为,函数参数只在定义的时候计算一次,在定义时参数a_list的内存你地址已经分配好了,由于列表是可变数据类型,改变数据不会重新创建对象,也就没有内存地址的重新分配,所以在以后调用时,只要不给默认参数重新赋值,它的内存地址都不会改变。两次调用用的是同一个内存地址,操作的是同一个列表。

    当参数时不可变数据类型时:

    复制代码
    def immutable_test(i =1):
        print("befor,adress of i",id(i))  
        i += 1
        print("after,address of i",id(i))  
        return i
    
    print(immutable_test())  
    print(immutable_test())
    复制代码

    结果:

    很明显第二次调用没有受第一次调用的影响,因为 i 是不可变数据类型,对它的操作会使内存重新分配,重新创建一个对象。那么函数中i += 1之后名字i指向了另外的地址;根据默认参数的规则,下次调用时,i指向的地址还是函数定义时赋予的地址,这个地址的值1并没有被改变。

    结论:

    默认参数为不可变数据类型时,多次调用不会造成任何影响;为可变数据类型时,多次调用的结果不符合预期。

    因此,在将可变数据类型作为默认参数时,就不能只在函数定义时初始化一次,而应该在每次调用时初始化。

    最佳实践是定义函数时指定可变默认参数的值为None,在函数体内部重新绑定默认参数的值。以下是对上面的两个可变默认参数示例最佳实践的应用:

    def good_append(new_item,a_list = None):
    if a_list is None:
    a_list = []
    a_list.append(new_item)
    return a_list

    print(good_append("1")) #['1']
    print(good_append("2")) #['2']
    print(good_append("c",["a","b"])) #['a', 'b', 'c']

    def log_time(msg,time = None):
    if time is None:
    time = dt.datetime.now()
    sleep(1)
    print("%s:%s"%(time.isoformat(),msg))

    log_time("msg1") #2018-10-31T19:44:34.117109:msg1
    log_time("msg2") #2018-10-31T19:44:35.117166:msg2

    最佳实践

  • 相关阅读:
    mysql 中表和数据库名称不要使用 '-' 命名
    htmlElement.style 是只读属性
    chrome 远程调试相关问题
    纯小白入手 vue3.0 CLI
    纯小白入手 vue3.0 CLI
    纯小白入手 vue3.0 CLI
    《前端之路》- TypeScript (四) class 中各类属性、方法,抽象类、多态
    《前端之路》- TypeScript (三) ES5 中实现继承、类以及原理
    《前端之路》- TypeScript(二) 函数篇
    《前端之路》--- 重温 Egg.js
  • 原文地址:https://www.cnblogs.com/wuyufeng-9-14/p/10172625.html
Copyright © 2011-2022 走看看