zoukankan      html  css  js  c++  java
  • 第四篇: python函数续

    1、函数的嵌套

    函数的嵌套调用:在调用一个函数的过程中,又调用了其它函数

    示例1:

    def bar():
        print('from nbar')
    
    def foo():
        print('from foo')
        bar()
    foo()
    #执行结果为
    C:UsersAdministratorAppDataLocalProgramsPythonPython36python.exe C:/Users/Administrator/PycharmProjects/python18/day4/函数嵌套.py
    from foo
    from nbar
    

    示例2:求函数所带四个参数的最大值

    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    
    def max4(a,b,c,d):
        res1=max2(a,b)
        res2=max2(res1,c)
        res3=max2(res2,d)
        return res3
    print(max(1,2,3,-1))
    
    #执行结果如下
    C:UsersAdministratorAppDataLocalProgramsPythonPython36python.exe C:/Users/Administrator/PycharmProjects/python18/day4/函数嵌套.py
    3
    

    函数的嵌套定义:在一个函数的内部,又定义另外一个函数

    2、名称空间和作用域

    名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方
    名称空间共有三种名称空间既:
      1、内置名称空间:在python解释器启动时产生,存放一些python内置的名字
      2、全局名称空间:在执行文件时产生,存放文件级别定义的名字
      3、局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效

    加载顺序:内置===》全局===》局部


    优先掌握一:名字的查找顺序是:局部==》全局===》内置


    作用域:作用的范围
    全局作用域:全局存货,全局有效:globals()


    局部作用域:临时存活,局部生效:locals()
    x=11111111111111111111111111111111111111111111
    
    # def f1():
    #     x=1
    #     y=2
    #     def f2():pass
    #     # print(locals())
    #     print(globals())
    #
    # f1()
    # print(locals() is globals())
    # print(locals())
    #
    # print(dir(globals()['__builtins__']))
    
    #global nonlocal掌握
    # x=1
    # def f1():
    #     global x
    #     x=2
    #
    # f1()
    # print(x)
    
    
    # l=[]
    # def f2():
    #     l.append('f2')
    #
    # f2()
    # print(l)
    
    
    # x=0
    # def f1():
    #     # x=1
    #     def f2():
    #         # x=2
    #         def f3():
    #            # global x
    #            nonlocal x
    #            x=3
    #         f3()
    #         # print(x)
    #     f2()
    #     print(x)
    # f1()
    # print(x)
    

     

    优先掌握二:作用域关系,在函数定义时就已经固定,于调用位置无关,在调用函数时,必须必须必须回到函数原来定义的位置去找作用域关系

    x=1
    def  f1():
        def f2():
            print(x)
        return f2
    
    
    # func=f1()
    # print(func)
    # x=10000000
    # func()
    # x=10000000
    
    
    def foo(func):
        x=300000000
        func() #f2()
    x=10000000000000000000000
    
    
    foo(f1())
    # x=10000000000000000000000
    # foo(f1())
    

      

    3、闭包函数

    1. 定义在函数内部的函数
    2. 包含对外部作用域名字的引用,而不是对全局作用域名字的引用,那么该内部函数就称为闭包函数

    # x=1
    # def  f1():
    #     x=11111111111
    #     def f2():
    #         print(x)
    #     return f2
    #
    # func=f1()
    
    
    # x=1000
    # func()
    
    # def foo():
    #     x=12312312312312312312312312312312312313123
    #     func()
    #
    #
    # foo()
    
    
    # def deco():
    #     x=123123123123
    #     def wrapper():
    #         print(x)
    #     return wrapper
    #
    # func=deco()
    
    
    # func()
    

    闭包函数的应用:惰性计算

    import requests #pip3 install requests
    
    # def get(url):
    #     return requests.get(url).text
    #
    # print(get('https://www.python.org'))
    # print(get('https://www.python.org'))
    # print(get('https://www.python.org'))
    # print(get('https://www.python.org'))
    
    # def index(url):
    #     # url='https://www.python.org'
    #     def get():
    #         # return requests.get(url).text
    #         print(requests.get(url).text)
    #
    #     return get
    #
    # python_web=index('https://www.python.org')
    # baidu_web=index('https://www.baidu.com')
    
    # python_web()
    # baidu_web()
    
    
    name='egon'
    def index(url):
        x=1
        y=2
        def wrapper():
            # x
            # y
            # return requests.get(url).text
            print(name)
        return wrapper
    
    python_web=index('https://www.python.org')
    
    # print(python_web.__closure__[0].cell_contents)
    print(python_web.__closure__)
    # print(python_web.__closure__[0].cell_contents)
    # print(python_web.__closure__[1].cell_contents)
    # print(python_web.__closure__[2].cell_contents)
    

    4、装饰器 

    1、 开放封闭原则:对扩展是开放的,对修改是封闭

    2、 装饰器:装饰它人的工具,装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象
      2.1 装饰器的遵循的原则:

        2.1.1、 不修改被装饰对象的源代码

        2.1.2、 不修改被调用对象的调用方式

    装饰器名,必须写在被装饰对象的正上方,并且是单独一行

    import time
    
    def timmer(func):
        # func=index
        def wrapper():
            start=time.time()
            func()
            stop=time.time()
            print('run time is %s' %(stop-start))
        return wrapper
    
    
    @timmer # index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
    @timmer # home=timmer(home)
    def home():
        time.sleep(2)
        print('welcome to home page')
    
    index()
    home()  

    装饰器补充

    #补充一:wraps
    
    # import time
    # from functools import wraps
    #
    # def timmer(func):
    #     @wraps(func)
    #     def wrapper(*args,**kwargs):
    #         start=time.time()
    #         res=func(*args,**kwargs)
    #         stop=time.time()
    #         print('run time is %s' %(stop-start))
    #         return res
    #     return wrapper
    #
    #
    # @timmer # index=timmer(index)
    # def index():
    #     '''这是index函数'''
    #     time.sleep(3)
    #     print('welcome to index')
    #     return 123
    #
    # print(index.__doc__)
    # # print(help(index))
    
    #补充二:一个函数头顶上可以多个装饰器 import time from functools import wraps current_user={'user':None} def timmer(func): @wraps(func) def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop-start)) return res return wrapper def auth(auth_type='file'): def deco(func): def wrapper(*args, **kwargs): if auth_type == 'file': if current_user['user']: return func(*args, **kwargs) name = input('name: ').strip() password = input('password: ').strip() with open('db.txt', encoding='utf-8') as f: user_dic = eval(f.read()) if name in user_dic and password == user_dic[name]: res = func(*args, **kwargs) current_user['user'] = name return res else: print('user or password error') elif auth_type == 'mysql': print('mysql') elif auth_type == 'ldap': print('ldap') else: print('not valid auth_type') return wrapper return deco @timmer #index=timmer(wrapper) @auth() # @deco #index=deco(index) #wrapper def index(): '''这是index函数''' time.sleep(3) print('welcome to index') return 123 # print(index.__doc__) # print(help(index)) index()

      

    5、生成器

     学习生成器之前,我们先来看看什么是列表生成式

    #列表生成式
    b = [ i*2 for i in range(10)]
    print(b)
     
    ###########打印输出###########
    #[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,还需要花费很长时间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种调用时才会生成相应数据的机制,称为生成器:generator

    要创建一个generator,有很多种方法,第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个生成器

    #生成器
    l = [ i*2 for i in range(10)]
    print(l)
     
    g = (i*2 for i in range(10))
    print(g)
     
    ###########打印输出###########
    #[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    #<generator object <genexpr> at 0x0064AAE0>
    

    print(g) 打印出来的信息显示g是一个生成器,创建lg的区别仅在于最外层的[]()l是一个list,而g是一个generator;我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值

    #生成器next打印
    print(next(g))
    #.........                 不断next 打印10次
    #..........
    print(next(g))
     
    ###########打印输出###########
    #0
    #........
    #18
    #Traceback (most recent call last):
    #  File "<stdin>", line 1, in <module>
    #StopIteration
    

    我们讲过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

    上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象,所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误

    #生成器for调用
    g = (i*2 for i in range(10))        #不用担心出现StopIteration错误
    for i in g:
        print(i)
     
    ###########打印输出###########
    # 0
    # 2
    # 4
    # 6
    # 8
    # 10
    # 12
    # 14
    # 16
    # 18
    

    generator非常强大。如果推算的算法比较复杂,用列表生成式转换的生成器无法去实现时,我们还可以用函数来实现。比如,著名的斐波拉契数列(Fibonacci)  

    #函数表示斐波拉契数列
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b)
            a, b = b, a + b
            n += 1
        return 'done'
     
    fib(5)
    ###########打印输出###########
    # 1
    # 1
    # 2
    # 3
    # 5
    

    仔细观察,可以看出,fib函数实际上是定义了斐波那契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator;也就是说,上面的函数和generator仅一步之遥,那我们能不能把上面的函数变成一个生成器呢?  

    #斐波拉契数列转换为generator
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            #print(b)
            yield b
            a, b = b, a + b
            n += 1
        return 'done'
     
    print(type(fib(5)))     #打印fib(5)的类型
    for i in fib(5):        #for循环去调用
        print(i)
    ###########打印输出###########
    # <class 'generator'>
    # 1
    # 1
    # 2
    # 3
    # 5
    

    要把fib函数变成generator,只需要把print(b)改为yield b就可以了,这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

    但是用for循环调用generator时,会发现拿不到generator的return语句的返回值,也就是return的值没有打印出来,现在我们来看看怎么去打印generator的返回值

    #获取generator的返回值
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            #print(b)
            yield b
            a, b = b, a + b
            n += 1
        return 'done'
     
    g = fib(5)
    while True:
        try:
            x = next(g)
            print( x)
        except StopIteration as e:
            print(e.value)
            break
    ###########打印输出###########
    # 1
    # 1
    # 2
    # 3
    # 5
    # done
    

    如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中,关于如何捕获错误,后面的错误处理还会详细讲解。 

    还可通过yield实现在单线程的情况下实现并发运算的效果

    import time
    def consumer(name):
        print("%s 准备吃包子啦!" %name)
        while True:
           baozi = yield
     
           print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
     
     
    def producer(name):
        c = consumer('A')
        c2 = consumer('B')
        c.__next__()        #c.__next__()等同于next(c)
        c2.__next__()
        print("老子开始准备做包子啦!")
        for i in range(10):
            time.sleep(1)
            print("%s做了2个包子!"%(name))
            c.send(i)
            c2.send(i)
     
    producer("lzl")
    

      

    6、迭代器  

    迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来  

    # while True: #单纯的重复
    #     print('你瞅啥')
    
    # l=['a','b','c','d']
    # count=0
    # while count < len(l):
    #     print(l[count])
    #     count+=1
    
    dic={'name':'egon','sex':'m',"age":18} #上述按照索引的取值方式,不适于没有索引的数据类型
    

    迭代器:
    可迭代对象iterable:凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象

    # s='hello'
    # l=['a','b','c','d']
    # t=('a','b','c','d')
    # dic={'name':'egon','sex':'m',"age":18}
    # set1={1,2,3}
    # f=open('db.txt')
    
    # s.__iter__()
    # l.__iter__()
    # t.__iter__()
    # dic.__iter__()
    # set1.__iter__()
    # f.__iter__()
    

    迭代器对象:可迭代对象执行内置的__iter__方法,得到的结果就是迭代器对象  

    # dic={'name':'egon','sex':'m',"age":18}
    #
    # i=dic.__iter__()
    # # print(i) #iterator迭代器
    #
    # # i.__next__() #next(i)
    # print(next(i))
    # print(next(i))
    # print(next(i))
    # print(next(i)) #StopIteration
    #
    # l=['a','b','c','d']
    #
    # i=l.__iter__()
    # print(next(i))
    # print(next(i))
    # print(next(i))
    # print(next(i))
    # print(next(i)) #StopIteration
    

    不依赖于索引的取值方式  

    # l=['a','b','c','d']
    # dic={'name':'egon','sex':'m',"age":18}
    # iter_l=iter(l)
    # iter_dic=iter(dic)
    # while True:
    #     try:
    #         # print(next(iter_l))
    #         k=next(iter_dic)
    #         print(k,dic[k])
    #     except StopIteration:
    #         break
    

    什么是迭代器对象:
    1 有__iter__,执行得到仍然是迭代本身
    2 有__next__

      

    迭代器对象的优点
    1:提供了一种统一的(不依赖于索引的)迭代方式
    2:迭代器本身,比起其他数据类型更省内存

    # l=['a','b','c','d']
    # i=iter(l)
    
    # dic={'a':1,'b':2}
    # x=dic.keys()
    # print(x)
    # i=x.__iter__()
    #
    # with open('a.txt') as f:
    #     # print(next(f))
    #     # print(next(f))
    #     # print(next(f))
    #     f.read()
    

    迭代器对象的缺点
    1:一次性,只能往后走,不能回退,不如索引取值灵活
    2:无法预知什么时候取值结束,即无法预知长度

    # l=['a','b','c','d']
    # i=iter(l)
    # print(next(i))
    # print(next(i))
    # print(next(i))
    
  • 相关阅读:
    需求管理是CMM可重复级中的6个关键过程域之一,其主要目标是__________。A.客观地验证需求管理活动
    47、软件需求工程的活动可以划分为5个独立的阶段:需求获取、需求建模、形成需求规格、需求验证和需求管理,需求建模是()
    JavaScript alert()函数
    系统讲解一下,Dao,Entity,Servlet,Action各自有什么东西-Java/Web开发
    用Eclipse 开发Dynamic Web Project应用程序
    Connection conn = DriverManager.getConnection("jdbc:odbc:bbs");
    linux 常用快捷命令
    Docker 命令大全
    小白入门之十七:yum源配置并使用其安装软件包
    Linux从一般用户切换到root用户
  • 原文地址:https://www.cnblogs.com/junxun/p/7224615.html
Copyright © 2011-2022 走看看