zoukankan      html  css  js  c++  java
  • Python函数与函数式编程

    1 函数

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

    函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

    1.1过程与函数

    1.面向对象 : 类(class)

    2.面向过程: 过程 (def)

    3函数式编程 : 函数(def)

    过程与函数

    #Author:Anliu
    #函数
    def fun1():
        """testing01"""
        print("this is a testing1")
        return 0
    #过程
    def fun2():
        """testing02"""
        print("this is a testing2")
    

    x = fun1()
    y = fun2()

    我们说在编程中,过程和函数都是可以调运的实体,将没有返回值的函数叫做过程。

    #Author:Anliu

    函数

    def fun1():
    """testing01"""
    print("this is a testing1")
    return 0

    过程

    def fun2():
    """testing02"""
    print("this is a testing2")

    x = fun1()
    y = fun2()

    print("from func1 return is %s"%x)
    print("from func2 return is %s"%y)

    执行结果:

    this is a testing1
    this is a testing2
    from func1 return is 0
    from func2 return is None

    由此可见,python中默认的不再将函数个过程区分。

    1.2 为什么使用函数

    1.代码重用

    2.保持一致性

    3.可扩展

    #Author:Anliu
    import time
    def logger():
    ,,,xxxxxxxxxx,,,
    time_format = '%Y-%m-%d %X'
    time_current = time.strftime(time_format)
    with open("a.txt","a",encoding=("utf-8")) as f:
    f.write("%s end action "%time_current)

    def test1():
    '''testing'''
    print("in the test1")
    logger()

    def test2():
    '''testing'''
    print("in the test2")
    logger()

    def test3():
    print("in the test3")
    logger()

    test1()
    test2()
    test3()

    上述代码实现了,在不同函数执行时打印日志的功能,一次说明函数实现的 “一致性,以及可扩展性”

    1.2定义一个函数

    你可以定义一个由自己想要功能的函数,以下是简单的规则:

    • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()

    • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

    • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。

    • 函数内容以冒号起始,并且缩进。

    • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

    1.3 语法

    Python 定义函数使用 def 关键字,一般格式如下:

    def 函数名(参数列表):
    函数体

    默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。

    #Author:Anliu
    def hello():
    print("hello world")

    hello()

    #Author:Anliu
    def area(width,heigt):
    return width * heigt

    def print_welcome(name):
    print("Wlcome",name)

    print_welcome("anliu")

    w = 4
    h = 5
    print("width=",w,"heigt=",h,"area=",area(w,h))

    1.4 函数返回值

    1.4.1 返回值的作用

    后续程序需要函数值的确认。

    1.4.1 返回值的效果

    return执行的效果是:返回一个值,且终止当前程序运行。

    #Author:Anliu
    def test1():
    print("in the test1")
    return 0
    print("test end")

    x = test1()
    print(x)

    执行结果:

    in the test1

    1.4.2 返回值的类型

    #Author:Anliu
    def test1():
    print("in the test1")

    def test2():
    print("in the test2")
    return 0

    def test3():
    print("in the test2")
    return 1,"hello",["dajiang","dajiangliu","xxxx"],{"jingling:shibachai"}

    def test4():
    print("in the test3")
    return test1

    x = test1()
    y = test2()
    z = test3()
    w = test4()

    print(x)
    print(y)
    print(z)
    print(w)

    执行结果:

    in the test1
    in the test2
    in the test3
    in the test3
    None
    0
    (1, 'hello', ['dajiang', 'dajiangliu', 'xxxx'], {'jingling:shibachai'})
    <function test1 at 0x0000019239987730>

    当没有返回值时,返回NUll。

    当返回值时一个特定值时,返回这个值。

    当返回值是多个值时,返回的是一个元组。

    当返回值是一个函数名时,返回的是函数的内存地址。

    当返回值时一个函数时,返回值时函数的执行结果。

    1.5 函数调运

    1.5.1 参数类型

    位置参数

    关键字参数

    默认参数

    参数组

    #Author:Anliu
    def test(x,y): #形参
    print(x)
    print(y)

    test("x","y") #位置实参调运,形参和实参是一一对应

    test(y=2,x=3) #关键字参数调运,与形参位置无关。

    test(x=2,3) #关键参数不能写在位置参数之前。

    test(3,y=2) #位置参数和关键字参数同时存在,以位置参数调运为主。

    (1)位置实参调运,形参和实参是一一对应

    (2)关键字参数调运,与形参位置无关。

    (3)关键字参数不能写在位置参数之前。

    (4)位置参数和关键字参数同时存在,以位置参数调运为主。

    #Author:Anliu
    

    def test(x,y=2):
    print(x)
    print(y)

    test(1,3)

    默认参数的特点:调运函数的时候,默认参数非必须传递

    用途:参数在不修改其值的情况下,使用默认值

    #Author:Anliu
    def test (x,y,z=2):
    print(x)
    print(y)
    print(z)

    test(1,3)

    实参不能大于形参数目。

    实际 上,生产环境中,实参是需要存在多个,如何去定义实参呢?局需要参数组的概念。

    #Author:Anliu
    def test(*args):
    print(args)

    test(1,3,4,5,6,7,8,9,)
    test([1,2,2,4,5,7,])

    执行结果:

    (1, 3, 4, 5, 6, 7, 8, 9)
    (1, 2, 2, 4, 5, 7)

    执行结果是元组。

    #Author:Anliu
    def test(x,y,
    args):
    print(x)
    print(y)
    print(args)

    test(1,3,4,5,6,7,8,9,)
    test(*[1,2,2,4,5,7,])

    参数组和形式参数可以混合使用。

    #Author:Anliu
    def test(**kwargs):
    print(kwargs)

    test(name='anliu',age=8,sex='F')

    test(**{'name':"anliu","age":18})

    把N个关键字参数,转换为字典的形式

    执行结果:

    {'name': 'anliu', 'age': 8, 'sex': 'F'}
    

    {'name': 'anliu', 'age': 18}

    可将关键字或者字典传递,并得到一个字典的输出结果。

    参数和参数组同时使用也是没有问题的。

    #Author:Anliu
    def test(name,age=8,**kwargs):
    print(name)
    print(age)
    print(kwargs)

    test("anliu",age=28,hobby='paoniu',sex='F')

    执行结果:

    anliu
    28
    {'hobby': 'paoniu', 'sex': 'F'}

    *args : 接受N个位置参数,转化成元组的形式

    **kwargs :接受N个关键字参数,转化成字典的形式

    1.6 变量

    1.6.1 局部变量

    #Author:Anliu
    def change_name(name):
    print("before change",name)
    name = "Auliu" #局部变量,这个函数就是变量的作用域
    print("after change",name)

    name = "anliu"
    change_name(name)
    print(name)

    局部变量,这个函数就是变量的作用域

    1.6.2 全局变量

    在函数内是不能修改全局变量的值

    #Author:Anliu
    school = "xiyunkeji" #全局变量
    def change_name(name):
    school = "baiyijishu" #在函数内是不能修改全局变量的值
    print("before change",name,school)
    name = "Auliu" #局部变量,这个函数就是变量的作用域
    print("after change",name)

    name = "anliu"
    change_name(name)
    print(name,school)

    输出结果:

    before change anliu baiyijishu
    after change Auliu
    anliu xiyunkeji

    定义global之后,全局变量也是可以在函数内修改的。

    #Author:Anliu
    school = "xiyunkeji" #全局变量
    def change_name(name):
    global school #定义global之后,全局变量也是可以在函数内修改的。
    school = "baiyijishu" #在函数内是不能修改全局变量的值
    print("before change",name,school)
    name = "Auliu" #局部变量,这个函数就是变量的作用域
    print("after change",name)

    name = "anliu"
    change_name(name)
    print(name,school)

    输出结果:

    before change anliu baiyijishu
    after change Auliu
    anliu baiyijishu

    看一下代码:

    #Author:Anliu
    names = ["anliu","anttech","xingyun"]
    def change_name():
    names[0] = "Anliu"
    print(names)
    change_name()
    print(names)

    执行结果:

    ['Anliu', 'anttech', 'xingyun']
    ['Anliu', 'anttech', 'xingyun']

    需要说明的是,当全局变量为列表,字典,集合包括类,这种复杂的数据类型及数据结果,函数中也是可以修改全局变量的。

    1.6.3变量内存的回收机制

    python解释器当变量名不存在时,变量内存会被回收。

    1.7 递归函数

    在函数内部,可以调运其他函数。如果一个函数在内部调运自身,这个函数就是递归函数。

    递归的特性:

    1.必须要有一个明确的结束条件。

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

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

    #Author:Anliu
    def calc(n):
    print(n)
    if int(n/2) > 0:
    return calc(int(n/2))
    print("-->",n)

    calc(10)

    1.8 高阶函数

    变量可以指向函数,函数的参数支持能接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数就称之为高阶函数。

    #Author:Anliu
    def add(a,b,f):
    return f(a) + f(b)

    x = add(1,-6,abs)
    print(x)

    以上abs是求绝对值的函数。

    1.9 匿名函数

    #Author:Anliu
    calc = lambda x:x*3
    print(calc(2))

    没有函数名

    1.10 高阶函数

    (1)把一个函数名当做实参传递给另一个函数

    (2)返回值中包含函数名

    #Author:Anliu
    def test1(func):
    print(func)

    def bar():
    print("in the bar")

    test1(bar)
    func = bar
    func()

    import time
    def bar():
    time.sleep(3)
    print("in the bar")

    def test2(func):
    print(func)
    return func

    t = test2(bar)
    print(t)
    t()

    1.11 嵌套函数

    在一个函数体内定义另一个函数。

    #Author:Anliu
    def foo():
    print("in the foo ")
    def bar():
    print("in the bar")
    bar()
    foo()


    2 函数式编程介绍

    函数是python内建支持的一种封装,我们通过把大段代码折成函数,通过一层一层的函数调运,就可以把复杂的任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程设计的基本单元。

    而函数式编程,虽然可以归结到面向过程的的程序设计,但是其思想更接近科学计算。

    这使得我们要明确计算机和计算的概念。

    在计算机层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断,和跳转指令,所以汇编语言是最贴近计算机的语言。

    而计算则指的是数学意义上的计算,越是抽象的计算,里计算机硬件越远。

    对应到编程语言,就是越低级的语言,越贴近计算机,执行效率高,比如C语言;级别越高的语言,越贴近计算,抽象程度高,执行效率低,比如lisp语言。

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入确定,输出就是确定的,这种纯函数我们称之为没有副作用。而容许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可以得到不同的输出,因此这种函数是有副作用的。

    python对函数式编程提供部分支持。由于python容许使用变量,因此python不是纯函数式编程式语言。

    3 装饰器

    定义:装饰器:装饰器本质是函数,(函数是有特定的功能),装饰器的功能就是装饰其他函数,就是为其他函数添加附加功能。

    原则:1.不能修改被装饰函数的源代码。

               2.不能修改被装饰的函数的调运方式。

    (装饰器对被装饰函数来说是透明的)

    实现装饰器知识储备

    1.函数即“变量”

    2.高阶函数

    (1)把一个函数名当做实参传递给另一个函数。

    (2)返回值中包含函数名。

    3嵌套函数

    装饰器=高阶函数+嵌套函数


    看以下装饰器示例:

    #Author:Anliu
    import time
    def timmer(func):
    def warpper(*args,**kwargs):
    start_time=time.time()
    func()
    stop_time=time.time()
    print("the func run time is %s"%(stop_time-start_time))
    return warpper

    @timmer
    def test1():
    time.sleep(3)
    print("in the test1")

    test1()

    为什么我们需要装饰器?

    比如我们有两个函数,现在需要给这两个函数添加打印日志的功能:

    #Author:Anliu
    def test1():
    pass
    def test2():
    pass

    test1()
    test2()

    我们改如何去做?

    方法一:

    #Author:Anliu
    import time
    def test1():
    print("this is a test1")
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)

    def test2():
    print("this is a test2")
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)

    test1()
    test2()


    方法二:

    #Author:Anliu
    import timedef
    logger():
    '''xxxxx'''
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)

    def test1():
    '''xxxxx'''
    print("this is a test1")
    logger()

    def test2():
    '''xxxxx'''
    print("this is a test2")
    logger()

    test1()
    test2()

    此法看似可行。但是问题来了,如果实在给程序已经应用到了生产环境,test函数已经承载业务,此时代码时不容许改变的,修改源代码,是有风险存在的。该当如何是好?

    利用高阶函数实现对test1()进行装饰一个打印日志功能。

    #Author:Anliu
    import time
    def test1():
    '''xxxxx'''
    print("this is a test1")

    def logger(func):
    '''xxxxx'''
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    func()
    print(time_current)

    logger(test1)

    这样也能实现对函数的装饰。即在不修改被装饰函数源代码的情况下为其添加功能。

    但是问题来了,虽然没有修改源代码,但是修改了函数的调运方式。

    再看如下代码:

    #Author:Anliu
    import time
    def test1():
    '''xxxxx'''
    print("this is a test1")

    def test2():
    '''xxxxx'''
    print("this is a test2")

    def logger(func):
    '''xxxxx'''
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)
    return func
    test1 = logger(test1)
    test1()
    test2 = logger(test2)
    test2()

    这样,我们用高阶函数的第二个特性,返回值中包含函数名,来实现了在不修改函数调运方式的情况下,完成对函数的装饰。

    这种方式看起来貌似没有问题,其实很扯淡。因为只要在我们这个实例上生效。那如果是我们的需求变了,不再是先输出实践,再执行函数,而是先执行函数,再打印时间。

    就是说,上面代码执行结果是:

    2019-07-13 00:31:15

    this is a test1

    我们现在的需求这样:

    this is a test1

    2019-07-13 00:31:15

    #Author:Anliu
    import time
    def test1():
    '''xxxxx'''
    print("this is a test1")

    def logger(func):
    '''xxxxx'''
    return func
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)

    test1 = logger(test1)
    test1()

    this is a test1

    完了,这下输出结果有问题了。

    我们前面说的retrun()既有返回值,同时终止程序。

    该问题我们来用嵌套函数来解决:

    #Author:Anliu
    import time
    def test1():
    '''xxxxx'''
    print("this is a test1")

    def timer (func):
    def logger():
    '''xxxxx'''
    func()
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)
    return logger

    test1 = timer(test1)
    test1()

    输出结果:

    this is a test1

    2019-07-13 00:49:58

    这个我们实现了一个装饰器功能。

    再看这两行代码:

    test1 = timer(test1) test1()

    很麻烦,python解释题给我们提供了一个“语法糖”,我们可以使用“语法糖”来实现。

    #Author:Anliu
    import time
    def timer (func):
    def logger():
    '''xxxxx'''
    func()
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)
    return logger

    @timer
    def test1():
    '''xxxxx'''
    print("this is a test1")
    test1()

    这样就实现了一个完整的装饰器。

    其实还有问题:

    若函数有参数传递,该如何呢?

    #Author:Anliu
    import time
    def timer (func):
    def logger():
    '''xxxxx'''
    func()
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)
    return logger

    @timer # test1 = logger(test1)

    def test1():
    '''xxxxx'''
    print("this is a test1")
    test1()

    @timer
    def test2():
    '''xxxxx'''
    print("this is a test1")
    test2()

    @timer
    def test3(name):
    '''XXXXX'''
    print("test3",name)
    test3("anliu")

    当有参数存在时,又开始报错。

    这是因为,本质上语法糖是@timer 等同于 test1 = logger(test1),起作用是将test1传递给logger函数。我们只需要将logger函数的形参,以及函数内的函数调运实参修改即可:

    #Author:Anliu
    import time
    def timer (func):
    def logger(args,**kwargs):
    '''xxxxx'''
    func(
    args,**kwargs)
    format_time = "%Y-%m-%d %X"
    time_current = time.strftime(format_time)
    print(time_current)
    return logger

    @timer # test1 = logger(test1)
    def test1():
    '''xxxxx'''
    print("this is a test1")
    test1()

    @timer
    def test2():
    '''xxxxx'''
    print("this is a test1")
    test2()
    @timer
    def test3(name,age,aaa):
    '''XXXXXXXXX'''
    print("test3",name,age,aaa)
    test3("anliu","age","aaa")


  • 相关阅读:
    腾讯广告算法大赛2019
    Mysql的部分常用SQL语句
    org.activiti.dependencies 7.1.0.M6 造成版本冲突问题的解决
    windows 将 redis 注册为服务 自动启动或手动启动
    org.springframework.security.access.AccessDeniedException: Access is denied
    对两个List进行关联匹配,选择匹配上的记录形成新的List输出
    越是大型的组织,越需要试验基地,试验基地应有特殊待遇
    dubbo+zookeeper 安装所遇系列问题
    签名与验签——图解
    关于航空母舰战斗群出海训练,常有大量鱼群跟随问题的建议和设想
  • 原文地址:https://www.cnblogs.com/anttech/p/12575772.html
Copyright © 2011-2022 走看看