zoukankan      html  css  js  c++  java
  • 路飞学城-Python开发集训-第3章

    学习心得:

      通过这一章的作业,使我对正则表达式的使用直接提升了一个level,虽然作业完成的不怎么样,重复代码有点多,但是收获还是非常大的,有点找到写代码的感觉了,遗憾的是,这次作业交过,这次集训就结束了,后面视频中的作业和内容将不再做讲解,也没有作业批改,不论如何这次集训对于自己提升还是蛮多的,真的要感谢路飞这个学习平台。

    学习笔记:

    三元运算:

    三元运算又称三目运算,是对简单的条件语句的简写。

    #简单条件语句
    if 条件成立:
        val=1
    else:
        val=2
    
    #改成三元运算
    val=1 if 条件成立 else 2

    小例子:

    a = 2
    b = 5
    val = a if a <b else b
    print(a)

    函数:

    函数的参数类型:位置参数、关键字参数、缺省参数、非固定参数

    *args

    def send_alert(msg,*args,age):
        for u in args:
            print("报警发送给",u)
    
    #如果参数中出现 *agrs,传递的参数就可以不再是固定个数,传过来的所有参数打包成元组
    #传参数有两种方式,一种是方式一,这种情况下所有参数被打包成元组
    #另一种方式是方式二,直接传一个元组或列表,注意一定要在元组或列表前面加*,不然会把他们当成一个参数
    #其实本质就是args就是一个元组
    #一般情况下非固定参数放在最后,后面不加其它参数,这里后面加个age是为了实验效果,由于args会截获所有位置参数,所以这里在给age传参数的时候,必须要指明,不然也会被args截获,从而没有age的错
    
    #方式一:
    send_alert("别再浪了","alex","eric","rain",age=22)
    
    #方式二:
    send_alert("别再浪了",*["alex","eric","rain"],age=22)

    **kwargs

    def func(name,*args,**kwargs):
        print(name,args,kwargs)
    
    func("alex")    #alex () {}   可以看出后面两个参数是可以不传的,不传就为空
    
    func("alex",22,"tesla","500w",addr="山东",num=1244)   #alex (22, 'tesla', '500w') {'addr': '山东', 'num': 1244}
    #args会截获位置参数,而kwargs会截获关键字参数
    
    d={"degress":"primary school"}
    func("peiqi",d)   #peiqi ({'degress': 'primary school'},) {}
    func("peiqi",**d)   #peiqi () {'degress': 'primary school'}     这个和上面args一样的道理

    局部变量:

    (1)局部变量和全局变量在某种程度上是两个独立的空间,相同的变量名代表不同的变量,所以局部并没有修改全局变量,而是在局部创建一个相同变量名的变量。

    name="black girl"
    
    def change_name():
        name="黑色的女孩"
        print(name)
    
    change_name()   #黑色的女孩
    print(name)   #black girl

    (2)查找变量遵循从自身开始按LEGB方向查找,比如在全局调用变量,那么就从身G开始,按GB方向查找,不会往后找。

    (3)由于局部变量和全局变量是两个独立空间,那如果想在局部修改(重新赋值方式)全局的变量,怎么办?

    name="black girl"
    
    def change_name():
        global name  #声明name是全局的那个变量,声明要放在变量前面,不然会报错!在生产环境中不建议在局部修改全局变量
        name="黑色的女孩"
        print(name)
    
    change_name()   #黑色的女孩
    print(name)   #黑色的女孩

      注意下面这种方法虽然能修改变量的值,但其实并没有修改变量本身,变量并没有变。

    name=["alex","black girl","peiqi"]
    
    def change_name():
        global name
        del name[2]
        print(name)
    
    change_name()   #['alex', 'black girl']
    print(name)   #['alex', 'black girl']

      变量自身有没有变可以看内存地址,如果内存地址变了,说明这个变量变了

    name=1
    print(id(name))   #1358758352
    name=2
    print(id(name))   #1358758384
    
    name=["alex","black girl","peiqi"]
    print(id(name))    #12374408
    del name[2]
    print(id(name))    #12374408

    嵌套函数:

    #情形一
    def func1():
        print("alex")
        def func2():
            print("eric")
    func1()     #alex
    #分析:为什么结果只打印了一个alex,而没有打印eric?
    #这是因为函数定义的时候不会被执行,如果想执行必须调用,题中调用了函数1,而函数1在执行的时候先是打印了alex,
    # 然后定义了函数2,但这只是定义了函数2,并没有执行,所以只打印了alex
    
    #情形二
    def func1():
        print("alex")
        def func2():
            print("eric")
        func2()
    func1()     #alex   eric
    #分析:为什么这次两个都打印了?
    #这是因为在执行函数1时,先打印了alex,然后定义了fun2,定义函数2之后,又执行了函数2,所以两个都打印了。
    
    #情形三
    age = 19
    def func1():
        age =73
        print(age)
        def func2():
            age = 84
            print(age)
        func2()
    func1()    #73   84
    #这个没什么好说的。
    
    #情形四
    age = 19
    def func1():
        age =73
        print(age)
        def func2():
            print(age)
        func2()
    func1()    #73   73
    #这个也没什么好说的,按照LEGB的原则去找,fun2在自己内部找不到age变量,就到它的父级去找,在父级找到了就打印了
    
    #情形五
    age = 19
    def func1():
        def func2():
            print(age)
        age = 73
        func2()
    func1()    #73
    #由于定义age是在执行func2之前,所以age存在于他的父级作用域,所以它就在父级作用域找到了age,所以打印了73
    
    #情形六
    age = 19
    def func1():
        def func2():
            print(age)
        func2()
        age = 73
    func1()    #报错:NameError: free variable 'age' referenced before assignment in enclosing scope
    #分析:为什么会报错?
    #虽然父级作用域存在age变量,但func2在调用的时候age还没有被定义,这就出现了调用在定义之前,所以报错,这个和global那个比较类似
    
    #情形七
    age = 19
    def func1():
        global age
        def func2():
            print(age)
        func2()
        age = 73
    func1()    #19
    print(age)    #73
    #这个global声明是在最上面的,所以fun2在自身没找到后,往父级找,其实在父级也没找到(父级中的age也是全局的,只是在局部被重新赋值了),
    # 然后往global找,找到了age=19,所以就打印了。打印73是因为被重新赋值导致的
    
    # 情形八
    age = 19
    def func1():
        global age
        def func2():
            print(age)
        age = 73
        func2()
    func1()   #73
    #func2在执行之前age已经被重新赋值了,所以打印的是73

    作用域:

    在python中函数就是一个作用域

    代码定义完成后,作用域已经生成,作用域链向上查找

    匿名函数:

    def calc(x,y):
        return x*y
    
    lambda x,y:x*y  #声明一个匿名函数
    
    #上面这两个函数执行效果是一样的,但是第二个函数不好执行,如果想执行需要将它赋给一个变量,如下:
    
    func=lambda x,y:x*y     #赋给一个变量之后这样就好执行了
    
    print(func(3,8))    #24
    
    #############################################################################################
    
    def calc(x,y):
        if x<y:
            return x*y
        else:
            return x/y
    
    #lambda不支持复杂的逻辑语句,像上面这样就不行,lambda支持最复杂的就是三元运算,匿名本质上就是把多行语句变成了一行
    
    func=lambda x,y:x*y if x<y else x/y
    
    print(func(16,8))       #2.0
    
    #匿名函数主要一个作用就是和其它一些方法搭配使用(像上面这样匿名函数赋值给一个变量,和普通函数没什么区别)
    
    def f2(n):
        return n*n
    
    print(list(map(f2,data)))   #用普通函数实现乘方
    print(list(map(lambda x:x*x,data)))     #map函数的作用就是将后面的参数一个一个放入前面的函数执行。
    
    #匿名函数的作用:
    #1.节省代码量
    #2.看着高级

    深入分析:

    # ---CASE 1
    fs = map(lambda i:(lambda j: i*j), range(6))
    print([f(2) for f in fs])
    
    #---CASE 2
    fs = [lambda j:i*j for i in range(6)]
    print([f(2) for f in fs])
    
    #---CASE 3
    fs = []
    for i in range(6):
        fs.append(lambda j:i*j)
        if i==3:
            break
    print([f(2) for f in fs])
    
    #---CASE 4
    fs = [(lambda i:lambda j:i*j)(i) for i in range(6)]
    print([f(2) for f in fs])

    搞会这几题只需弄懂一个问题,lambda函数是否执行并且在什么时候执行。

    递归:函数在执行的过程中执行自己。

    import sys
    print(sys.getrecursionlimit())    #默认递归深度
    sys.setrecursionlimit(1500)    #设置递归深度
    
    def resursion(n):
        print(n)
        resursion(n+1)
    
    resursion(1)

    为什么要限制递归深度?

    简单的理解就是递归函数执行之后,之前执行的所有函数都没有结束,这样会占用大量的内存空间,最终把内存撑爆。

    深层次的理解就是函数的栈帧的关系。

    递归的作用:用来解决复杂的数学问题,比如斐波那契数列、汉诺塔、多级评论数、二分查找、求阶乘等

    求阶乘:

    任何大于1自然数n阶乘表示方法:

    n! = 1*2*3*4...*n

    n! = n*(n-1)!

    内置函数:

    eval()  执行括号内的字符串,如果是代码或运算就执行,但只能执行一行代码,多行无法执行,它可以拿到返回值,但是无法执行函数。

    exec()  可以执行多行代码,如果代码中有函数,这个函数是拿不到返回值的,也就是说只能执行,但没有结果。

    code='''
    def foo():  
        print("run foo")
        return 1234
    foo()
        '''     #这个函数必须顶行写,不然报错!!!
    res=exec(code)  #run foo
    print(res)  #none,也就是说exec没有返回值
    
    print(eval("1+3+6+8"))  #18,虽然eval不能执行多行代码,但是通过此方法还是能证明它有返回值。
    print(exec("1+3+6+8"))  #None,再次证明exec没有返回值

    ord()  查看字符的ASCII码

    chr()  将看ASCII码编号对应的字符

    print(ord("a"))     #97
    print(chr(97))      #a

    sum()  求和

    a=[100,-33,-22,180,30]
    print(sum(a))   #255

    print()

    msg="又回到最初的起点"
    msg2="记忆中你青涩的脸"
    f=open("那些年.txt","w",encoding="utf8")
    print(msg,msg2,end="",sep="|",file=f)  #又回到最初的起点|记忆中你青涩的脸

    dir()  打印当前程序的变量名

    vars()  打印当前程序的变量名和变量值

    locals()  打印当前局部变量的变量名和变量值

    globals()  打印全局变量名和变量值 

    print(dir())    #['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
    print(vars())   #{'__spec__': None, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/Lowry/PycharmProjects/lufyy/dir_var.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000060E3C8>, '__doc__': None, '__name__': '__main__', '__cached__': None, '__package__': None}
    print(locals())   #如果在全局,结果同上,如果在函数里面,那么只打印局部变量和变量值
    print(globals())    #不论在哪,都是只打印全局变量名和变量值

    round()  保留几位小数

    print(round(1.22234342,2))  #1.22  保留两位小数

    装饰器:

    写一个装饰器

    生成器:

    列表生成式:li = [ i*i  for i in range(10) ]  这个生成的是一个列表

    这种生成式用法只能用在列表或元组里

    斐波那契

    只要函数里面有yield,这个函数名()就变成了一个生成器,无论里面有没有return。

    return在生成器里,代表生成器的中止,直接报错。

    next

    唤醒生成器并断续执行

    send

    唤醒并继续执行

    发送一个信息到生成器内部

    def range2(n):
        count=0
        while count<n:
            count+=1
            sign=yield count
            if sign=="stop":
                break
    
    g=range2(10)
    print(next(g))
    print(next(g))
    g.send("stop")
    print(next(g))

    迭代器:

    可直接用于for循环的数据类型有以下几种:

    一类是集合数据类型,如 list、tuple、dict、set、str 等

    一类是generator ,包括生成器和带yield的generator function。

    可以直接用于for循环的对象统称为可迭代对象:iterable

    可使用instance()判断一个对象是不是iterable对象

    from collections import Iterable    #Iterable第一个字母必须要大写
    
    print(isinstance([],Iterable))  #True

    而生成器不但可以被for循环,还可以被next()函数调用并返回下一个值,直到最后抛出stopiteration错误表示无法继续

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator (只要满足这个条件的都迭代器,生成器只是迭代器的一种)

    可使用instance()判断一个对象是不是iterator对象

    from collections import Iterator
    
    print(isinstance((i for i in range(10)),Iterator))  #True
    
    print(isinstance([],Iterator))  #False

    小结:

    凡是可作用于for循环的对象都是Iterable类型;

    凡是可作用于next()函数的对象都是Iterbtor类型,它们表示一个惰性计算序列

    集合数据类型如list、dict、str乖都是Iterable但不是Iterbtor,不过可以通过iter()函数将可迭代对象变成迭代器对象。

    python3的for循环本质上就是通过不断调用next()函数实现的。

  • 相关阅读:
    设置DELL R720 的CPU 风扇转速
    mysqldump 备份导出数据排除某张表或多张表
    MySQL 之 LOAD DATA INFILE 快速导入数据 (单表数据很大)
    ACL规则 反掩码的 写法
    配置Nginx 支持中文URL
    如何删除IE中的证书
    微软Surface 上网本 键盘失灵
    华为 S2700忘记console口密码
    Dell PowerEdge R710, R720 用U盘装系统
    用php做省份的三级联动 附带数据库
  • 原文地址:https://www.cnblogs.com/sq5288/p/9076275.html
Copyright © 2011-2022 走看看