• python成长之路七-函数的进阶


    1,python中,名称空间分三种:

    1. 全局命名空间

    2. 局部命名空间(临时命名空间)

    3. 内置名称空间

    2,作用域(两种):

       1,全局作用域  包含:全局名称空间   内置名称空间

       2,局部作用域  包含:局部命名空间

     

      2.1,取值顺序:

        就近原则:局部名称空间 --> 全局名称空间 --> 内置名称空间   单向从小到大范围

      2.2, 加载顺序:

        内置名称空间 --> 全局名称空间(当程序执行时) -- > 局部名称空间(当函数调用的时候)

    3,函数的嵌套:

      

    def func1():
        print(111)
    def func2():
        print(222)
        func1()
        print(333)
    print(666)
    func2()
    print(555)
    例子1
    def func1():
        print(222)
        def func2():
            print(333)
        print(111)
        func2()
        print(666)
    func1()
    
    # 执行结果:
    222 111 333 666
    例子2

    4,global   nonlocal

      局部名称空间对全局名称空间的变量可以引用,但是不能改变。

    count = 1
    def func1():
        count = 2
        print(count)
    func1()
    count = 1
    def func1():
        # count = 3
        count = count + 1  # local variable 'count' referenced before assignment
        print(count)
    func1()
    报错

    报错原因: 如果你在局部名称空间 对一个变量进行修改,那么解释器会认为你的这个变量在局部中已经定义了,但是对于上面的例题,局部中没有定义,所以他会报错,

      global

        1,在局部名称空间声明一个全局变量。

    声明

        2,在局部名称空间声明可以对全局变量进行修改。

    count = 1
    def func1():
        global count
        count = count + 1
        print(count)
    func1()
    print(count)
    修改

      nonlocal

        1,子函数对父函数的变量进行修改。

        2,此变量不能是全局变量

        3,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

    def func1():
        count = 666
        def inner():
            print(count)
            def func2():
                nonlocal count
                count += 1
                print("func2",count)
            func2()
            print("inner",count)
        inner()
        print("funcl",count)
    func1()
    
    # 运行结果:
    666
    func2 667
    inner 667
    funcl 667
    global

    5,函数的应用

      1,函数名就是函数的内存地址。

    def func():
        pass
    print(func) # <function func at 0x05958660>
    View Code

      2,函数名可以作为变量。

    def func1():
        print(666)
    f1 = func1
    f2 = f1
    f2()
    View Code

      3,函数名可以作为函数的参数。

    def func():
        print(666)
    def func1():
        func()
    def func2(x):
        x()
    func2(func1)
    View Code

      4,函数名可以当作函数的返回值。

    def wraaper():
        def inner():
            print("inner")
        return inner
    ret = wraaper()
    ret()
    View Code

      5,函数名可以当作为容器类类型的元素。

    def func1():
        print("in func1")
    def func2():
        print("in func2")
    def func3():
        print("in func3")
    def func4():
        print("in func4")
    l1 = [func1,func2,func3,func4]
    for i in l1:
        i()
    View Code

         向上面的函数名这种,第一个类对象。

    6,globals()   locals()

      1,globals()  返回全局变量的一个字典。

      2,locals()   返回当前位置的局部变量的字典。

    def funcl():
        a = 2
        b = 3
        # print(globals())
        # print(locals())
        def inner():
            c = 5
            d = 6
            print(globals())
            print(locals())
        inner()
    print(globals())
    print(locals())
    funcl()
    View Code

    7,闭包

        --内层函数对外层函数的变量(非全局变量)的引用,并返回。这样就形成了闭包。

      1,迭代器的条件:

          1,必须要有函数嵌套。

          2,内层函数必须要引用外层函数中的变量(不能是全局变量)。

          3,外层函数必须返回内部中的函数名(引用)。
        
    def wraaper():
        n = 1
        def inner():
            nonlocal n
            n += 1
            return n
        # inner()
        return inner
    f = wraaper()
    print(f())
    print(f())
    闭包

      2,闭包的作用:

          当程序执行时,遇到了函数执行,他会在内存开辟一个空间,局部名称空间,

          如果这个函数内部形成了闭包,

          那么他就不会随着函数的结束而消失。

    # 1,写装饰器的时候用。
    # 2,写爬虫的时候用。
    
    
    from urllib.request import urlopen
    
    def index():
        url = "http://www.xiaohua100.cn/index.html"
        def get():
            return urlopen(url).read()
        return get
    
    xiaohua = index()  # get
    content = xiaohua()  # get()
    content = xiaohua()  # get()
    print(content.decode('utf-8'))
    作用

    8,迭代器

      1,可迭代对象

        对象内部含有__iter__方法的就是可迭代对象。

        可迭代对象满足可迭代协议。

      2,判断是否是可迭代对象。

        

    dic = {"name":"alex"}
    print('__iter__' in dir(dic))
    方法一
    from collections import Iterable
    from collections import Iterator
    print(isinstance("alex",Iterable))
    print(isinstance('alex',Iterator))
    print(isinstance("alex",str))
    方法二

      3,可迭代对象 vs 迭代器

        可迭代对象不能取值,迭代器是可以取值的。

        可迭代对象 可以转化成迭代器。

    lis = [1,2,3]  # 可迭代对象
    itet = lis.__iter__()  #迭代器
    itet = iter(lis)  # 迭代器
    print(itet)
    View Code

        可迭代器如何取值?

          next一次,取值一次

          1,可迭代对象不能取值,迭代器是可以取值的。

          2,迭代器非常节省内存。

          3,迭代器每次只会取一个值。

          4,迭代器是单向的从上至下地取值,一条路走到头。

        1,迭代器原理

          1,将可迭代对象转化成迭代器。

          2,调用__next__方法取值。

          3,利用异常处理停止报错。

    s1 = "asdfg"
    iter1 = s1.__iter__()
    while 1:
        try:
            print(iter1.__next__())
        except StopIteration:
            break
    View Code
    s1 = "asdfg"
    
    # l1 = [i for i in range(100)]
    # print(11)
    
    ret = (i for i in range(10000))
    print(ret.__next__())
    print(ret.__next__())
    print(ret.__next__())
    View Code

    9, 生成器

        --就是自己python用代码写的迭代器,生成器的本质就是迭代器。

      1,构建一个生成器的两种方式:

          1,通过生成器函数。

          2,生成器表达式。

       生成器函数:

    def func1(x):
        x += 1
        return x
    func1(5) # 函数的执行命令,并且接受函数的返回值
    print(func1(5))
    函数
    def func1(x):
        x += 1
        print(111)
        print(111)
        print(111)
        yield x
        x += 2
        print(222)
        yield "alex"
        x += 3
    g_obj = func1(5) # 生成器函数对象
    # print(g_obj)
    # print(g_obj.__next__())
    print(g_obj.__next__())
    生成器函数

        一个 naxt 对应一个 yield

        yield 将值返回给生成器对象 .__next__()

        yield 和 return区别

        return 结束函数,给函数的执行者返回值

        yield  不会结束函数,一个next 对应一个yield,给生成器对.__next__()返回值。

        

        生成器函数 和 迭代器 区别

          1,自定制的区别

    # li = [1,2,3,4,5]
    # li.__iter__()
    
    def func1(x):
        x += 1
        yield x
        x += 3
        yield x
        x += 5
        yield x
    g1 = func1(5)
    print(g1.__next__())
    print(g1.__next__())
    print(g1.__next__())
    区别1

          2,内存级别的区别

          迭代器是需要可迭代对象进行转化。可迭代对象非常占内存。

          生成器直接创建,不需要转化,从本质就节省内存。

    def func1():
        for i in range(10000):
            yield i
    
    g1 = func1()
    for i in range(50):
        print(g1.__next__())
    
    # ————————————————————————
    def func1():
        print(1)
        count = yield 6
        print(count)
        print(2)
        count1 = yield 7
        print(count1)
        print(3)
        yield 8
    
    g = func1()
    next(g)
    g.send("alex")
    # g.send("太白")
    print(g.__next__())
    区别二

        

         send   与   naxt   区别

          send与next一样,也是对生成器取值(执行一个yield)的方法。

          send可以给上一个yield传值。

          第一次取值永远都是next。

          最后一个yield永远也得不到send传的值。

    # 函数
    def cloth1(n):
        for i in range(n+1):
            print("衣服%s号" % i)
    cloth1(1000)
    # --------------------------------
    # 生成器函数
    def cloth1(n):
        for i in range(1,n+1):
            yield ("衣服%s号" % i)
    g = cloth1(1000)
    for i in range(50):
        print(g.__next__())
    # for i in range(50):
    #     print(g.__next__())
    函数 vs 生成器

       列表推导式:

          -- 一行代码几乎搞定你需要的任何的列表。

          优点:一行解决,方便

          缺点:容易着迷,不易排错,不能超过三次循环。

         列表推导式不能解决所有列表问题,所以不要太刻意用。

        循环模式   [变量(加工后的变量)for 变量 initerable]

    l = [i for i in range(1,101)]
    print(l)
    
    l2 = print(["python%s期" % i for i in range(1,11)])
    
    print([i*i for i in range(1,11)])
    循环模式

        筛选模式  [变量(加工后的变量)in iterable if 条件]

    l3 = [i for i in range(1,31) if i % 2 == 0]
    print(l3)
    
    print([i for i in range(1,31) if i % 3 == 0])
    
    print([i**2 for i in range(1,31) if i % 3 == 0])
    
    
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
             ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    # 请选出名字中带两个e的
    
    print([j for i in names for j in i if  j.count("e") == 2])
    筛选模式

       生成器表达式: 将列表推导式的 [ ] 换成 ( ) 即可。

    g = (i for i in range(100000))
    print(g)
    print(g.__next__())
    print(g.__next__())
    for i in range(20): # 循环取取值
        print(g.__next__())
    生成器表达式
    mcase = {"a":10,"b":34}
    mcase_frequency = {mcase[k]: k for k in mcase} # 将键值对反转
    print(mcase_frequency)
    元组表达式
    squared = {x**2 for x in [1,-1,2]} # 将集合去重
    print(squared)
    集合表达式
  • 相关阅读:
    在java中获取URL的域名或IP与端口
    解决notepad++64位没有plugin manager的问题
    统一认证需要解决的问题
    搭建Maven私服
    Update openssh7.9 on centos6
    python下载想听的有声书,让喜马拉雅收费,我是程序员!
    golang ---获取内存信息
    websocket学习
    go 读取BMP文件头二进制读取
    go 计算文件行
  • 原文地址:https://www.cnblogs.com/peng104/p/9488414.html
Copyright © 2020-2023  润新知