zoukankan      html  css  js  c++  java
  • [学习总结] python语言学习总结 (二)

    1.python中的拆包

    之前就只写了*可以是未知数量的参数,**可以传入未知数量命名参数。这次详细记下拆包。

    def f1(a, *l):
        print(a)
        # 不拆包
        print(l)
        # 拆包
        print(*l)
        f2(l)
        f2(*l)
    
    
    def f2(*l):
        print(l)
        print(*l)
    
    
    def f3(**kw):
        # 不拆包
        print(kw)
        # 得到键名
        print(*kw)
        # 拆包,键名对应
        f4(**kw)
        # 注意,python中没办法输出**kw,不信可以自己试试。。
    
    
    def f4(a, b):
        print(a, b)
    
    
    f3(a=1, b=2)
    
    
    f1(1, 2, 3)
    
    '''
    {'a': 1, 'b': 2}
    a b
    1 2
    1
    (2, 3)
    2 3
    ((2, 3),)
    (2, 3)
    (2, 3)
    2 3
    '''

    我试图通过这段代码的运行情况搞清楚拆包,实际上结果也特别明显。

    其实python给f1和f2函数传入的参数是个元组,也就是形式参数被转换为元组传入了f1和f2中作为实参,这应该是函数给我们做的装包工作,这个工作对我们在函数里操作是很方便的,而从未拆包和拆包的f2的输出来看,我们的理解是正确的。

    同样的,**kw传入的参数其实是个字典,传入之后会隐式地进行装包工作,也就是将a=1,b=2装包成{'a':1,'b':2}的字典,这样方便了我们在函数中提取相应参数,我觉得还是很有用的。需要注意的是,我们无法通过print(**kw)得到a=1,b=2的输出结果,因为print函数貌似不支持这种输出,可以自己尝试下。而从f4的输出看出,我们的理解是正确的。

    因此,我们可以在以下场景用到拆包操作。

    1.我们有一个元组,想把这个元组的数据分别作为参数传入。其实就是上面f2函数实现的。

    2.我们有一个字典,想把这个字典的数据分别作为参数传入。其实就是上面f4函数实现的。

    2.python中的切片

    说实在话,切片用到的次数非常多,因为经常操作字符串、list和numpy,所以这个东西用到的次数非常多。

    以一个简单的字符串为例

    str = "abcdefg"
    
    
    print(str[0:2:1], str[0:2:-1], str[:], str[::-1], str[::-2])
    
    
    '''
    ab  abcdefg gfedcba geca
    '''

    切片最常用的是一个左右中括号的操作;通过指定的下标来访问一组序列的元素,其实就切片操作。

    中括号中我们可以指定三个参数,其中第一个参数代表要取的序列的起始index,我们选0,就是从最开始选,第二个参数是结束index,但是不包含这个index对应的数据,从以上输出中我们是可以看出来的,第三个参数是步长,步长为1,那么他就从左往右一个一个取;步长为-1,那么他就从右往左一个一个取,步长为负就是反方向取,因此我们可以填-2,那么他就从右往左以两个步长取元素。

    其中呢,后面的冒号是可以省略的,也就是可以不填步长,默认就是1,只有一个冒号而不填任何参数就是复制这个序列,而前两个参数空,只把步长设为1其实就是倒置这个序列。

    3.python中的名称空间

    python中的名称空间我觉得还是要搞清楚的,这样对理解python这门语言还是很有帮助的。
    名称空间(namespace):名称空间是名字和对象的映射。也就是可以把一个namespace理解为一个字典,实际上很多当前的Python实现namespace就是用的字典。各个名称空间是独立的,没有任何关系的,所以一个名称空间中不能有重名,但不同的名称空间是可以重名而没有任何影响。


    Build-in
    ....Global
    ........Enclosed
    ............Local

    可见确实是个层级关系。
    我们来分别解释这四个名称空间,
    Build-in:python解释器启动产生的字典,用于存放python内置的名字。
    Global:执行python文件时,存放文件级定义的名字,就是被import的时候创建,在解释器退出的时候才被删除。
    Enclosed:指的是一个函数被另一个函数包含时的命名空间。
    Local:执行文件过程中,调用函数时产生的名称空间,用来存放函数内定义的名字,由于生命周期的原因,函数调用结束后该名字会被删除。

    Python在查找变量时候按照从内至外的顺序查找变量,可以说成是LEGBD顺序。
    作用域(scope):作用域是Python程序(文本)的某一段或某些段,在这些地方,某个命名空间中的名字可以被直接引用。这个作用域就是这个命名空间的作用域。

    下面用代码来理解一下作用域。

    from copy import copy
    a = 5
    print("***build-in and globals***")
    #  print(type(list(globals().keys())))
    globals_init = copy(list(globals().keys()))
    print("
    ".join(globals_init))  # 输出的是build-in的命名空间下的名字key
    
    
    def f1(b=3):
        c = 4
        print("***globals in f1***", *(globals().keys() - globals_init), sep="
    ")
        #  解释下这里,globals().keys()返回的是list,list相减得到的是set,然后对set解包就可以输出了,也可以把set转化为list用.join输出
        print("***locals in f1***", *(locals().keys()), sep="
    ")
        
        
        def f2():
            c = 5
            print("***locals in f2***", *(locals().keys()), sep="
    ")
        print("c=", c)
        f2()
        print("c=", c)
    
    
        def f3():
            nonlocal c
            c = 6
            print("***locals in f3***", *(locals().keys()), sep="
    ")
        print("c=", c)
        f3()
        print("c=", c)
    
    
    f1()
    
    '''
    ***build-in and globals***
    __name__
    __doc__
    __package__
    __loader__
    __spec__
    __annotations__
    __builtins__
    __file__
    __cached__
    copy
    a
    ***globals in f1***
    globals_init
    f1
    ***locals in f1***
    b
    c
    c= 4
    locals in f2
    c
    c= 4
    c= 4
    locals in f3
    c
    c= 6
    '''

    咱们从这里可以看出,不同作用域对应的名称是相互独立的,在函数内如果和函数外有相同的变量名称,会默认把近的那个作为要找到的变量,如果要访问函数外的比如a怎么办呢,很简单,函数里面写上global a 即可,否则你的操作就相当于在函数内的local里建立了一个新变量。函数嵌套的时候使用nonlocal去操作被套函数外的local变量,甚至也可以通过global操作全局变量。上面的例子仔细看看应该是理解了。

    4.python中的一些高阶函数总结

    分别是map、filter、reduce、sorted。其中sorted函数之前已经写过了,但是当时没有用到参数key,这次查了一下,发现key就是自定义排序规则,比如我们让key=abs,那么就会按照绝对值大小排序,当然我们也可以自定义函数,我这里用lambda定义了匿名函数来对x平方大小排序,然后映射回原list。map函数通过建立一个映射,对后面的range通过调用前面的匿名函数形成一个数值映射,然后得到map结果,我们将这个结果转为list输出。filter在map的基础上呢,相当于加上了一层判断,其实filter也会对后面的list生成一个值的映射,但是filter会利用函数作为参数做一层判断,保留满足条件的结果。reduce函数呢,可以允许我们两两调用函数参数,最终只得到一个结果(如例子),这个例子的计算结果其实是1*2*3*4=24也就是也就是先1*2=2,再2*3=6,再6*4=24的结果。;lambda没什么说的了。不是很全,后面会再总结。

    from functools import reduce
    import random
    a = map(lambda x: x**2, range(1, 5))
    print(list(a))
    #  [1, 4, 9, 16]
    
    b = filter(lambda x: x>0, [1,-5,6,0])
    print(list(b))
    #  [1, 6]
    
    c = reduce(lambda x,y: x*y,range(1,5))
    print(c)
    #  24
    
    lst = [x * (-1)**x for x in range(1,10)]
    random.shuffle(lst)
    print(lst)
    d = sorted(lst,key = lambda x: x**2,reverse = True)
    print(d)
    #  [-3, -5, -7, 4, 6, 8, -1, 2, -9]
    #  [-9, 8, -7, 6, -5, 4, -3, 2, -1]
  • 相关阅读:
    骑行封龙山
    静夜
    骑行伏羲台
    我?
    生活挺好
    多事之秋,大家注意安全
    看不到啊看不到
    个人时间管理
    给DataGrid设置中文列名
    食用油是那么让人又爱又恨!
  • 原文地址:https://www.cnblogs.com/aoru45/p/9908590.html
Copyright © 2011-2022 走看看