zoukankan      html  css  js  c++  java
  • 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「递归函数」

    「函数式编程」

  • 相关阅读:
    关于键盘触发事件和屏幕触发事件的问题
    andriod开发之自动开关机实现代码
    Android之Gallery的两种使用方法
    关于自定义View时,画图形和图片时抗锯齿的使用的问题
    android:descendantFocusability用法简析
    MVC访问Views文件下的静态文件
    iframe框架之间js方法相互调用及数据传递
    省、市、地区联动选择JS封装类PCASClass.js
    MVC自定义URL地址参数
    C#字符窜中转义小括号
  • 原文地址:https://www.cnblogs.com/hellojesson/p/5845149.html
Copyright © 2011-2022 走看看