美文网首页
py_23 面向过程编程和函数式

py_23 面向过程编程和函数式

作者: 阿登20 | 来源:发表于2020-08-20 20:14 被阅读0次
    一 编程范式
    编程范式指的就是编程的套路,打个比方,如果把编程的过程比喻为练习武功,那编程范式指的就是武林中的各种流派,而在编程的世界里常见的流派有:`面向过程、函数式、面向对象`
    二 面向过程
        面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么
        优点:复杂的问题流程化,进而简单化
        缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身
    三 函数式
    lambda: lambda 参数1,参数2: 表达式
        调用:
        1.res=(lambda x,y,z:x+y+z)(1,2,3)
        2.func=lambda x,y,z:x+y+z   res=func(1,2,3)
    
     有名字的函数与匿名函数的对比
        有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能
        匿名函数:一次性使用,随时随时定义
       应用: max,min,sorted,map,reduce,filter
        
            max(iterable, key=lambda k:dict[k])
            min(iterable, key=lambda k:dict[k])
            sorted(iterable,key=lambda k:dict[k],reverse=True)  False 升序 返回是一个新列表
            map(lambda x:x*2, iterable) 映射 得到一个迭代器对象
            filter(lambda x:x>3, iterable) 过滤不满足函数返回条件x>3的,得到一个迭代器对象
            reduce(lambda x,y:x+y,[2,4,6],1) 累加操作或字符串拼接 返回值是一个合并之后的结果
            
    
    

    一 编程范式

    很多初学者在了解了一门编程语言的基本语法和使用之后,面对一个’开发需求‘时仍然会觉得无从下手、没有思路/套路,本节主题“编程范式”正是为了解决该问题,那到底什么是编程范式呢?

    编程范式指的就是编程的套路,打个比方,如果把编程的过程比喻为练习武功,那编程范式指的就是武林中的各种流派,而在编程的世界里常见的流派有:面向过程、函数式、面向对象

    在正式介绍前,我们需要强调:“功夫的流派没有高低之分,只有习武的人才有高低之分“,在编程世界里更是这样,各种编程范式在不同的场景下都各有优劣,谁好谁坏不能一概而论,下面就让我们来一一解读它们。

    二 面向过程

    2.1 定义

    面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么
    基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式

    2.2优点:

    复杂的问题流程化,进而简单化

    2.3缺点:

    可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身

    2.4应用:

    函数的参数传入,是函数吃进去的食物,而函数return的返回值,是函数拉出来的结果,
    面向过程的思路就是,把程序的执行当做一串首尾相连的功能,该功能可以是函数的形式,
    然后一个函数吃,拉出的东西给另外一个函数吃,另外一个函数吃了再继续拉给下一个函数吃.

    扩展性要求不高的场景,典型案例如linux内核,git,httpd

    举例
    流水线1:
    用户输入用户名、密码--->用户验证--->欢迎界面
    
    流水线2:
    用户输入sql--->sql解析--->执行功能
    复制代码
    """
    
    
    #=============复杂的问题变得简单
    #注册功能:
    #阶段1: 接收用户输入账号与密码,完成合法性校验
    def talk():
        while True:
            username=input('请输入你的用户名: ').strip()
            if username.isalpha():
                break
            else:
                print('用户必须为字母')
    
        while True:
            password1=input('请输入你的密码: ').strip()
            password2=input('请再次输入你的密码: ').strip()
            if password1 == password2:
                break
            else:
                print('两次输入的密码不一致')
    
        return username,password1
    
    #阶段2: 将账号密码拼成固定的格式
    def register_interface(username,password):
        format_str='%s:%s\n' %(username,password)
        return format_str
    
    #阶段3: 将拼好的格式写入文件
    def handle_file(format_str,filepath):
        with open(r'%s' %filepath,'at',encoding='utf-8') as f:
            f.write(format_str)
    
    
    def register():
        user,pwd=talk()
        format_str=register_interface(user,pwd)
        handle_file(format_str,'user.txt')
    
    
    register()
    
    
    #=============牵一发而动全身,扩展功能麻烦
    #阶段1: 接收用户输入账号与密码,完成合法性校验
    def talk():
        while True:
            username=input('请输入你的用户名: ').strip()
            if username.isalpha():
                break
            else:
                print('用户必须为字母')
    
        while True:
            password1=input('请输入你的密码: ').strip()
            password2=input('请再次输入你的密码: ').strip()
            if password1 == password2:
                break
            else:
                print('两次输入的密码不一致')
    
    
        role_dic={
            '1':'user',
            '2':'admin'
        }
        while True:
            for k in role_dic:
                print(k,role_dic[k])
    
            choice=input('请输入您的身份>>: ').strip()
            if choice not in role_dic:
                print('输入的身份不存在')
                continue
            role=role_dic[choice]
    
        return username,password1,role
    
    #阶段2: 将账号密码拼成固定的格式
    def register_interface(username,password,role):
        format_str='%s:%s:%s\n' %(username,password,role)
        return format_str
    
    #阶段3: 将拼好的格式写入文件
    def handle_file(format_str,filepath):
        with open(r'%s' %filepath,'at',encoding='utf-8') as f:
            f.write(format_str)
    
    
    def register():
        user,pwd,role=talk()
        format_str=register_interface(user,pwd,role)
        handle_file(format_str,'user.txt')
    
    
    register()
    
    
    #ps:talk内对用户名\密码\角色的合法性校验也可以摘出来做成单独的功能,
    # 但本例就写到一个函数内了,力求用更少的逻辑来为大家说明过程式编程的思路
    
    # 示例:复杂的问题变得简单,但扩展功能麻烦
    

    三 函数式

    函数式编程并非用函数编程这么简单,而是将计算机的运算视为数学意义上的运算,比起面向过程,函数式更加注重的是执行结果而非执行的过程,代表语言有:Haskell、Erlang。而python并不是一门函数式编程语言,但是仍为我们提供了很多函数式编程好的特性,如lambda,map,reduce,filter

    3.1 匿名函数与lambda

    对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下

    lambda 参数1,参数2,...: expression
    

    举例

    # 1、定义
    #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
    lambda x,y,z:x+y+z  
    
    #等同于
    def func(x,y,z):
        return x+y+z
    
    # 2、调用
    # 方式一:
    res=(lambda x,y,z:x+y+z)(1,2,3)
    
    # 方式二:
    func=lambda x,y,z:x+y+z # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的
    res=func(1,2,3)
    
    lambda 格式 说明
    lambda x, y: x*y 函数输入是 x 和 y,输出是它们的积 x*y
    lambda :None 函数没有输入参数,输出是 None
    lambda :aaa(3,4) 函数没有输入参数,输出是 aaa(3,4)的结 果
    lambda *args:sum(args) 输入是任意个数的参数,输出是它们的和
    lamdba **kwargs : 1 输入是任意键值对参数,输出是 1

    有名字的函数与匿名函数的对比

    #有名函数与匿名函数的对比
    有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能
    
    匿名函数:一次性使用,随时随时定义
    
    应用:max,min,sorted,map,reduce,filter
    

    案例1

    如果有这样一个列表[1,2,3,4,5,6,7,8,9,10] ,
    现在需要将列表里的每个元素乘以2,应该怎么做呢?

    # 方式一
    a = [1,2,3,4,5,6,7,8,9,10]
    for m,n in enumerate(a):
        a[m] = n*2
    print(a)
    
    # 方式2 map(func,iterable)
    new_a = list(map(lambda x:x*2, a))
    print(new_a)
    
    # 方式3
    b = [x*2 for x in a]
    print(b)
    

    案例2

    匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用,我们以下述字典为例来介绍它

    salaries={
        'siry':3000,
        'tom':7000,
        'lili':10000,
        'jack':2000
    }
    

    要想取得薪水的最大值和最小值,我们可以使用内置函数max和min(为了方便开发,python解释器已经为我们定义好了一系列常用的功能,称之为内置的函数,我们只需要拿来使用即可)

    >>> max(salaries)
    'tom'
    >>> min(salaries)
    'jack'
    

    内置max和min都支持迭代器协议,工作原理都是迭代字典,取得是字典的键,因而比较的是键的最大和最小值,而我们想要的是比较值的最大值与最小值,于是做出如下改动

    # 函数max会迭代字典salaries,每取出一个“人名”就会当做参数传给指定的匿名函数,然后将匿名函数的返回值当做比较依据,最终返回薪资最高的那个人的名字
    
    
    salaries={
        'siry':3000,
        'tom':7000,
        'lili':10000,
        'jack':2000
    # max工作原理:迭代iterable 还回元素,key 比较依据。
    a = max(salaries, key=lambda k:salaries[k])
    print(a)  # lili
    b = min(salaries, key=lambda k:salaries[k])
    print(b)  # jack
    

    同理,我们直接对字典进行排序,默认也是按照字典的键去排序的

    >>> sorted(salaries)
    ['jack', 'lili', 'siry', 'tom']
    

    3.2 sorted() 排序

    salaries={
        'siry':3000,
        'tom':7000,
        'lili':10000,
        'jack':2000
    }
    # sorted(iterable,key=None,reverse=False) 返回一个新列表 默认升序 True降序
    list1 = sorted(salaries,key=lambda k:salaries[k],reverse=True)
    print(list1[0])
    

    3.3 map、reduce、filter

    • map 返回是一个迭代器对象

    • reduce 返回是一个合并过后的值

    • filter 返回是一个迭代器对象

    函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象,我们以一个可迭代对象array为例来介绍它们三个的用法

    array=[1,2,3,4,5]
    

    要求一:对array的每个元素做平方处理,可以使用map函数

    map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下

    >>> array=[1,2,3,4,5
    >>> res=map(lambda x:x**2,array)
    >>> res
    <map object at 0x1033f45f8>
    >>>
    

    解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器。

    >>> list(res) #使用list可以依次迭代res,取得的值作为列表元素
    [1, 4, 9, 16, 25]
    

    要求二:对array进行合并操作,比如求和运算,这就用到了reduce函数

    reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值

    # reduce在python2中是内置函数,在python3中则被集成到模块functools中,需要导入才能使用
    >>> array=[1,2,3,4,5
    >>> from functools import reduce 
    >>> res=reduce(lambda x,y:x+y,array)
    >>> res
    15
    

    解析:

    1 没有初始值,reduce函数会先迭代一次array得到的值作为初始值,作为第一个值数传给x,然后继续迭代一次array得到的值作为第二个值传给y,运算的结果为3

    2 将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果作为第二个值传给y,依次类推,知道迭代完array的所有元素,得到最终的结果15

    也可以为reduce指定初始值

    >>> array=[1,2,3,4,5]
    >>> res=reduce(lambda x,y:x+y,array,100)>>> res
    115
    

    要求三:对array进行过滤操作,这就用到了filter函数,比如过滤出大于3的元素

    >>> array=[1,2,3,4,5
    >>> res=filter(lambda x:x>3,array)
    

    解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器。

    >>> list(res) 
    [4, 5]
    

    提示:我们介绍map、filter、reduce只是为了带大家了解函数式编程的大致思想,在实际开发中,我们完全可以用列表生成式或者生成器表达式来实现三者的功能。

    演示代码

    # ---------------------------map()映射--------------------
    # map(func,iterabal) 映射
    L = ["ab","fdsa","dasf","faf","fea","fafa"]
    # 需求 将L里面的元素后缀加上SB
    # 方法1
    L = [x+"SB" for x in L]
    print(L) # ['abSB', 'fdsaSB', 'dasfSB', 'fafSB', 'feaSB', 'fafaSB']
    
    # 方法2
    L = map(lambda x :x+"SB", L) # map返回是一个迭代器对象
    print(L) # <map object at 0x000000000227B160>
    print(list(L)) # ['abSBSB', 'fdsaSBSB', 'dasfSBSB', 'fafSBSB', 'feaSBSB', 'fafaSBSB']
    
    
    #-------------------------------filter过滤-------------------------
    
    # filter(func, iterable) 返回是一个 迭代器对象
    L = ['ab', 'fdsa', 'dasfSb', 'faf', 'feaSB', 'fafaSB']
    # 过滤掉SB
    # 方法1
    res = [x for x in L if x.lower().endswith("sb")]
    print(res) # ['dasfSb', 'feaSB', 'fafaSB']
    
    # 方法2
    res = filter(lambda x:x.lower().endswith("sb"), L)
    print(list(res)) # ['dasfSb', 'feaSB', 'fafaSB']
    
    
    #------------------reduce合并操作--------------
    from functools import reduce
    # 累加操作 reduce(function, sequence, initial=None)
    res = reduce(lambda x,y:x+y,[2,4,6],1)
    """
    x=1,y=2传进函数 得到的返回值 3赋值给x
    x=3,y=4
    x=7,y=6
    res = reduce(lambda x,y:x+y,[2,4,6]) 结果为12
    如果第三个参数没有,那么就是序列类型第1 第2个元素传给x,y.(x+y的和,第三个元素)
    传进函数,依次类推。
    
    """
    print(res)
    
    # 字符串拼接
    res = reduce(lambda x,y:x+y,["a","b","c"],"阿登")
    print(res)  # 阿登abc
    res = reduce(lambda x,y:x+y,["a","b","c"])
    print(res)  # abc
    

    相关文章

      网友评论

          本文标题:py_23 面向过程编程和函数式

          本文链接:https://www.haomeiwen.com/subject/drvejktx.html