zoukankan      html  css  js  c++  java
  • 步入函数式编程的大门

    注:本人用Python3.4作为学习版本,以下学习心得只适用于Python3.4。

    写下这篇博客,意味着我即将步入函数式编程的大门。

    说起函数,首先想到的莫过于读书至今依然围绕在我身边的那个“函数”。数学计算中的函数,简单地说,就是对给定数的一种人为约定的运算法则,将给定的数通过某种变化得到一个新的结果。Python中的函数有内置函数,简单的说和数学上的函数功能类似,比如说abs,就是将给定的值取绝对值,验证如下:

    # Author: Lucas w
    res = abs(-10)
    print(res)

    运行结果如下所示:

    10
    
    Process finished with exit code 0

    类似的函数在Python中有好多,函数式编程和数值运算中的函数有着相同的灵魂,作为初级入门,我暂且将函数式编程定义为:将一段代码封装起来,就变成一个函数,起个名字,就是函数名,当需要调用这段代码时,直接调用函数名即可。以下是验证程序:

    # Author: Lucas w
    #一段代码
    a=1
    b=2
    c=a+b
    print(c)
    #将代码封装变成一个简单函数
    def res():
        a=1
        b=2
        c=a+b
        print(c)
    res()

    结果如下:

    3
    3
    
    Process finished with exit code 0

    说了这么多,接下来谈一下函数的基本形式,代码如下:

    # Author: Lucas w
    def test(x):
        x+=1
        print(x)
        return 0
    test(1)

    运行结果如下:

    2
    
    Process finished with exit code 0

    其中test表示函数名,x为形式参数,return为函数的返回值,这就是函数最简单的标准形式。接下来我们对函数进行全面的剖析。

    首先我们来探讨函数的返回值return。

    当我们需要接收函数返回值时,我们需要将函数赋给一个变量。验证程序如下:

    # Author: Lucas w
    def test():
        return 0
    y= test()
    print(y)

    运行结果如下:

    0
    
    Process finished with exit code 0

    接下来要考虑的问题是,return都可以返回什么样的值。经过学习,初步确定为三种:当没有定义返回值时,返回空值None;当定义为对象时,返回该对象;当定义不止一个对象时,返回一个元组。验证程序如下:

    # Author: Lucas w
    def test1():
        return
    x= test1()
    def test2():
        return 1
    y= test2()
    def test3():
        return 1,2,3,4,5
    z= test3()
    print(x)
    print(y)
    print(z)

    运行结果如下:

    None
    1
    (1, 2, 3, 4, 5)
    
    Process finished with exit code 0

    至此,我们已经熟悉了函数return都可以返回的值,至于定义函数为什么要加return这个返回值,大概是某些特定的时候,需要得到函数的计算结果,所以return才应运而生,我们姑且这么理解,毕竟刚入门,不可能追究过深。

    接下来,我们来挖掘一下函数的参数所蕴含的秘密。

    说起参数,我们都知道函数有形式参数,有实际参数。至于这两者的区别,一句话概括:实际参数占用内存空间,而形式参数不占用内存空间。这里我们用查询内存地址函数id来验证,程序如下:

    # Author: Lucas w
    def test(x):
        print(x)
        print(id(x))
        return
    test(1)
    print(id(1))

    运行结果如下:

    1
    1755480256
    1755480256
    
    Process finished with exit code 0

    可以看出,当函数运行时形式参数和实际参数有相同的内存地址。但是当函数运行后,形式参数被释放,不占用内存;而实际参数依然在内存中存在。验证如下:

    # Author: Lucas w
    def test(x):
        print(x)
        return
    test(1)
    print(id(1))
    print(id(x))

    运行如下:

    1
    1755480256
    Traceback (most recent call last):
        print(id(x))
    NameError: name 'x' is not defined
    
    Process finished with exit code 1

    可以看出,并没有在内存中找到x。这就看出了形式参数和实际参数的区别。形式参数用时占用内存,不用时释放内存;而实际参数,只要定义了,就一直在内存中存在。

    接下来,我们来探讨参数的调用。这里主要有两种调用方式:位置参数调用,顾名思义就是按照函数定义时参数的位置,采用一一对应的原则进行调用;另一种是关键字调用,这种调用方式更加灵活。验证程序如下:

    # Author: Lucas w
    def test(x,y,z):
        print(x)
        print(y)
        print(z)
        return
    print("位置参数调用")
    test(1,2,3)
    print("关键字调用")
    test(x=1,z=3,y=2)

    运行结果如下:

    位置参数调用
    1
    2
    3
    关键字调用
    1
    2
    3
    
    Process finished with exit code 0

    另外需要注意的是,关键字参数只能写在位置参数后边,不然程序就会报错。验证如下:

    # Author: Lucas w
    def test(x,y,z):
        print(x)
        print(y)
        print(z)
        return
    print("位置参数在关键字参数前,可以调用")
    test(1,y=2,z=3)

    运行结果如下:

    位置参数在关键字参数前,可以调用
    1
    2
    3
    
    Process finished with exit code 0

    位置参数在关键字参数后,则不能完成函数调用,验证程序如下:

    # Author: Lucas w
    def test(x,y,z):
        print(x)
        print(y)
        print(z)
        return
    print("位置参数在关键字参数后,不可以调用")
    test(x=1,2,3)

    运行结果如下:

        test(x=1,2,3)
                ^
    SyntaxError: non-keyword arg after keyword arg
    
    Process finished with exit code 1

    因此,在调用函数时只要记住一句话:位置参数在前,关键字参数在后。

    当我们需要定义函数的参数,不只局限于x,y...登有限个参数时。Python提供了两种方式:一种是元组存储法;一种是字典存储法。

    接下来我们来看元组存储法,程序如下:

    # Author: Lucas w
    def test(*args):
        print(args)
        return
    test(1,2,3,4,5,6,7,8,9,0)

    运行结果如下:

    (1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
    
    Process finished with exit code 0

    以此可知,我们输入的参数,都存储在了args这个tuple中,并且并不限制参数数目。

    接下来我们来验证第二种方法,字典存储法。验证程序如下:

    # Author: Lucas w
    def test(**args):
        print(args)
        return
    test(name="Wang",age="18",sex="men")

    运行结果如下:

    {'sex': 'men', 'name': 'Wang', 'age': '18'}
    
    Process finished with exit code 0

    因此,当我们需要定义的函数有未知个参数时,可以采取两种方法。一种是定义为元组,采用*args;一种是定义为字典,采用**args。

    至此,函数式编程基本形式,我们已经有了大概的了解。接下来明确一下局部变量和全局变量的关系。

    在Python中,

    全局变量指的是:除函数内定义的变量之外,其余程序中所有该变量都代表同一个变量。全局变量一般在程序一开始定义。

    局部变量指的是:函数内定义的变量,生效范围只在函数内,当函数不运行时,该变量不生效。

    另外需要注意的是,如果同时将一个变量定义为全局变量和局部变量,那么程序在执行时,函数内将其作为局部变量,函数外将其作为全局变量。实际运行时,也就是同名,实际代表的功能并不一样。这就好比老王有个儿子叫小王,而班里还有一个同学叫小王,我们并不能说这两个小王都是老王的儿子,也仅仅只是同名而已。慢慢体会,似乎同名的全局变量和局部变量也是一样的道理。验证程序如下:

    # Author: Lucas w
    XiaoWang = "小王的同学"
    def test(x):
        XiaoWang = "老王的儿子"
        print("局部变量")
        print(XiaoWang)
        return
    test(XiaoWang)
    print("全局变量")
    print(XiaoWang)

    运行结果如下:

    局部变量
    老王的儿子
    全局变量
    小王的同学
    
    Process finished with exit code 0

    这个全局变量和局部变量重名一般不会出现,之所以拿出来比较,也仅仅是加深理解概念罢了,并没有实际意义。另一个更加鸡肋的功能,将局部变量转换为全局变量。

    这个用法,在Python中存在,但是实际用处并不大,只能将我等入门级程序员弄的满脸蒙蔽。转换方法如下所示:

    # Author: Lucas w
    XiaoWang = "小王的同学"
    def test(x):
        global XiaoWang
        XiaoWang = "老王的儿子"
        print("转换为全局变量的局部变量")
        print(XiaoWang)
        return
    test(XiaoWang)
    print("全局变量")
    print(XiaoWang)

    运行结果如下:

    转换为全局变量的局部变量
    老王的儿子
    全局变量
    老王的儿子
    
    Process finished with exit code 0

    这个global功能,暂且知道用法,不进行细究。接下来我们进入递归函数的学习。

    所谓递归函数,字面意思可以理解为函数自身来调用自身,需要注意的是,Python中默认递归次数为999,虽然说我们可以通过设置来增加递归次数,但这显然不是最理想的做法,因为我们打破了Python对系统的一种保护机制。因此,我们在使用递归函数时必须明确指定一个结束条件,以免造成对系统损坏。以下是一种简单的递归函数:

    # Author: Lucas w
    def test(x):
        print(x)
        x-=1
        if x>0:
            return test(x)
    test(5)

    运行结果如下:

    5
    4
    3
    2
    1
    
    Process finished with exit code 0

    了解完递归函数之后,进入最后一个知识点:高阶函数。

    所谓高阶函数,就是将运算法作为参数引入函数的定义中,通过以下例子,我们就可以直观的看到。验证程序如下:

    # Author: Lucas w
    def test(x,y,f):
        return f(x)+f(y)
    res=test(1,-3,abs)
    print(res)

    运行结果如下:

    4
    
    Process finished with exit code 0

    自此,我们对Python中函数的概念有了一个大致的了解,算作是小小的入门吧,毕竟只是了解了一些概念,随着学习的深入,慢慢进步,共勉。

  • 相关阅读:
    Selenium简单测试页面加载速度的性能(Page loading performance)
    Selenium Page object Pattern usage
    Selenium如何支持测试Windows application
    UI Automation的两个成熟的框架(QTP 和Selenium)
    分享自己针对Automation做的两个成熟的框架(QTP 和Selenium)
    敏捷开发中的测试金字塔(转)
    Selenium 的基础框架类
    selenium2 run in Jenkins GUI testing not visible or browser not open but run in background浏览器后台运行不可见
    eclipse与SVN 结合(删除SVN中已经上传的问题)
    配置Jenkins的slave节点的详细步骤适合windows等其他平台
  • 原文地址:https://www.cnblogs.com/lucas0625/p/7577005.html
Copyright © 2011-2022 走看看