zoukankan      html  css  js  c++  java
  • Python学习笔记(十二)—函数

    一、函数是什么?

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。通俗来讲函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。

    1 def fun():  #定义一个名称是fun的函数
    2     print('hello world!')  #函数体:函数要实现的功能
    3 fun()  #调用这个函数
    4 
    5 结果:
    6 hello world!

    二、函数的好处

      1、简化程序代码

      2、提高程序代码的复用性

      3、代码可扩展性

    三、函数的定义

    Python中提供了许多内建函数,比如print函数。当然函数也可以自己创建,被叫做用户自定义函数。

    函数定义的规则:

    • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()
    • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
    • 函数的第一行语句可以选择性地使用文档字符串,用于存放函数说明。
    • 函数内容以冒号起始,并且缩进。
    • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

    语法格式: 

    1 def functionname( parameters ):
    2    "函数_文档字符串"
    3    function_suite    #函数体
    4    return [expression]  #调用函数后的返回

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

    实例:

    1 def print_str(str):
    2     '打印输出传入的字符串'
    3     print('要打印的字符串是:',str)
    4 print('Hello world!')
    5 
    6 运行结果:
    7 Hello world!

    四、参数传递

    在Python中,类型属于对象,变量是没有类型的;比如

    a = [1,2,3]

    a = 'helloworld!'

    如上,[1,2,3]是一个list类型, 'helloworld!'是一个string类型,而变量a是没有类型的,它仅仅是一个对象的引用(一个指针),可以是list类型对象也可以是string类型对象。

    对象分为:可更改对象与不可更改对象

    可更改对象:list、dicti等 

    不可更改对象:字符串、元祖、numbers

      可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了

      不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。

    函数的参数传递:

      可变类型:如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

      不可变类型:如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。

    #传不可变对象实例
    def ChangeInt(a):
        print('修改前a的值:',a)
        a = 10
        print('修改后a的值:',a)
    b = 2
    ChangeInt(b)
    print(b)
    
    运行结果:
    修改前a的值: 2
    修改后a的值: 10
    2
    
    分析:
    ChangeInt(b)把b的值复制给a,a未修改前a=b=同一内存地址;a=10重新修改后,a重新生成一个对象指针指向了10,但是b的指针还是指向的2,所以b的值为2而非10
    #传可变对象实例
    # 可写函数说明
    def changeme(mylist):
        "修改传入的列表"
        mylist.append([1, 2, 3, 4])
        print("函数内取值: ", mylist)
        return
    # 调用changeme函数
    mylist = [10, 20, 30]
    changeme(mylist)
    print("函数外取值: ", mylist)
    
    运行结果:
    函数内取值:  [10, 20, 30, [1, 2, 3, 4]]
    函数外取值:  [10, 20, 30, [1, 2, 3, 4]]

    五、参数

    函数在调用的时候,可以传入参数,参数有实参和形参。

    实参:实参可以是常量、变量、表达式、函数等,无论实参是何种类型,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

    形参:形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效

    简单点说,形参就是函数接收的参数,而实参就是你实际传入的参数。

    def print_str(str):  #str就是定义的形参
        '打印输出传入的字符串'
        print('要打印的字符串是:',str)
    test = 'Hello world!'
    print(test)  #test就是实参,当然这里也可以直接传入‘helloworld!’

     函数的四种参数类型:

    位置参数:

    简单来说就是按照参数的位置来进行传参。位置参数是必传的,有几个位置参数在调用的时候就要传几个,否则就会报错;如果有多个位置参数,记不清楚哪个位置传哪个参数,可以使用位置参数的名字来指定调用。比如下面的fun函数也可以使用fun(y=1,x=2)这样来调用,这种调用方式叫做关键字传参

    #位置参数
    def fun(x,y):  #x,y就是位置参数
        print(x+y)
    fun(3,3)  #调用这个函数
    fun(y=2,x=6)

    默认参数:

    默认参数就是在定义形参的时候,给函数默认赋一个值,这样就算你在调用的时候没传入这个参数,它也是有值的。因此默认参数不是必填的,如果给默认参数传值的话,它就会使用你传入的值,如果不传入值,那么就使用默认的值。

    注意:如果使用默认值参数的话,必须放在位置参数后面定义。

    #有默认参数,不传值
    def fun(x,y=6): 
        print(x+y)
    fun(3)  #调用这个函数,y不传值
    fun(y=0,x=6)  #抵用这个函数,y传值为0
    
    运行结果:
    9
    6
    
    
    #默认参数位置在位置参数前面
    def fun(x=4,y):  
        print(x+y)
    fun(y=3)  #调用这个函数
    
    运行结果:
    SyntaxError: non-default argument follows default argument

    非固定参数:

    位置参数和默认值参数都是参数个数固定的,如果一个函数,参数不固定,也不知道这个函数后期会扩展到何种程度,可能参数会越来越多,这个时候在用固定参数程序就不好扩展了。这个时候就应该使用非固定参数。非固定参数有两种,一种是可变参数,一种是关键字参数。

    可变参数:

    在变量名前边加入*号(变量名可以随便起,一般都叫args),其特点是:

    1、不限制传参的个数
    2、元素都放入一个元组中
    3、不是必传的
    4、它用在传参比较多的情况下

    注意:如果位置参数、默认值参数、可变参数一起使用的的话,可变参数必须在位置参数和默认值参数后面。

    #可变参数
    def send_sms(*phone_num):
            print(phone_num)
    send_sms()
    send_sms(13199998888)
    send_sms(13899992222,13499989234)
    
    运行结果:
    ()
    (13199998888,)
    (13899992222, 13499989234)
    
    def my(name,county='china',*args):   #可变参数、默认值参数、位置参数同时使用,可变参数必须在位置参数的后边,否则会报错
        print(name)
        print(county)
        print(args)
        print(kwargs)
    my('gyb','beijing','天通苑',color = '红色',age = 19)
    
    运行结果:
    gyb
    beijing
    ('天通苑', '海淀区')

    关键字参数:

    在变量前边加入两个*号(变量名可以随便起,一般都叫kwargs),其特点:

    1、不限制传参的个数
    2、不是必传的
    3、元素都放在一个字典中
    4、它用在传参比较多的情况下

    注意:1、关键字也可以和位置参数、默认参数、可变参数一起使用,但是关键字参数必须在最后边,否则程序会出错;2、使用关键字参数的话,调用的时候必须使用关键字传参;

    #关键字参数
    def send_sms(**phone_num):
        print('详细信息:',phone_num)
    send_sms()
    send_sms(name='test',sex='20')
    send_sms(addr = '北京市',country = '中国',c = 'abc',f = 'kkk')
    
    运行结果:
    详细信息: {}
    详细信息: {'name': 'test', 'sex': '20'}
    详细信息: {'addr': '北京市', 'c': 'abc', 'f': 'kkk', 'country': '中国'}
    
    
    def my(name,county='china',*args,**kwargs):
        '''
        如果定义的函数如上边这样那么:
            1、先写位置参数,其次是默认值参数,然后是可变参数,最后是关键字参数,的顺序来写;
        '''
        print(name)
        print(county)
        print(args)
        print(kwargs)
    # my('gaobo','japan','beijing','天通苑',color = '红色',age = 19)
    my('gyb','beijing','天通苑',color = '红色',age = 19)
    
    运行结果:
    gyb
    beijing
    ('天通苑',)
    {'color': '红色', 'age': 19}

    六、函数的返回值

    每个函数都会有返回值,如果在函数中没有指定返回值的化,程序默认返回None。函数也可以返回多个值,如果返回多个值的话,会把返回的值都存放到一个元组中,返回的是一个元组。

    函数之所以有返回值,是因为返回值需要供后边的程序调用。

    Python中使用return语句来返回值,return有两个用处:1、函数遇到return就结束;2、返回函数的处理结果

    #函数没有return语句,返回默认值None
    def my():
        res = '这是一个测试函数!'
    res1 = my()
    print(res1)
    
    运行结果:
    None
    
    #函数有return语句,返回函数值
    def my():
        res = '这是一个测试函数!'
        return res
    res1= my()
    print(res1)
    
    运行结果:
    这是一个测试函数!
    
    #函数有return,返回多个值
    def my():
        res = '这是一个测试函数!'
        a = 123
        return res,a
    res1= my()
    print(res1)
    
    运行结果:
    ('这是一个测试函数!', 123)

    七、全局变量和局部变量

    全局变量:定义在函数外部的变量拥有全局作用域,在整个程序中都生效。

    局部变量:定义在函数内部的变量拥有一个局部作用于,出了这个函数就不生效了。

    注意:全局变量如果要在函数中修改的话,需要加global关键字声明,如果是list、字典和集合的话,则不需要加global关键字,直接就可以修改。

    total = 0  # 这是一个全局变量
    # 可写函数说明
    def sum(arg1, arg2):
        # 返回2个参数的和."
        total = arg1 + arg2  # total在这里是局部变量.
        print("函数内是局部变量 : ", total)
        return total
    # 调用sum函数
    sum(10, 20)
    print("函数外是全局变量 : ", total)
    
    运行结果:
    函数内是局部变量 :  30
    函数外是全局变量 :  0
    #在函数中修改全局变量
    total = 0  # 这是一个全局变量
    # 可写函数说明
    def sum(arg1, arg2):
        # 返回2个参数的和."
        global total   #声明变量total为全局变量
        total = arg1 + arg2  # total在这里是局部变量.
        print("函数内是全部变量 : ", total)
        return total
    # 调用sum函数
    sum(10, 20)
    print("函数外是全局变量 : ", total)
    
    运行结果:
    函数内是全部变量 :  30
    函数外是全局变量 :  30
    #list的修改
    total = [1,2,3,4,5]  # 这是一个全局变量
    # 可写函数说明
    def sum(arg1, arg2):
        # 返回2个参数的和."
        total.append(6)  #修改全局变量
        print("函数内是全部变量 : ", total)
        return total
    # 调用sum函数
    sum(10, 20)
    print("函数外是全局变量 : ", total)
    
    运行结果:
    函数内是全部变量 :  [1, 2, 3, 4, 5, 6]
    函数外是全局变量 :  [1, 2, 3, 4, 5, 6]

    八、递归调用

    递归函数,就是函数内部自己调用自己,这就叫递归。

    递归调用,可以实现循环的效果,但是效率没有循环效率高;

    def test():
        num = int(input('please input number:'))
        if num %2 != 0: #判断输入的数字是不是奇数
            return True  #如果是奇数的话,退出程序返回True
        print('不是奇数')
        return test() #如果不是奇数,继续调用自己,输入值
    print(test())  #调用test函数

    递归调用的特性:

    1、必须有一个明确的结束条件

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

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

    九、匿名函数

    Python使用lambda来创建匿名函数:

    • lambda只是一个表达式,函数体比def简单很多。

    • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。

    • lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

    • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

    语法:

    lambda [arg1 [,arg2,.....argn]]:expression

    实例:

    # 可写函数说明
    sum = lambda arg1, arg2: arg1 + arg2
    
    # 调用sum函数
    print("相加后的值为 : ", sum(10, 20))
    print("相加后的值为 : ", sum(20, 20))
    
    运行结果:
    相加后的值为 :  30
    相加后的值为 :  40

    lambda详细的参考连接:https://blog.csdn.net/zjuxsl/article/details/79437563

  • 相关阅读:
    Seam的安全框架授权(Authorization)(译) (三)
    Seam的安全框架授权(Authorization)(译) (一)
    Seam的安全框架错误信息(Error Messages)(译)
    如何编出健壮的代码,java编程30条规则(转)
    Seam的安全框架身份管理(Identity Management)(译)
    Seam的安全框架授权(Authorization)(译) (二)
    集成Seam,Spring和jBPM指南(译)
    拖拉是种病,不治会要命!(转)
    Jboss Seam, mysql中文乱码问题4步骤总结(转)
    ubuntu上的mysql字符集设置(转)
  • 原文地址:https://www.cnblogs.com/beginner-boy/p/12527280.html
Copyright © 2011-2022 走看看