python 函数

一:为何用函数之不使用函数的问题
    #组织结构不清晰
    #代码冗余
    #无法统一管理且维护难度大


二:函数分类:
    1. 内置函数
    2. 自定义函数


三:为何要定义函数
    函数即变量,变量必须先定义后使用,未定义而直接引用函数,就相当于在引用一个不存在的变量名
    代码演示?

四:定义函数都干了哪些事?
    只检测语法,不执行代码


五:如何定义函数(函数名要能反映其意义)
    def ...


六:定义函数的三种形式
    无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
    有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
    空函数:设计代码结构


七 :函数的调用
    1 先找到名字
    2 根据名字调用代码

八:函数调用的三种形式
  1 语句形式:foo()
  2 表达式形式:3*len('hello')
  4 当中另外一个函数的参数:range(len('hello'))

九:函数的参数:
 1 形参和实参定义
 2 形参即变量名,实参即变量值,函数调用则将值绑定到名字上,函数调用结束,解除绑定
 3 具体应用
    位置参数:按照从左到右的顺序定义的参数
        位置形参:必选参数
        位置实参:按照位置给形参传值

    关键字参数:按照key=value的形式定义实参
        无需按照位置为形参传值
        注意的问题:
                1. 关键字实参必须在位置实参右面
                2. 对同一个形参不能重复传值

    默认参数:形参在定义时就已经为其赋值
        可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
        注意的问题:
                1. 只在定义时赋值一次
                2. 默认参数的定义应该在位置形参右面
                3. 默认参数通常应该定义成不可变类型


    可变长参数:
        针对实参在定义时长度不固定的情况,应该从形参的角度找到可以接收可变长实参的方案,这就是可变长参数(形参)
        而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参也应该有两种解决方案,分别是*args,**kwargs

        ===========*args===========
        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,3,4,5)

        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,*[3,4,5])


        def foo(x,y,z):
            print(x,y,z)
        foo(*[1,2,3])

        ===========**kwargs===========
        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,a=1,b=2,c=3)

        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,**{'a':1,'b':2,'c':3})


        def foo(x,y,z):
            print(x,y,z)
        foo(**{'z':1,'x':2,'y':3})

        ===========*args+**kwargs===========

        def foo(x,y):
            print(x,y)

        def wrapper(*args,**kwargs):
            print('====>')
            foo(*args,**kwargs)

    命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
        可以保证,传入的参数中一定包含某些关键字
        def foo(x,y,*args,a=1,b,**kwargs):
            print(x,y)
            print(args)
            print(a)
            print(b)
            print(kwargs)

        foo(1,2,3,4,5,b=3,c=4,d=5)
        结果:
            1
            2
            (3, 4, 5)
            1
            3
            {'c': 4, 'd': 5}


