zoukankan      html  css  js  c++  java
  • Python之函数

    为什么要使用函数?

     在说明原因之前,我们先来看一个需求,比如你的boss需要你写实现以下的打印输出,并插入在某段程序代码的20个位置都条件此打印输出:

    ********************
    ********************
    hello,python!
    ********************
    ********************

     你咔咔咔就用代码实现了需求,并将代码添加到了程序的20个位置,代码如下,但是你的boss看着你的代码却不是很认可,他说:如果我现在需要你把所有的"*"都换成"#"。你一脸懵逼,难道要一个一个的改吗?

    print(
    """
    ********************
    ********************
    hello,python!
    ********************
    ********************
    """
    )

     苦苦思索不得果,询问boss,boss捋了捋袖子,几下就给你搞定了,对你说:去学学函数吧,便离去,深藏功与名,代码如下:

    def  index():
        """打印符号"""
        print('*'*20)
    def  say():
        """打印问候"""
        print("hello,python!")
    index()
    index()
    say()
    index()
    index()

    你看了一眼代码豁然开朗,那么这里这么写到底有什么好处呢?

    1.如果你现在需要将所有的"*"改为"#",只需要将函数index中的"*"替换为"#"

    2.如果你现在需要打在问候前后各打印3行符号,只需要在say()前后各加一个index()

    3.如果你现在还需要在其他程序其他的地方再打印这五行输出,只需要复制粘贴下面的五行代码

    这就是函数带来的好处,也就是为什么要使用函数

    1.减少了重复的代码

    2.更有利于阅读代码,便于调试,可维护性增强

    3.增加了代码整体结构的层次化,使组织结构更清晰

     初识函数

     在python中函数大致可以分为两类:

     1.内置函数

     比如用来求和的sum函数,求最大值的max函数,求最小值的min函数等等

    print(sum((1,2,3)))  #求和
    print(max(1,2,3))  #打印最大值
    print(min(1,2,3))  #打印最小值

     在python3.x中,print本身也是一个内置的函数,但是在python2.x不是函数。

     2.自定义函数

     说了那么多函数的好处,那么我们该怎么定义函数呢?
    一般格式如下:

    def 函数名(arg1,arg2,arg3):
        """描述信息"""
        函数体
        return

    def为函数的关键字,函数名为自定义,最好是具有描述性的名字且不能与python的关键字一致,arg1等为函数的形参,可以有也可以没有,数量可以是一个或者是无穷个,引号处为描述信息,强烈的要求你在定义函数的时候请写上描述信息,便于其他人一眼看到你定义的函数的时候,知道是做什么的,函数体定义了一系列的具体操作,return用来返回值,当一个函数没有使用return来返回值,python解释器默认会返回一个None值。

    定义函数

    在python中,函数必须是先定义后使用的,可以从是否向函数内传入参数将函数的定义分为以下三种:

    1.无参函数

    函数体内只是简单的命令,不需要依赖外部传入的参数

    def my_python():
        """This is my python"""
        print("From my python!")
    print(my_python.__doc__)  #可打印注释信息
    2.有参函数
    需要依赖外部传入的值
    def my_max(x,y):
        """求2个数的最大值"""
        max_number=x if x > y else y
        return max_number
    3.空函数
    在一个项目的前期,可以使用空函数来定义整个项目的框架
    def auth():
        pass
    def goods():
        pass

     那么定义了这么的函数,怎么去用呢?下面我们就来讲讲函数的调用

     函数的调用

    我们也从是否传递参数来说明函数的调用

    1.无参函数的调用

    在调用无参函数的时候只需要使用函数名加小括号即可调用

    def my_python():
        """This is my python"""
        print("From my python!")
    my_python()   #调用函数
    #输出结果
    From my python!

    2.有参函数的调用

    在调用有参函数的时候,需要向函数里面传递值

    def my_max(x,y):
        """求2个数的最大值"""
        max_number=x if x > y else y
        return max_number
    res=my_max(100,2)
    print(res)
    #输出结果
    100

     如上函数,我们将100和2传递给了函数my_max,函数求出最大值并返回最大值,这里将最大值返回给了res,然后打印res。

    返回值

    通常情况下无参函数不需要使用return返回值

    1.无参函数返回值

    在无参函数中不写return,默认会返回一个None

    def foo():
        """打印"""
        print("From the foo")
    res=foo()
    print(res)
    #输出结果
    From the foo
    None

     2.return一个值

    def my_max(x,y):
        """求2个数的最大值"""
        max_number=x if x > y else y
        return max_number
    res=my_max(100,2)
    print(res)
    #输出结果
    100

     3.return可以返回任意类型的多个值

    def bar(x,y):
        """测试return"""
        return x,y,3,4,5,[1,2],{'a':2},{1,2},(1,2)
    res=bar(1,2)
    print(res)
    #输出结果
    (1, 2, 3, 4, 5, [1, 2], {'a': 2}, {1, 2}, (1, 2))

    return返回多个值的时候,返回的是一个元组

    那如果我们在一个函数内同时使用多个返回值呢?

    def mul_retu():
        return 1
        return 2
        return 3
    print(mul_retu())
    #输出结果
    1

     当函数体内有多个返回值,仅执行一条

     形参和实参

    形参:在定义函数的时候,括号里面的参数,相当于变量

    实参:在调用函数的时候,括号里面的参数,相当于值,实参也可以被当成变量值

    举个例子:

    def my_max(x,y):
        """求2个数的最大值"""
        max_number=x if x > y else y
        return max_number
    res=my_max(100,2)
    print(res)

    这里的函数名后括号内的x和y就是形参,而在调用函数的时候函数名括号里面的(100,2)就是实参。只有在调用阶段的时候,形参和实参才会有绑定关系,也就是说函数只有在被调用时生效。

    我们来看以下几个函数:

    def bar(x):
        print(x)
        x=3
    x=1
    bar(x)
    print(x)
    #运行结果
    1
    1
    def bar1(y):
        print(y)
        y.append(5)
    y=[1,2,3,4]
    bar1(y)
    print(y)
    #运行结果
    [1, 2, 3, 4]
    [1, 2, 3, 4, 5]
    def bar1(z):
        print(z)
        z=(1,2)
    z=(1,2,3,4)
    bar1(z)
    print(z)
    #运行结果
    (1, 2, 3, 4)
    (1, 2, 3, 4)

    以上几个函数都试图去修改外部传入的变量的值,但是只有个别修改成功了,这里总结以下:

    如果向函数内传递的是不可变类型(字符串,元组,整型),函数则不能修改其值

    如果向函数内传递的是可变的类型(列表,字典),函数会修改其值

    所以在向函数内部传递值的时候,部件以传递可变类型,这样函数会修改外部的值,除非你想要这么做。

     位置参数和默认参数

    前面我们写过实参和形参,现在我们就站在不同的角度去看传值。

    实参的角度,先来一个函数:

    def foo(x,y):
        """大于2个数"""
        print(x)
        print(y)

    既然我们是通过实参的角度,那么通过实参有以下两种方式的传值:

    1.按照位置传值给函数

    foo(1,2)

    这里的1必定传给了x,2必定传给了y。

    2.按关键字传值

    我们可以在传值的时候就指定x,y传的值,那么不管x在前还是在后,都能正确的传给形参x和y

    foo(x=1,y=2)
    foo(y=2,x=1)

    3.混合传值

    也可以把按位置传值和按关键字传值放在一起,这个时候按关键字传值就必须要在前面,而且对于关键字传值,一个参数不能重复的赋值

     从形参的角度来看

    def foo(x,y):
        """大于2个数"""
        print(x)
        print(y)

    位置参数是必须要传值的,一个位置参数就必须传一个值

    但是也可以存在不一定要传值的默认参数,可以在定义函数的时候,就在形参后跟值

    def foo(x,y=1):
        print(x)
        print(y)
    foo(1)
    foo(y=2,x=1)

    可变参数

     我们来看函数max()求最大值的函数

    >>> max(1,2,3,4)
    4
    >>> max(1,2,3,4,56,12)
    56
    >>> max(123,221,324,32,123,3,1,23,2)
    324

    可以看到我们不管给函数max传递多少个值,他都能接受,这是怎么实现的呢?

    引出:

    *args     (args可以用任何合法的字符串代替,默认一般使用args)

    *args是一个可变的形参,看下面的函数:

    def foo(x,*args):
        print(x)
        print(args)
    foo(1,2,3,4,5)
    #运行结果
    1
    (2, 3, 4, 5)

    从实参的角度来看,1会传给x,呃,那么2,3,4,5该怎么办,按位置传值的时候,多余的实参会传给args,生成一个元组

    当*args与位置形参和默认形参混合的时候,位置形参要放在最前面,默认形参要放在最后面:

    def foo(x,*args,y=1):   #一般*args不会和默认参数放在一起用
        print(x)
        print(y)
        print(args)
    foo(1,2,3,4,5,y=100)
    #运行结果
    1
    100
    (2, 3, 4, 5)
    #从形参的角度
    def foo(*args):  #foo(x,y,z)
        print(args)
    foo(1,2,3)
    #从实参的角度
    #*args=*(1,2,3)
    def bar(x,y,z):
        print(x)
        print(y)
        print(z)
    bar(*(1,2,3)) #bar(1,2,3)

     除了*args之外还有个**kwargs,我们来看一个例子,当按关键字传值的时候,多余的会传给kwargs,生成一个字典:

    def foo(x,**kwargs):
        print(x)
        print(kwargs)
    foo(1,y=2,a=3,b=4)
    #输出结果
    1
    {'a': 3, 'b': 4, 'y': 2}
    #从实参的角度
    def foo(x,y,z=1):
        print(x)
        print(y)
        print(z)
    foo(**{'x':1,'y':2,'z':3}) #foo(x=1,y=2,z=3) 

     *args和**kwargs混合

    def auth(name,passwd,sex='male'):
        print(name)
        print(passwd)
        print(sex)
    def foo(*args,**kwargs):  
        # print("From the foo")
        auth(*args,**kwargs)
        
    foo("Frank","123")
    foo(name='claire',passwd='123',sex="female")

    名称空间和作用域

    名称空间

    从字面的意思来看就是存放名字的空间,当我们定一个变量的这个,例如x=1,那么x就是名称,它会放到一个所谓的“空间”中,当我们调用它的名称的时候就可以获得其值。在python中有3种类型的名称空间。

    1.内置名称空间

    解释器一启动就有的,比如sum,print,max这些函数名都内置的名称

    2.全局名称空间

    在一个文件中,顶头写的就是定一个全局的名称,比如顶头定一个变量,列表或者字典,那么这些对象的名称就是全局名称

    3.局部名称空间

    在函数内部定义的对象的名称

     
    作用域:就是名称空间的作用范围
    看一下下面的例子
    x=1
    def foo():
        x=12
        print(x)
    foo()
    print(x)
    #运行结果
    12
    1

     根据结果我们可以知道,当在函数内部,打印一个变量的时候,她会现在局部名称空间里面去找有没有这个变量,如果有就打印其值,当我们在全局名称空间里面打印变量值的时候,它会在全局下面找,而不会去局部名称空间里面去找。

    x=1
    def foo():
        print(x)
    foo()
    print(x)
    #输出结果
    1
    1
    来看一下上面的例子,当我们在局部名称空间里面并没有定义值,它会去全局的名称空间去找。
    所有在函数内部需要一个变量的时候,寻找名称空间顺序是局部==>全局==>内置,如果在全局下需要一个变量的时候,会现在全局找,再在内置找,不会去局部名称空间里面去找。
    这里内置名称空间和全局名称空就是全局作用域,局部名称空间就是局部作用域。


    名称空间的查询

    查询名称空间可以使用如下函数:

    globals():查看全局名称空间

    locals():查看局部名称空间

    1.在全局作用域下查询

    在全局作用域下查询,全局名称空间和局部名称空间是一样的

    x=1
    def  my_function():
        y=2
    print(globals())   #查看全局名称空间
    print(locals())    #查看局部名称空间
    #运行结果
    {'__name__': '__main__', '__doc__': None, 'x': 1, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001C6F17E6A58>, 'my_function': <function my_function at 0x000001C6F1CA0268>, '__spec__': None, '__file__': 'E:/py_fullstack/函数/名称空间和作用域.py', '__cached__': None, '__builtins__': <module 'builtins' (built-in)>}
    {'__name__': '__main__', '__doc__': None, 'x': 1, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001C6F17E6A58>, 'my_function': <function my_function at 0x000001C6F1CA0268>, '__spec__': None, '__file__': 'E:/py_fullstack/函数/名称空间和作用域.py', '__cached__': None, '__builtins__': <module 'builtins' (built-in)>}
    2.在局部作用域内查询

    2.在局部作用域内查询

    在局部作用域内查询,即在函数内部查询,全局名称空间为函数外部的名称空间(内置名称空间和全局名称空间),而局部名称空间只有函数内部定义的名称(局部名称空间)

    x=1
    def  my_function():
        y=2
        print(globals())
        print(locals())
    my_function()
    #运行结果
    {'__builtins__': <module 'builtins' (built-in)>, 'x': 1, '__doc__': None, '__file__': 'E:/py_fullstack/函数/名称空间和作用域.py', '__name__': '__main__', '__package__': None, '__cached__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000016AAF6F6A58>, '__spec__': None, 'my_function': <function my_function at 0x0000016AAFB20268>}
    {'y': 2}

    函数的嵌套

    1.函数的嵌套调用

    函数可以被其他的函数放在函数体内调用,举例如下:

    def my_max(x,y):
        return x if x >y else y
    print(my_max(10,100))
    def my_max4(a,b,c,d):
        res1=my_max(a,b)
        res2=my_max(res1,c)
        res3=my_max(res2,d)
        return res3
    print(my_max4(1,20,2,111))
    #运行结果
    100
    111
    2.函数的嵌套定义
    意思就是可以在函数内定义函数
    def f1():
        print("from the f1")
        def f2():
            print("from the f2")
            def f3():
                print("from the f3")
        f2()
    f1()
    #运行结果
    from the f1
    from the f2

    函数对象

    在Python中有句话是“一切皆对象”,函数也不例外,函数作为对象可以赋值给一个变量、可以作为元素添加到集合对象中,可以作为参数传递给其他的函数,也可以作为返回值,这一类特性就是“第一类对象”所有的:

    def foo():
        print("foo")
    print(foo)
    #运行结果
    <function foo at 0x0000020717320048>

    函数可以被赋值

    def foo():
        print('foo')
    # print(foo)
    f=foo
    print(f)
    f()
    #运行结果
    <function foo at 0x000001D4C59F0048>
    foo

    函数可以被当作参数传递

    def foo():
        print('foo')
    def bar(func):
        print(func)
    bar(foo)
    #运行结果
    <function foo at 0x000002B425570048>

    把函数当作容器类型的元素

    def search():
        print('===search')
    def add():
        print('===add')
    def delete():
        print('===delete')
    cmd_dic={
        'search':search,
        'add':add,
        'delete':delete,
    }
    def tell_message():
        msg="""
        search:查询
        add:增加
        delete:删除
        """
        print(msg)
    while True:
        tell_message()
        choice = input("Please input your choice:").strip()
        cmd_dic[choice]()

    闭包函数

    首先我们来看下面这个例子

    x=100
    def f1():
        x=1
        def f2():
            print(x)
        return f2
    f=f1()  #返回f2的内存地址
    print(f)
    f()
    #运行结果
    <function f1.<locals>.f2 at 0x00000288E92401E0>
    1
    闭包:首先必须是内部定义的函数,该函数包含对外部作用域而不是全局作用域名字的引用,上面的f2就是一个闭包函数
    闭包的应用(爬取一个页面),这里的f2也是一个闭包函数:
    from urllib.request import urlopen
    def f1(url):
        def f2():
            print(urlopen(url).read())
        return f2
    python=f1('http://www.python.org')    #返回了函数f2的功能和对外部作用域定义的url==》python
    python()
  • 相关阅读:
    思岚 激光雷达 A3 使用官方sdk读取数据
    思岚激光雷达 开箱使用
    ubuntu 更新软件失败
    ubuntu 安装tftp
    Ubuntu 安装Telnet服务
    【博客搬至CSDN】
    【RabbitMQ】一文带你搞定springboot整合RabbitMQ涉及消息的发送确认,消息的消费确认机制,延时队列的实现
    基于JVisualVM的可视化监控
    LCN解决分布式事务原理解析+项目实战(原创精华版)
    springboot 用监听器统计在线人数案例分析
  • 原文地址:https://www.cnblogs.com/liubinsh/p/7229351.html
Copyright © 2011-2022 走看看