zoukankan      html  css  js  c++  java
  • 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)
    集合表达式
  • 相关阅读:
    (转载)SAPI 包含sphelper.h编译错误解决方案
    C++11标准的智能指针、野指针、内存泄露的理解(日后还会补充,先浅谈自己的理解)
    504. Base 7(LeetCode)
    242. Valid Anagram(LeetCode)
    169. Majority Element(LeetCode)
    100. Same Tree(LeetCode)
    171. Excel Sheet Column Number(LeetCode)
    168. Excel Sheet Column Title(LeetCode)
    122.Best Time to Buy and Sell Stock II(LeetCode)
    404. Sum of Left Leaves(LeetCode)
  • 原文地址:https://www.cnblogs.com/peng104/p/9488414.html
Copyright © 2011-2022 走看看