=======================本节课新内容==========================
    一:函数对象:函数是第一类对象,即函数可以当作数据传递
    1 可以被引用
    2 可以当作参数传递
    3 返回值可以是函数
    3 可以当作容器类型的元素
        #利用该特性,优雅的取代多分支的if
        def foo():
            print('foo')

        def bar():
            print('bar')

        dic={
            'foo':foo,
            'bar':bar,
        }
        while True:
            choice=input('>>: ').strip()
            if choice in dic:
                dic[choice]()

    二:函数的嵌套
        1 函数的嵌套调用
            def max(x,y):
                return x if x > y else y

            def max4(a,b,c,d):
                res1=max(a,b)
                res2=max(res1,c)
                res3=max(res2,d)
                return res3
            print(max4(1,2,3,4))

        2 函数的嵌套定义
            def f1():
                def f2():
                    def f3():
                        print('from f3')
                    f3()
                f2()

            f1()
            f3() #报错


    三 名称空间和作用域:
        名称空间:存放名字的地方,三种名称空间,加载顺序是?
        名字的查找顺序
        作用域即范围(作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关)

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

        global
        nonlocal


        LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
        locals 是函数内的名字空间,包括局部变量和形参
        enclosing 外部嵌套函数的名字空间(闭包中常见)
        globals 全局变量,函数定义所在模块的名字空间
        builtins 内置模块的名字空间



    四:闭包:内部函数包含对外部作用域而非全局作用域的引用

        def counter():
            n=0
            def incr():
                nonlocal n
                x=n
                n+=1
                return x
            return incr

        c=counter()
        print(c())
        print(c())
        print(c())
        print(c.__closure__[0].cell_contents) #查看闭包的元素



    闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
    应用领域:延迟计算
    from urllib.request import urlopen

    def index(url):
        def get():
            return urlopen(url).read()
        return get

    baidu=index('http://www.baidu.com')
    print(baidu().decode('utf-8'))


    五: 装饰器

    1 为何要用装饰器:
        开放封闭原则:对修改封闭,对扩展开放

    2 什么是装饰器
       装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。

    3. 先看简单示范
        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
        def foo():
            time.sleep(3)
            print('from foo')
        foo()


    4
    def auth(driver='file'):
        def auth2(func):
            def wrapper(*args,**kwargs):
                name=input("user: ")
                pwd=input("pwd: ")

                if driver == 'file':
                    if name == 'egon' and pwd == '123':
                        print('login successful')
                        res=func(*args,**kwargs)
                        return res
                elif driver == 'ldap':
                    print('ldap')
            return wrapper
        return auth2

    @auth(driver='file')
    def foo(name):
        print(name)

    foo('egon')

    5 装饰器语法:
        被装饰函数的正上方,单独一行
        @deco1
        @deco2
        @deco3
        def foo():
            pass

        foo=deco1(deco2(deco3(foo)))



    六:迭代器
        迭代的概念:重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
            # while True: #只满足重复,因而不是迭代
            #     print('====>')

            #迭代
            l=[1,2,3]
            count=0
            while count < len(l): #只满足重复,因而不是迭代
                print('====>',l[count])
                count+=1


        为何要有迭代器?
        可迭代的对象?
        哪些是可迭代对象?
        迭代器?
            l={'a':1,'b':2,'c':3,'d':4,'e':5}
            i=l.__iter__() #等于i=iter(l)

            print(next(i))
            print(next(i))
            print(next(i))
        StopIteration?

        for循环

        迭代器的优缺点:
            优点:
                提供统一的且不依赖于索引的迭代方式
                惰性计算,节省内存
            缺点:
                无法获取长度
                一次性的,只能往后走,不能往前退

        迭代器协议



   七 生成器
   yield:
    把函数做成迭代器
    对比return,可以返回多次值,挂起函数的运行状态



    # def foo():
    #     return 1
    #     return 2
    #     return 3
    #
    # res=foo()
    # print(res)


    def foo():
        yield 1
        yield 2
        yield 3

    res=foo()
    print(res)

    from collections import Iterable,Iterator
    print(isinstance(res,Iterator))

    print(next(res))
    print(next(res))
    print(next(res))


    应用一:
        def counter(n):
            print('start')
            i=0
            while i < n:
                yield i
                i+=1
            print('end')

        c=counter(5)
        # print(next(c)) #0
        # print(next(c)) #1
        # print(next(c)) #2
        # print(next(c)) #3
        # print(next(c)) #4
        # print(next(c)) #5 --->没有yield,抛出StopIteration


        for i in counter(5):
            print(i)

    应用二:管道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()
                if line:
                    yield line
                else:
                    time.sleep(0.5)

    def grep(pattern,lines):
        for line in lines:
            if pattern in line:
                yield line

    for i in grep('python',tail('a.txt')):
        print(i)


    #协程函数
        def eater(name):
            print('客人%s来吃饭了' %name)
            food_list=[]
            while True:
                food=yield food_list
                food_list.append(food)
                print('%s 吃了 %s' %(name,food))

        e=eater('egon')
        e.send(None) #next(e) #初始化装饰器,
        e.close() #关闭

    面向过程编程:
        import os
        def init(func):
            def wrapper(*args,**kwargs):
                g=func(*args,**kwargs)
                next(g)
                return g
            return wrapper



        def search(file_dir,target):
            for par_dir,_,files in os.walk(file_dir):
                for file in files:
                    filepath='%s\%s' %(par_dir,file)
                    target.send(filepath)

        @init
        def opener(target):
            while True:
                filepath=yield
                with open(filepath) as f:
                    target.send((f,filepath))
        @init
        def cat(target):
            while True:
                res=False
                f,filepath=yield res
                for line in f:
                    print(line,end='')
                    res=target.send((line,filepath))
                    if res:
                        break


        @init
        def grep(pattern,target):
            res = False
            while True:
                line,filepath=yield res
                res=False
                if pattern in line:
                    res=True
                    target.send(filepath)

        @init
        def printer():
            while True:
                filepath=yield
                print(filepath)

        search(r'C:\Users\Administrator\PycharmProjects\test\字符编码\a',
               opener(cat(grep('python',printer()))))



    八:生成器表达式
        with open(r'C:\Users\Administrator\PycharmProjects\test\字符编码\spider.py',encoding='utf-8') as f:
        g=max(len(line.strip()) for line in f)
        print(g)


    九:函数的递归调用
        图解:递推和回溯

        # salary(5)=salary(4)+300
        # salary(4)=salary(3)+300
        # salary(3)=salary(2)+300
        # salary(2)=salary(1)+300
        # salary(1)=100
        #
        # salary(n)=salary(n-1)+300     n>1
        # salary(1) =100                n=1

        def salary(n):
            if n == 1:
                return 100
            return salary(n-1)+300

        print(salary(5))


    十:二分法
        l=[1,2,10,2,30,40,33,22,99,31]
        def search(num,l):
            print(l)
            if len(l) > 1:
                mid=len(l)//2
                if num > l[mid]:
                    #in the right
                    l=l[mid:]
                    search(num,l)
                elif num < l[mid]:
                    #in the left
                    l=l[:mid]
                    search(num,l)
                else:
                    print('find it')
            else:
                if num == l[0]:
                    print('find it')
                else:
                    print('not exists')

        search(100,l)

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29896444/viewspace-2139915/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29896444/viewspace-2139915/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值