• python函数 与 函数式编程


    函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。

    函数是一个能完成特定功能的代码块,可在程序中重复使用,减少程序的代码量和提高程序的执行效率。

    定义:将一组语句的集合通过一个名字(函数名)封装起来,通过调用该函数名执行。

    #  函数主要作用:
    1. 减少重复代码
    2. 方便修改 更易扩展
    3. 保持代码一致性

    1「函数的创建」

    1.1 在python中,函数定义语法格式如下:

    def function_name(arg1,arg2[,...]): #采用def 关键字
        statement
    [return value]  #返回值不是必须的,如果没有return语句,则Python默认返回值None。

    1.2 函数名的命名规则

    1. 函数名必须以下划线或字母开头,可以包含任意字母、数字或下划线的组合。不能使用任何的标点符号;
    2. 函数名是区分大小写的。
    3. 函数名不能是保留字。

    1.3 形参和实参

    形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应与实参一一对应)
    
    实参:实际参数,调用函数时传给函数的参数,可以是常量,变量,表达式,函数,传给形参 
    
    区别:形参是虚拟的,不占用内存空间,.形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据传送单向,实参传给形参,不能形参传给实参

    1.4 返回值

    要想获取函数的执行结果,就可以用return语句把结果返回。

    # 注意:
    a. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果;因此,也可以理解为 return 语句代表着函数的结束。
    b. 如果未在函数中指定return,那这个函数的返回值为None  
    c. return多个对象,解释器会把这多个对象组装成一个元组或者字典,作为一个一个整体结果输出。

    2「函数的参数」

    2.1 参数类型

    a. 位置参数    # (也称作:必备参数)
    b. 关键字参数 
    c. 默认参数    # (也称作:缺省函数)
    d. 不定长参数  # (也称作:可变长参数 有两种*args:接收的参数封装成一个元组,**kwargs:接收的参数封装成一个字典)
    另外注意:*后边的args 和 **后边的kwargs 这两个字符是约定俗称的建议写法,这块是可以自定义的。

    a. 位置参数:

    位置参数,必须以正确的顺序传入函数;调用时的参数个数必须和声明时的一致。

    def f(name,age):        # 这里定义了nam,age 两个形参
        print('I am %s,I am %d'%(name,age))
     
    f('jesson',26)          #实参输入的时候,有先后顺序,与形参上下对应
    f('pitter',25,'sport')  #这里调用,会报错;因为传入3个实参数量,超过了定义的两个形参数量;同时少了也不可以。

    b. 关键字参数

    关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

    def f(name,age):
        print('I am %s,I am %d'%(name,age))
     
    # f(26,'jesson')  #报错
    f(name='jesson',age=26) 
    f(age=26,name='jesson') #两种写法都可以

    c. 默认参数(缺省函数)

    调用函数时,缺省参数的值如果没有传入,则被认为是默认值。

    实例会打印默认的性别,如果sex没有被传入:

    def print_info(name,age,sex='male'):
     
        print('Name:%s'%name)
        print('age:%s'%age)
        print('Sex:%s'%sex)
        return
     
    print_info('jesson',26)        #这里不给sex参数传值的话,会获取默认的值
    print_info('pitter',25,'male')
    print_info('张三',28,'female') 

    d. 不定长参数

    在函数参数的引用时,有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。

    加了星号(*)的变量名会存放所有未命名的变量参数;而加(**)的变量名会存放命名的变量参数,即传入的值要求是以键值对的形式。

    def add(*args):
        sum=0
        for v in tuples:
            sum+=v
     
        return sum
     
    print(add(1,3,5,7,9))   #这里一次传入多个值,形参*args 会将获取的多个值,封装成一个元组。
    print(add(2,4,6,8,10))
    def print_info(**kwargs):
     
        print(kwargs)
        for i in kwargs:
            print('%s:%s'%(i,kwargs[i]))#根据参数可以打印任意相关信息了
     
        return
     
    print_info(name='jesson',age=26,sex='male',hobby='sports',nationality='Chinese',job='IT')

    总结:

    Python中函数的参数主要有以上四种,它们在定义时候,如果需要同时使用,注意写法有一个先后顺序;即:

    位置参数 》 默认参数 》 *不定长参数(元组) 》 **不定长参数(字典)

    这么做的目的是为了保证获取值的一致性,不出现错乱。

    例如:

    def print_info(name,sex='male',*args,**kwargs):

    3「函数的作用域」

    3.1 作用域介绍:

    python程序执行的时候,查找引用函数的默认顺序,遵循LEGB原则。

    即:引用函数的时候,在四个作用域中查找:先局部(Local),次之(Enclosing),再次之全局(Global),最后是内置(Build-in)。

    • L:local,局部作用域,即函数中定义的变量;
    • E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
    • G:globa,全局变量,就是模块级别定义的变量;
    • B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
    x = int(2.9)  # int built-in
    g_count = 0   # global
    def outer():
        o_count = 1   # enclosing
        def inner():
            i_count = 2  # local
            print(o_count)
        #print(i_count) #找不到
        inner()
    outer()
    # print(o_count) #找不到 因为执行是从上往下,查找是有内往外,局部函数可以调用全局变量,外部的函数不能调用局部变量

    当然,local和enclosing是相对的,enclosing变量相对上层来说也是local。

    3.2 作用域产生

    在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的,如下代码:

    if 2>1:
        x = 1
    print(x)  # 1

    这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。

    def test():
        x = 2
    print(x) # NameError: name 'x2' is not defined  可以类比局部变量可以引用全局变量,全局变量不能调用局部变量。

    def、class、lambda是可以引入新作用域的。 

    3.3 变量的修改

    5「高阶函数」

    高阶函数就是把函数当做参数传递的一种函数。其与C#中的委托有点相似,个人认为。
     def add(x,y,f):
            return f( x)+ f( y)
        print   add(-18,11,abs)

    它将这么执行:

    abs(-18) + abs(11)

    结果则会是:

    29

    map()函数

    map()是 Python 内置的高阶函数,它接收一个函数 f 和一个list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。

    def f(x):
        return x* x
    print map(f,[1,2,3,4,5,6,7]) #list里的每个元素都会走一遍f(x)方法

    结果将会是:

    [1, 4, 9, 10, 25, 36, 49]

    reduce()函数

    reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
    def f(x ,y ):
            return x* y
        print reduce(f,[1,2,3,4]) #1*2*3*4

    它的结果将会是这样:

    24

    如若想给初始值呢?需要这样:  

      def f(a,b):
            return a+ b
        print reduce(f,[1,2,3,4],10) #1+2+3+4+10.这里的第三个参数是做为初始值的。

    结果会是:

    20

    filter()函数

    filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
     def is_odd(x):
           return x%2==1
        print filter(is_odd,[1,2,3,4,5,6,7])

    结果是:

    [1, 3, 5, 7]

     自定义排序函数

    Python内置的 sorted()函数可对list进行排序:

    sorted([36, 5, 12, 9, 21])

    结果是:

    [5, 9, 12, 21, 36]

    但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。


    6 匿名函数

    高阶函数是可以把函数当参数来传递的,那么当不需要显示传递的函数名称时应该怎么办呢?我们就可以用到匿名函数。

    比如上面讲了Map()函数,当时的例子是这样:

    def f(x):
        return x* x
    print map(f,[1,2,3,4,5,6,7]) #list里的每个元素都会走一遍f(x)方法

    要将其改成匿名函数,匿名函数的话需要用到lambda关键字,后面跟参数,然后冒号,再后面就写表达式,也就是返回的结果,不用写return。那么这个匿名方法将会是这样:

    print map(lambda x:x*x,[1,2,3,4,5,6,7])

     最后将上面的reduce()函数改成匿名函数吧,略体会下匿名方法的写法。原本是这样:

    def f(x ,y ):
            return x* y
        print reduce(f,[1,2,3,4]) #这里是写"f",而不是"f()"

    匿名方法将是:

    print reduce(lambda x,y:x+y,[1,2,3,4,5])

    7「递归函数」

    「函数式编程」

  • 相关阅读:
    JZOJ 3034. 【NOIP2012模拟10.17】独立集
    JZOJ 3035. 【NOIP2012模拟10.17】铁轨
    JZOJ 1259. 牛棚安排
    数位DP JZOJ 3316. 非回文数字
    JZOJ 3046. 游戏
    JZOJ 3013. 填充棋盘
    debian 安装oracle提供的java8
    java 汉字转拼音 PinYin4j
    debian ssh设置root权限登陆 Permission denied, please try again
    java并发下订单生成策略
  • 原文地址:https://www.cnblogs.com/hellojesson/p/5845149.html
Copyright © 2020-2023  润新知