• 函数


    1. 函数嵌套

    1.1 函数嵌套调用

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

    复制代码
    def bar():
        print("from in the bar.")
    
    def foo():
        print("from in the foo.")
        bar()
    
    foo()
    复制代码

     

    1.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
    
    res = max4(2,5,3,-4)
    print(res)
    复制代码

     

    1.3 函数嵌套定义

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

    复制代码
    def f1():
        x = 1
        def f2():
            print("from f2.")
        f2()   # 只能在函数内部调用
    
    f1()
    复制代码

    2. 名称空间

    2.1 介绍

      名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方。

      内置名称空间:在python解析器启动时产生,存放一些python内置的名字。

      全局名称空间:在执行文件时产生,存放文件级别定义的名字。

      局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效。

    2.2 加载、查找顺序

      加载顺序:内置名称空间 --> 全局名称空间 --> 局部名称空间

      查找顺序:局部名称空间 --> 全局名称空间 --> 内置名称空间

                                     

    3. 作用域

    3.1 基本概念

      作用域:作用的范围

      全局作用域:全局存活、全局有效

      局部作用域:临时存活、局部有效

      查看作用域:globals(),locals()

        查看全局作用域:globals()

        查看局部作用域:locals()

    3.2 global

      局部修改全局的名字:global

      针对全局不可变类型,用global进行修改

      针对全局可变类型,在函数内部可以直接修改全局变量的内容

      利用global,在函数内部进行修改全局变量;此种方法慎用;以后尽量避免利用局部修改全局的名字

    复制代码
    # 不可变类型,利用global进行修改全局变量值
    x = 20
    def foo():
        global x
        x = 30
    foo()
    print(x)        # 此时x的值已经被修改,变为30
     
    # 可变类型的全局变量,在函数内部进行直接修改
    l = []
    def foo():
        l.append("jack")
    foo()
    print(l)    # 此时l已经变为:['jack']
    复制代码

    3.3 nonlocal

      nonlocal,修改的局部变量的上一层变量,只是修改局部的变量;

    复制代码
    x = 0
    def f1():
        x = 100
        def f2():
            x = 200
            def f3():
                nonlocal x
                x = 300
            f3()
            print(x)   # 利用nonlocal定义的变量 进行修改上一层的局部变量
        f2()
        print(x)      # nonlocal只修改上一层局部变量,此时打印f1定义的变量
    f1()
    复制代码

     

    3.2 作用域关系

      作用域关系:在函数定义时就已经确定,与调用位置无关;在调用函数时,必须回到函数原来定义的位置去找作用域关系

    复制代码
    x = 1
    def f1():
        def f2():
            print(x)
        return f2
    
    func = f1()
    x = 10000
    func()       # 此时打印1000,只是打印的是x = 1定义的地方,只是在后面进行修改 x = 10000
     
    
    # 作用域关系,在定义阶段就已经确定,与调用位置无关
    
    x = 1
    def f1():
        def f2():
            print(x)
        return f2
    
    def foo(func):
        x = 30000
        func()   # 相当于调用f2,打印x为1
    
    foo(f1())
    复制代码

    4. 闭包函数

    4.1 定义

      闭包函数简单理解就是:闭合、包裹的函数

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

    4.2 实例

    复制代码
    # wrapper称为闭包函数,定义deco内部的函数,并对外部x的引用,而变量x不是全局变量
    def deco():
        x = 1000
        def wrapper():
            print(x)
        return wrapper
    
    func = deco()
    func()
    复制代码

    4.3 闭包应用-惰性计算

      爬网页的简单程序

    复制代码
    import requests   # pip3 install requests
    def index(url):
        def wrapper():
            # return requests.get(url).text
            print(requests.get(url).text)
        return wrapper
    
    python_web = index("https://www.python.org")
    baidu_web = index("https://www.baidu.com")
    
    python_web()
    baidu_web()
    复制代码
     

    4.4 查看闭包函数参数

      查看闭包函数外面包裹的参数

    复制代码
    import requests   # pip3 install requests
    def index(url):
        def wrapper():
            print(requests.get(url).text)
        return wrapper
    python_web = index("https://www.python.org")
    print(python_web.__closure__)   # (<cell at 0x00000000021A7528: str object at 0x0000000002209DB0>,)
    print(python_web.__closure__[0].cell_contents) # 查看闭包函数的包裹的参数 https://www.python.org
    复制代码

    5. 装饰器

    5.1 基本概念

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

      装饰器:装饰其他对象的工具

        装饰器本身可以是任意可调用对象,被装饰的对象也可以是任意可调用对象

      装饰器的遵循的原则:

        1.不修改被装饰对象的源代码

        2.不修改被调用对象的调用方式

      装饰器的目的是:

        在遵循1和2原则的前提,为其他可调用对象添加新功能

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

    5.2 装饰器前奏

    5.2.1 修改源代码

    复制代码
    import time
    def index():
        start_time = time.time()
        time.sleep(2)
        print("from in index")
        stop_time = time.time()
        print("run time is %s" % (stop_time - start_time))
    index()
    复制代码

    5.2.2 修改了调用方式

    复制代码
    import time
    def wrapper(func):
        start_time = time.time()
        time.sleep(2)
        func()
        stop_time = time.time()
        print("run time is %s" % (stop_time - start_time))
    
    def index():
        time.sleep(2)
        print("from in index.")
    
    wrapper(index)  # 修改了函数的调用方式
    复制代码

    5.2.3 应用实例

    复制代码
    import time
    def timmer(func):
        def wrapper():
            start_time = time.time()
            func()
            stop_time = time.time()
            print("run time is %s" %(stop_time - start_time))
        return wrapper
    @timmer  # index=timmer(index)
    def index():
        time.sleep(2)
        print("from in index")
    @timmer  # home=timmer(home)
    def home():
        time.sleep(2)
        print("from in home")
    
    index()
    home()
    复制代码

      运行结果:

    from in index
    run time is 2.0001142024993896
    from in home
    run time is 2.0001144409179688

    5.3 被装饰的对象有参数

      解决装饰器的闭包函数,能够适应有参数、无参数、各种各样的参数的形式

    复制代码
    import time
    def timmer(func):
        def wrapper(*args, **kwargs):
            start=time.time()
            func(*args, **kwargs)
            stop=time.time()
            print('run time is %s' %(stop-start))
        return wrapper
    
    @timmer # home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page' %name)
    
    home('jack')  #  hom('jack') wrapper('jack')
    复制代码

    5.4 被装饰的对象有返回值

      有返回值的情况,需要在装饰器处理有返回值的情况,也就是在wrapper最后,利用return进行返回处理结果

    复制代码
    import time
    def timmer(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 # home=timmer(home)
    def home(name):
        time.sleep(2)
        print("welcome %s to home page" %name)
        return "from home return ok."
    
    res = home('jack') # wrapper('jack')
    print(res)         # from home return ok.
    复制代码

    5.5 装饰器:登录认证

      实行认证功能的装饰器,需要对用户输入用户名和密码进行验证,在输入正确的情况下,才执行被装饰函数的内容。

    5.5.1 无参数装饰器实现认证

    复制代码
    current_user={'user':None}
    def auth(func):
        def wrapper(*args, **kwargs):
            if current_user['user']:    # 自带bool判断功能
                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')
        return wrapper
    
    @auth #index=auth(index) index=wrapper
    def index():
        print('from index')
    @auth
    def home(name):
        print('welcome %s' %name)
    
    index() #wrapper()
    home('jack')
    复制代码

    5.5.2 有参函数装饰器

    复制代码
    current_user={"user":None}
    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
    @auth(auth_type="mysql") #@deco  #index=deco(index)
    def index():
        print("from index")
    @auth(auth_type='file')
    def home(name):
        print("welcome %s" %name)
    index() #wrapper()
    home('jack')
    复制代码

    5.6 装饰器的其他属性

    5.6.1 被装饰函数的注释信息

       需要导入functools模块,在被装饰的函数上方加@wraps(func)

    复制代码
    from functools import wraps
    def decorator(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return wrapper
    
    @decorator
    def index():
        '''这是注释index信息'''
        print('from to index')
        return "in the index"
    
    print(index.__doc__)
    # print(help(index))
    复制代码

    5.6.2 一个函数被多个装饰器装饰

      一个函数的多个装饰器,在上面的装饰器先执行,在下面的装饰器后执行

    复制代码
    def timmer(func):
        def wrapper(*args, **kwargs):
            print("this is timmer.")
            res=func(*args,**kwargs)
            return res
        return wrapper
    def auth(auth_type='file'):
        def deco(func):
            def wrapper(*args, **kwargs):
                print("this is auth.")
                return func(*args, **kwargs)
            return wrapper
        return deco
    
    @timmer #index=timmer(wrapper)
    @auth() # @deco #index=deco(index) #wrapper
    def index():
        '''这是index函数'''
        print('welcome to index')
        return "from in index"
    
    index()
    复制代码

    6. 迭代器

    6.1 解析

      迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来;取出序列类型的元素,就是迭代

      序列类型:列表、元组、字符串

      下面的方法按照索引的取值方式,不适用没有索引的数据类型

    l=['aa','bb','cc','dd']
    count=0
    while count < len(l):
        print(l[count])
        count+=1

      不依赖索引方式,进行取值,就是迭代器;迭代非序列类型编程可能。

    6.2可迭代对象

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

    复制代码
    s='hello '                      # 字符串
    l=['a','b','c','d']             # 列表
    t=('a','b','c','d')             # 元组
    dic={'name':'egon','sex':'m'}   # 字典
    set1={1,2,3}                    # 集合
    f=open('db.txt')                # 文件
    
    s.__iter__()
    l.__iter__()
    t.__iter__()
    dic.__iter__()
    set1.__iter__()
    f.__iter__()
    复制代码

    6.3迭代器对象

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

      迭代器:本身也是可迭代对象

      什么是迭代器对象:

        1.有__iter__,执行得到仍然是迭代本身

        2.有__next__方法

    复制代码
    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
    复制代码

    6.4迭代器优缺点

      迭代器对象的优点

        1:提供了一种统一的(不依赖于索引的)迭代方式

        2:迭代器本身,比起其他数据类型更省内存

    复制代码
    l = ['a', 'b', 'c', 'd']
    i = iter(l)
    
    dic = {'a': 1, 'b': 2}
    x = dic.keys()
    print(x)
    i = x.__iter__()  # 执行__iter()__,成为迭代器对象;可以对i执行next()的方法
    
    # 文件是迭代器对象
    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))

    6.5 for循环原理

      for循环遵循迭代器协议,有__iter__方法,还有__next__方法。

      for循环,利用迭代器,进行循环;for,可跟可迭代对象的数据类型;自动进行捕捉异常,自动调用__iter__方法

      例如列表:for循环,先调用__iter__方法,变为迭代器对象,然后再进行循环

      迭代器:有__iter__方法,为for循环准备的。

    复制代码
    l=['a','b','c','d']
    for item in l: #iter_l=l.__iter__()
        print(item)
    
    for item in {1,2,3,4}:   # 可循环集合
        print(item)
    
    with open('a.txt') as f:
        # for line in f: #i=f.__iter__()  可循环文件 把文件变成可迭代对象
        #     print(line)
        print(f is f.__iter__())
    复制代码

    6.6 判断可迭代对象、迭代器对象

      需要利用模块Iterable、Iterator进行判断

    复制代码
    from collections import Iterable,Iterator
    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('a.txt')
    
    # 判断是否可迭代对象;所有对象都是可迭代对象
    print(isinstance(s,Iterable))
    print(isinstance(l,Iterable))
    print(isinstance(t,Iterable))
    print(isinstance(dic,Iterable))
    print(isinstance(set1,Iterable))
    print(isinstance(f,Iterable))
    
    # 判断是否迭代器对象
    print(isinstance(s,Iterator))
    print(isinstance(l,Iterator))
    print(isinstance(t,Iterator))
    print(isinstance(dic,Iterator))
    print(isinstance(set1,Iterator))
    print(isinstance(f,Iterator))   #只有文件是迭代器对象
    复制代码

    7. 生成器

    7.1 简介

      生成器:在函数内部包含yield关键,那么该函数执行的结果是生成器

      生成器就是迭代器

      yield的功能:

        1 把函数的结果做成迭代器(以一种优雅的方式封装好__iter__,__next__)

        2 函数暂停与再继续运行的状态是由yield保存

    7.2 应用实例

    实例1:

    复制代码
    def func():
        print("first")
        yield 111
        print("second")
        yield 222
        print("third")
        yield 333
        print("forth")
    
    g = func()
    from collections import Iterator
    print(isinstance(g,Iterator))          # 生成器就是迭代器
    
    # print(next(g))
    # print('======>')
    # print(next(g))
    # print('======>')
    # print(next(g))
    # print('======>')
    # print(next(g))
    for i in g: #i=iter(g)
        print(i)
    复制代码

    实例2:

      产生无穷无尽的值,是个重复的过程。利用生成器解决此问题。

    复制代码
    def func(n):
        print('我开动啦')
        while True:
            yield n
            n+=1
    g = func(0)    # 没有任何执行效果
    # print(next(g))
    # print(next(g))
    for i in g:
        print(i)
    复制代码

    实例3:

      模拟range功能,在python3中,range只是一个迭代器对象,并没有产生所需数据。

    复制代码
    def my_range(start,stop):
        while True:
            if start == stop:
                raise StopIteration
            yield start
            start+=1
    
    g = my_range(1,5)  # 是个生成器,就是一个迭代器
    print(next(g))
    print(next(g))
    print(next(g))
    
    for i in my_range(1,5):
        print(i)
    复制代码

    7.3 yield与return的比较

      相同:都有返回值的功能

      不同:return只能返回一次值,而yield可以返回多次值

    7.4 模拟tail、grep

    复制代码
    # python3 tail.py -f access.log | grep 'error'
    import time
    
    def tail(filepath):
        with open(filepath, 'r') as f:
            f.seek(0, 2)
            while True:
                line = f.readline()
                if line:
                    yield line
                else:
                    time.sleep(0.2)
    
    def grep(pattern,lines):
        for line in lines:
            if pattern in line:
                print(line,end='')
    
    grep('error',tail('access.log'))
    复制代码

    8. 三元表达式

    复制代码
    def foo(x):
        if x > 3:
            return 'ok'
        else:
            return 'no'
    
    # 利用三元表达式,使代码更简洁
    x = 5
    res = x if x > 3 else 'no'
    print(res)
    
    def max2(x,y):
        return x if x > y else y
    print(max2(1,3))
    
    name='egon'
    print('SB' if name == 'alex' else 'shuai')
    复制代码

    9. 列表解析

      列表解析,也就是列表生成式

      列表解析,直接在列表中,写for循环进行生产列表

    复制代码
    l=[]
    for i in range(10):
         l.append('egg%s' %i)
    print(l)
    
    # 产生10个值的列表
    l=['egg%s' %i for i in range(10)]
    print(l)
    
    # 按照条件,产生一个列表,支持if判断,不支持else
    l=['egg%s' %i for i in range(10) if i > 5]   # 只有条件成立执行,不支持else
    print(l)
    
    # 对原列表进行附加操作,进行生产新列表
    nums=[1,2,3,4,5,6]
    nums_new=[item**2 for item in nums if item > 3]
    print(nums_new)
    
    # 对原列表根据条件进行筛选,生产新列表
    names=['alex_sb','wupeiqi_sb','egon','yuanhao_sb']
    names_new=[name for name in names if name.endswith('sb')]
    print(names_new)
    复制代码

    10. 生成器表达式

      g=('egg%s' %i for i in range(1000))

      上面就是生成器,其实就是迭代器;每次在内存中就只有一条值

      场景:数据量大的场景,

      生成器:就是生成值。

      生成器表达式:就是拿到生产数据的机器。

      实例1:

    g=('egg%s' %i for i in range(1000))
    print(g)
    print(next(g))
    print(next(g))
    print(next(g))

      实例2:

    # 获取文件最长一行的值
    with open('db.txt',encoding='utf-8') as f:
        res = max(len(line) for line in f)     #python提供简写的形式,去掉多余的小括号
        print(res)

      实例3:

        模拟求总价

    复制代码
    with open('a.txt',encoding='utf-8') as f:
        l = ( float(line.split()[1]) * int(line.split()[2]) for line in f)  # 解决文件过大的问题
        print(sum(l))
    #等价于
    with open('a.txt', encoding='utf-8') as f:
        l=[]
        for line in f:
           goods=line.split()
           price=float(goods[1])
           count=int(goods[2])
           cost=price * count
           l.append(cost)
    
        print(sum(l)) #196060.0
    复制代码

      实例4:

        模拟数据库查询,根据条件进行查询

    复制代码
    # [{'name': 'apple', 'price': 333, 'count': 3}, ]
    with open('a.txt',encoding='utf-8') as f:
        info=[
            {
                'name':line.split()[0],
                'price':float(line.split()[1]),
                'count':int(line.split()[2])
            } for line in f if float(line.split()[1]) >= 30000
        ]
        print(info)
    复制代码
  • 相关阅读:
    js幻灯片效果!
    构造函数和析构函数的简单说明
    ASP.NET接口的基础使用例子
    带预览图的js切换效果!
    在win7系统中安装sqlserver2005出现 [Microsoft][SQL Native Client]客户端不支持加密问题!
    Win7开启无线共享上网的方法
    C# 结构体 简明介绍
    C#访问修饰符简单说明
    C#不定长参数的使用
    研究了一下Google Ajax Search API, 给博客做了个样品
  • 原文地址:https://www.cnblogs.com/ldq1996/p/7688493.html
Copyright © 2020-2023  润新知