• Python编程-函数进阶


    一、函数对象

    函数是第一类对象,即函数可以当作数据传递

    1 可以被引用
    2 可以当作参数传递
    3 返回值可以是函数
    4 可以当作容器类型的元素
    
    def foo():
        print('from foo')
    
    func=foo    #将函数赋值给func
    
    print(foo)  #打印函数,将返回函数在内存中的地址
    print(func) #此时func = foo
    func()      #加上大括号才能引用函数
    
    运行结果:
    <function foo at 0x00000000007E00D0>
    <function foo at 0x00000000007E00D0>
    from foo
    
    def foo():
        print('from foo')
    
    def bar(foo):   #给函数bar一个参数foo
        print(foo)  #打印foo,其实就是打印foo函数在内存中的地址
        foo()       #引用foo函数
    
    bar(foo)
    
    运行结果:
    <function foo at 0x00000000006D00D0>
    from foo
    
    def foo():
        print('from foo')
    
    def bar(foo):
        return foo         #返回值是foo函数在内存中的地址
    
    f=bar(foo)
    
    print(f)               #取bar函数的返回值
    
    f()
    
    运行结果:
    <function foo at 0x0000000000D700D0>
    from foo
    
    def foo():
        print('from foo')
    dic={'func':foo}
    
    print(dic['func'])     #打印字典key名为func的值foo,也就是foo函数在内存中的地址
    
    dic['func']()          #调用foo函数
    
    运行结果:
    <function foo at 0x00000000007C00D0>
    from foo
    

    应用

    def select(sql):
        print('========>select')
    
    def insert(sql):
        print('========>add')
    
    def delete(sql):
        print('=======>delete')
    
    def update(sql):
        print('-=---->update')
    
    
    func_dic={
        'select':select,
        'update':update,
        'insert':insert,
        'delete':delete
    }
    
    def main():
        while True:
            sql = input('>>: ').strip()
            if not sql:continue
            l = sql.split()
            cmd=l[0]
            if cmd in func_dic:
                func_dic[cmd](l)
    
    main()
    def main():
        sql = input('>>: ')
        l = sql.split()
        print(l)
        if l[0] == 'select':
            select(l)
        elif l[0] == 'insert':
            insert(l)
        elif l[0] == 'delete':
            delete(l)
        elif l[0] == 'update':
            update(l)
    

    二、函数的嵌套

    1.函数的嵌套调用
    def max2(x,y):                #取最大值
        return x if x > y else y
    
    def max4(a,b,c,d):
        res1=max2(a,b)            #两两比较,取最大值
        res2=max2(res1,c)
        res3=max2(res2,d)
        return res3
    
    print(max4(10,99,31,22))
    
    运行结果:
    99
    
    name = "Alex"
    
    def change_name():                    #先调用这层 
        name = "Alex2"
    
        def change_name2():               #再调用这层 
            name = "Alex3"
            print("第3层打印", name)
    
        change_name2()  # 调用内层函数    
        print("第2层打印", name)
    
    change_name()
    print("最外层打印", name)             #最后到这层
    
    运行结果:
    第3层打印 Alex3
    第2层打印 Alex2
    最外层打印 Alex
    
    2.函数的嵌套定义

    注意:定义函数在运行程序时不会执行,仅判断语法是否有错误

    def f1():
    
        def f2():
            print('from f2')
            def f3():
                print('from f3')
            f3()
        f2()
    
    f1()
    
    运行结果:
    from f2
    from f3
    

    三、名称空间与作用域

    1.定义名字的方法
    import time
    
    name='egon'
    
    def func():
        pass
    
    class Foo:
        pass
    
    2.三种名称空间
    (1)内置名称空间

    随着python解释器的启动而产生,內建函数属于内置名称空间内

    print(sum)
    print(max)
    print(min)
    
    print(max([1,2,3]))
    
    import builtins
    for i in dir(builtins):      #查看內建函数
        print(i)
    
    (2)全局名称空间

    文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间

    x=1
    if x ==1 :
        y=2
    import time
    
    name='egon'
    
    def func():
        pass
    
    class Foo:
        pass
    
    x=1
    
    def func():
        money=2000
        x=2
        print('func')
    print(x)
    print(func)
    func()
    print(money)       #money属于func函数内的局部命名空间
    
    func()
    print(x)
    
    报错信息:
    Traceback (most recent call last):
    1
      File "E:/s17/day04/名称空间与作用域.py", line 59, in <module>
        print(money)
    <function func at 0x00000000007B00D0>
    NameError: name 'money' is not defined
    func
    
    (3)局部名称空间

    调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解绑定

    x=10000          #全局
    def func():
        x=1          #局部
        def f1():
            pass
    

    3.作用域

    (1)全局作用域:内置名称空间,全局名层空间
    (2)局部作用:局部名称空间

    名字的查找顺序:局部名称空间---》全局名层空间---》内置名称空间

    x=1
    def func():
        x=2
        print(x)
        sum=123123
        print(sum)
    func()
    
    运行结果:
    2
    123123
    
    def func():
        x=2
    
    func()
    print(x)     #此时调用不到x
    
    报错信息:
    Traceback (most recent call last):
      File "E:/s17/day04/名称空间与作用域.py", line 94, in <module>
        print(x)
    NameError: name 'x' is not defined
    

    查看全局作用域内的名字:gloabls()

    查看局局作用域内的名字:locals()

    x=1000
    def func():
        x=2
    
    print(globals())
    
    print(locals())
    print(globals() is locals())
    
    运行结果:
    {'func': <function func at 0x00000000007D00D0>, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000626DA0>, '__spec__': None, 'x': 1000, '__cached__': None, '__doc__': '
    作用域:
        1. 全局作用域:内置名称空间,全局名层空间
        2. 局部作用:局部名称空间
    ', '__builtins__': <module 'builtins' (built-in)>, '__package__': None, '__file__': 'E:/s17/day04/名称空间与作用域.py', '__name__': '__main__'}
    {'func': <function func at 0x00000000007D00D0>, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000626DA0>, '__spec__': None, 'x': 1000, '__cached__': None, '__doc__': '
    作用域:
        1. 全局作用域:内置名称空间,全局名层空间
        2. 局部作用:局部名称空间
    ', '__builtins__': <module 'builtins' (built-in)>, '__package__': None, '__file__': 'E:/s17/day04/名称空间与作用域.py', '__name__': '__main__'}
    True
    
    x=1000
    def func(y):
        x=2
        print(locals())
        print(globals())
    
    func(1)
    
    运行结果:
    {'y': 1, 'x': 2}
    {'__file__': 'E:/s17/day04/名称空间与作用域.py', '__doc__': '
    作用域:
        1. 全局作用域:内置名称空间,全局名层空间
        2. 局部作用:局部名称空间
    ', '__package__': None, 'func': <function func at 0x00000000007E00D0>, '__name__': '__main__', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000646DA0>, '__builtins__': <module 'builtins' (built-in)>, 'x': 1000, '__cached__': None, '__spec__': None}
    

    全局作用域:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕

    局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效

    x=1
    
    def f1():
        print(x)
    
    def foo():
        print(x)
    
    def f(x):
        # x=4
        def f2():
            # x=3
            def f3():
                # x=2
                print(x)
    
            f3()
        f2()
    
    f(4)
    
    运行结果:
    4
    

    四、闭包

    1. 定义在内部函数
    2. 包含对外部作用域而非全局作用域的引用,该内部函数就成为闭包函数
    def f1():
        x = 1
        def f2():
            print(x)
        return f2
    
    f=f1()
    print(f)
    
    x=100000000000000000000000000
    f()
    
    运行结果:
    <function f1.<locals>.f2 at 0x00000000006B01E0>
    1
    

    闭包应用:惰性计算

    抓取网页

    from urllib.request import urlopen
    
    def index(url):
        def get():
            return urlopen(url).read()
    
        return get
    
    oldboy=index('http://crm.oldboyedu.com')
    
    print(oldboy().decode('utf-8'))
    print(oldboy.__closure__[0].cell_contents)
    
    res=urlopen('http://crm.oldboyedu.com').read()
    
    print(res.decode('utf-8'))
    
    x=1
    y=2
    def f1():
        x=1
        y=2
        def f2():
            print(x,y)
        return f2
    
    f=f1()
    print(f.__closure__[0].cell_contents)
    
    运行结果:
    1
    

    五、装饰器

    装饰器:修饰别人的工具,修饰添加功能,工具指的是函数

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

    为什么要用装饰器:

    • 开放封闭原则:对修改是封闭的,对扩展是开放的
    • 装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为期添加新功能

    在修改代码时,为了不对源代码产生影响而使用装饰器

    import time
    
    def timmer(func):                 #增加执行时间计算
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
        return wrapper
    
    @timmer                           #对源代码进行装饰,index=timmer(index)
    def index():
    
        time.sleep(3)
        print('welcome to index')
    
    f=timmer(index)
    print(f)
    f()                              #wrapper()---->index()
    
    index=timmer(index)              #index==wrapper
    
    index() #wrapper()----->
    

    流程分析

    import time
    def timmer(func):
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    @timmer                          #装饰器 index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
        return 1
    
    @timmer
    def foo(name):
        time.sleep(1)
        print('from foo')
    
    
    res=index()                      #wrapper()
    print(res)
    
    res1=foo('egon')                 #res1=wrapper('egon')
    print(res1)
    
    运行结果:
    welcome to index
    run time is 3.012805223464966
    1
    from foo
    run time is 1.0140018463134766
    None
    

    应用

    login_user={'user':None,'status':False}
    def auth(func):
        def wrapper(*args,**kwargs):
            if login_user['user'] and login_user['status']:
                res=func(*args,**kwargs)
                return res
            else:
                name=input('>>: ')
                password=input('>>: ')
                if name == 'egon' and password == '123':
                    login_user['user']='egon'
                    login_user['status']=True
                    print('33[45mlogin successful33[0m')
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('33[45mlogin err33[0m')
        return wrapper
    
    @auth
    def index():
        print('welcome to index page')
    @auth
    def home(name):
        print('%s welcome to home page' %name)
    
    index()
    home('egon')
    

    有参装饰器

    import time
    def timmer(func):
        def wrapper(*args,**kwargs):
            print('====>timmer.wrapper')
            start_time=time.time()
            res=func(*args,**kwargs)                         #auth_wrapper
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    login_user={'user':None,'status':False}
    def auth(driver='file'):
        def auth2(func):
            def wrapper(*args,**kwargs):
                print('=======>auth.wrapper')
                time.sleep(5)
                if driver == 'file':
                    if login_user['user'] and login_user['status']:
                        res=func(*args,**kwargs)
                        return res
                    else:
                        name=input('>>: ')
                        password=input('>>: ')
                        if name == 'egon' and password == '123':
                            login_user['user']='egon'
                            login_user['status']=True
                            print('33[45mlogin successful33[0m')
                            res=func(*args,**kwargs)
                            return res
                        else:
                            print('33[45mlogin err33[0m')
                elif driver == 'ldap':
                    print('==========ldap的认证')
                elif driver == 'mysql':
                    print('==========mysql的认证')
                    return func(*args,**kwargs)
                else:
                    print('=========未知的认证来源')
            return wrapper
        return auth2
    
    @auth('file')                  #@auth2====>index=auth2(index)===>index=auth_wrapper
    @timmer                        #index=timmer(auth_wrapper) #index=timmer_wrapper
    def index():
        time.sleep(3)
        print('welcome to index page')
    @auth(driver='mysql')
    def home(name):
        print('%s welcome to home page' %name)
    index()                       #timmer_wrapper()
    home('egon') #wrapper('egon')
    

    六、迭代器

    迭代的概念:重复+上一次迭代的结果为下一次迭代的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值

    迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件

    特点:

    • 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
    • 不能随机访问集合中的某个值 ,只能从头到尾依次访问
    • 访问到一半时不能往回退
    • 便于循环比较大的数据集合,节省内存
    while True: #只满足重复,因而不是迭代
        print('====>')
    

    真正的迭代如下:

    l = [1, 2, 3]
    count = 0
    while count < len(l):  
        print('====>', l[count])
        count += 1
    
    l = (1, 2, 3)
    count = 0
    while count < len(l):  
        print('====>', l[count])
        count += 1
    
    s='hello'
    count = 0
    while count < len(s):
        print('====>', s[count])
        count += 1
    

    为什么要有迭代器?对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式

    可迭代的对象:内置__iter__方法的,都是可迭代的对象

    [1,2].__iter__()
    'hello'.__iter__()
    (1,2).__iter__()
    
    {'a':1,'b':2}.__iter__()
    {1,2,3}.__iter__()
    

    迭代器:执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法

    i=[1,2,3].__iter__()
    
    print(i)
    
    print(i.__next__())
    print(i.__next__())
    print(i.__next__())
    print(i.__next__()) #抛出异常:StopIteration
    
    dic={'a':1,'b':2,'c':3}
    i=dic.__iter__()
    while True:
        try:
            key=i.__next__()
            print(dic[key])
        except StopIteration:
            break
    
    如何判断一个对象是可迭代的对象,还是迭代器对象

    from collections import Iterable,Iterator

    'abc'.iter()
    ().iter()
    [].iter()
    {'a':1}.iter()
    {1,2}.iter()

    f=open('a.txt','w')
    f.iter()

    下列数据类型都是可迭代的对象,只有文件是迭代器对象

    print(isinstance('abc',Iterable))
    print(isinstance([],Iterable))
    print(isinstance((),Iterable))
    print(isinstance({'a':1},Iterable))
    print(isinstance({1,2},Iterable))
    print(isinstance(f,Iterable))

    可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象

    迭代协议:

    • 对象有__next__
    • 对象有__iter__,对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身

    迭代器的优点和缺点

    优点:

    • 提供了一种不依赖下标的迭代方式
    • 就跌迭代器本身来说,更节省内存

    缺点:

    • 无法获取迭代器对象的长度
    • 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退

    七、生成器

    生成器函数:只要函数体包含yield关键字,该函数就是生成器函数
    生成器就是迭代器

    一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器;

    def func():
        yield 1
        yield 2
        yield 3
        yield 4
    

    上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。

    运行结果:
    >>> temp = func()
    >>> temp.__next__()
    1
    >>> temp.__next__()
    2
    >>> temp.__next__()
    3
    >>> temp.__next__()
    4
    >>> temp.__next__()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    
    def foo():
        print('first')
        yield 1
        print('second')
        yield 2
        print('third')
        yield 3
        print('fourth')
        yield 4
        print('fifth')
    
    g=foo()
    for i in g:
        print(i)
    print(next(g))      #触发迭代器g的执行,进而触发函数的执行
    
    运行结果:
    first
    1
    second
    2
    third
    3
    fourth
    4
    fifth
    

    yield的功能:

    • 相当于为函数封装好__iter__和__next__
    • return只能返回一次值,函数就终止了,而yield能返回多次值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行

    应用:tail -f a.txt | grep 'python'

    import time
    def tail(filepath):
        with open(filepath,encoding='utf-8') as f:
            f.seek(0,2)
            while True:
                line=f.readline().strip()
                if line:
                    yield line
                else:
                    time.sleep(0.2)
    
    t=tail('a.txt')
    
    for line in t:
        print(line)
    				
    def grep(pattern,lines):
        for line in lines:
            if pattern in line:
                yield line
                
    g=grep('python',tail('a.txt'))
    print(g)
    
    for i in g:
        print(i)
    

    八、递归

    在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身

    def calc(n):
        print(n)
        if int(n/2) ==0:
            return n
        return calc(int(n/2))
     
    calc(10)
    
    运行结果:
    10
    5
    2
    1
    

    应用:递归问路

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    import time
    
    person_list=['alex','wupeiqi','yuanhao','linhaifeng']
    def ask_way(person_list):
        print('-'*60)
        if len(person_list) == 0:
            return '没人知道'
        person=person_list.pop(0)
        if person == 'linhaifeng':
            return '%s说:我知道,老男孩就在沙河汇德商厦,下地铁就是' %person
        print('hi 美男[%s],敢问路在何方' %person)
        print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' %(person,person_list))
        time.sleep(3)
        res=ask_way(person_list)
        # print('%s问的结果是: %res' %(person,res))
        return res
    
    
    
    res=ask_way(person_list)
    
    print(res)
    

    递归特性:

    • 必须有一个明确的结束条件

    • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

    • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

    九、内置函数

    内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii

  • 相关阅读:
    关于MySQL与SQLLite的Group By排序原理的差别
    利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包括增删改查、JavaBean反射原理,附源代码)
    深入java并发Lock一
    windows 7 SDK和DDK下载地址
    用cocos2d-x 3.2 实现的FlappyBird
    Java替代C语言的可能性
    Spring Quartz结合Spring mail定期发送邮件
    web小流量实验方案
    paip.微信菜单直接跳转url和获取openid流程总结
    【java web】java运行预编译Groovy脚本
  • 原文地址:https://www.cnblogs.com/tongxiaoda/p/7595733.html
Copyright © 2020-2023  润新知