美文网首页
叶子带你学 Python | (四)函数初探

叶子带你学 Python | (四)函数初探

作者: 初心不变_叶子 | 来源:发表于2021-07-29 21:55 被阅读0次

    习题答案

    作业一:视情况而定,如果不作为字典的键是可以的。

    作业二:

    • 错误一:定义列表 a 的过程中,3 后面的逗号写成了点
    • 错误二:在定义只有一个元素的元组时,元素和后引号之间要加逗号
    • 错误三:不能对元组使用 append() 函数,因为它是不可变的

    作业三,代码如下:

    a = [1, 1, 2, 2, 2, 3, 3, 3, 4, 4]
    b = []
    
    for i in a:
        if i % 2 != 0:
            b.append(i)
    

    注意,直接在 a 中进行 remove() 是不可取的,因为删除元素时会改变各元素的索引值,导致后续迭代时有部分元素被跳过。

    这是另一种可行的代码实现,如果感兴趣可以尝试运行观察输出,不需要理解原理:

    a = [1, 1, 2, 2, 2, 3, 3, 3, 4, 4]
    print(list(filter(lambda x: x % 2 != 0, a)))
    

    函数初探

    Python 的函数,和数学课上学到的函数还是有些区别的。

    数学课上的函数是这样的:

    image

    Python 中的函数不能画出图像,但它可以做一些神奇的事情。

    举个例子,如果你的程序中有几十个位置都需要找到一个可迭代对象中搜友的偶数,每次都使用循环解决太麻烦了,而且当需求改变为找到所有奇数时,你还需要把每个位置都进行修改。

    我们可以使用函数来简化这一过程。

    让我们来定义一个简单的函数,它接收一个数字,并将其加上 1 后返回:

    def add_1(x):
        x += 1
        return x
    

    如你所见,使用 def 关键字来定义一个函数,紧接着是一个空格,然后是函数的名字。

    接下来是一对小括号,里面是函数的参数,接下来是一个冒号。

    函数体内的代码需要缩进,和循环、分支结构的原因一样,让 Python 看出哪部分属于这个函数。

    在另外一些编程语言中,虽然缩进不是必须的,但必须使用大括号来区分代码块,这样看来还是 Python 简单。

    回到正题,函数的第一行将 x 加 1,并将结果赋值给 x。+= 运算符是一种简写形式,相当于x = x + 1

    同样的,也有 -=、*=、/= 运算符,灵活运用可以避免很多不必要的繁琐。

    最后,我们使用 return 关键字来返回一个值,在这里我们返回了 x。

    运行程序,什么都不会发生,因为你只是定义了一个函数,但还没有使用它,术语叫做”调用“。

    是时候让这个函数发挥作用了,运行以下代码:

    a = 6
    a = add_1(a)
    print(a)
    

    输出是 ”7“。注意,如果不把函数返回的结果 7 赋值给 a,最终结果不会发生改变。

    你也许注意到了,定义函数时的参数名不一定和调用函数时传入的参数名相等。

    既然传入的参数是真实存在的,是实际的,就叫”实参“吧,函数定义里的参数名只是做个样子,走个形式,就叫”形参“。

    一句话解释,实参在函数外面用,形参在函数里面用;实参要有值,形参被对应的形参赋值。

    我们之前使用过的 print()、remove() 本质上也是函数,让我们来看一眼 print() 的内部有什么东西:

    image

    看不懂,告辞。

    函数返回值

    先讲讲结果吧。我们在前面提到过,用 return 来返回结果,那么如果不写 return 会发生什么呢?

    运行以下代码:

    def add_1(x):
        x += 1
    
    print(add_1(6))
    

    输出结果是”None“。这个单词的意思是”不存在“,也就是说这个函数什么也没有返回。None 也是一种数据类型。

    同样的,如果你在函数最后加上 return,但后面什么都不写,也会返回 None。

    另外,还有一点需要提示大家:函数在返回结果后,后面的部分不会被执行。

    也就是说,如果你定义这样一个函数:

    def test_return():
        print("开始执行函数")
        return
        print("函数返回了 None")
    
    test_return()
    

    你只会看到第一个 print() 输出的内容。

    函数参数

    必选参数

    这是我们在这个系列中第一次看到二级标题,事情貌似变得复杂了起来,但是不用担心。

    必选参数,顾名思义就是没有不行。让我们试一下:

    def need_two_args(a, b):
        return None
    need_two_args(1)
    

    运行结果:

    TypeError: need_two_args() missing 1 required positional argument: 'b'
    

    报错信息提示我们这个函数缺少一个参数”b“。

    如果多一个呢?

    def need_two_args(a, b):
        return None
    need_two_args(1, 2, 3)
    

    运行结果:

    TypeError: need_two_args() takes 2 positional arguments but 3 were given
    

    报错信息提示我们这个函数只需要两个参数,但你给了三个。

    不是个好伺候的东西,让我们先看看后面几个:

    关键字参数

    看名字优点难以理解,来点代码:

    def need_two_args(a, b):
        return None
    need_two_args(b=2, a=1)
    

    其实这并不是一种参数类型,而是一种传参方式。

    在调用函数时,将参数部分写成”形参=实参“的形式,使用这种方式传参时,这些形参被叫做关键字参数。

    有什么好处呢?可以不严格按照定义形参的顺序传参,另外会提高代码的可读性,这在复杂程序的开发中是很重要的。

    注意,关键字参数和必选参数不能重复,例如你不能这样:

    def need_two_args(a, b):
        return None
    need_two_args(2, a=1)
    

    按照必选参数,a 的值是 2,但按照关键字参数,a 的值是 1,于是 Python 就不知道怎么处理了:

    TypeError: need_two_args() got multiple values for argument 'a'
    

    关键字参数也不能放在必选参数前面,不能这样:

    def need_two_args(a, b):
        return None
    need_two_args(a=1, 2)
    

    Python 不知道 2 是给 a 的还是给 b 的:

    SyntaxError: positional argument follows keyword argument
    

    可选参数

    你现在要做一个函数,接收两个参数,将第一个加上第二个:

    def add_two_numbers(a, b):
        return a + b
    

    但你在使用的时候,发现大多数情况下 b 的值都是 1,但拆分成两个函数太麻烦了,这时可以用可选参数:

    def add_two_numbers(a, b=1):
        return a + b
    

    当你只传入一个数时,函数会返回这个数加 1 后的结果,当传入两个数时,则按照原先规则执行。

    和关键字参数类似,可选参数必须在必选参数后面。

    注意:你可以将参数的默认值设置为一个可变对象,但强烈不建议这样做,可能会导致一些奇奇怪怪的问题。

    如果你需要一个可变参数的默认值呢?很简单,把这个参数的默认值设置为 None,在函数内判断其是否为默认值,然后做赋值处理即可。

    不定长参数

    这种参数能屈能伸,少的时候可以不接收参数,多的时候可以接收好几个参数。

    用起来也不难,在参数名前加一个星号即可,就像这样:

    def one_or_more_args(a, *more):
        return None
    

    不定长参数将以一个元组的形式出现,举个例子:

    one_or_more_args(1,2,3)
    

    这时,a 的值为 1,more 的值为 (2, 3)。

    不定长参数也要放在必须参数后面,因为它是一个无底洞,放在前面会导致后面的参数无法被赋值。

    函数文档

    所谓“文档”,就是说明函数用途的一段话。

    当你的程序规模逐渐变大,或者需要和别人进行协作时,编写函数文档会让你和他人更容易理解这个函数的用途。

    比如:

    def GetUserName(user_url):
        """
        该函数接收用户个人主页 Url,并返回该链接对应用户的昵称
    
        Args:
            user_url (str): 用户个人主页 Url
    
        Returns:
            str: 用户昵称
        """
        pass
    

    这是 JRT 中一个函数的开头部分。

    我们使用多行字符串来编写函数文档,这也是一种数据类型。使用三个连续的引号包裹一段文字,然后将其放置在函数定义的下一行,注意要在函数体内部(缩进),就变成了一个函数文档。

    在这个函数文档中,我们用一句话概括了这个函数的功能,并指出了它参数和返回值的信息。

    你可以使用 __doc__ 来查看一个函数的文档:

    print(GetUserName.__doc__)
    

    在 VS Code 中,当你输入一个函数时,函数的参数和文档也会自动显示:

    image

    如果没有文档,且函数的命名和参数命名都不规范,我们需要阅读函数的代码,才能确定它实现的功能:

    image

    而且在这个函数中还调用了三个其它的函数......

    所以,为了节省你和他人的时间,请编写函数文档,并给函数和参数取易于理解的名字。

    这里推荐一个 VS Code 插件:Python Docstring Generator。安装之后,只需要在函数体开头输入三个连续引号,然后按下回车键,就会自动根据当前函数的参数和返回值生成文档模板,只需要补全每一项的含义即可。

    VS Code 小技巧

    • 右键函数名,在右键菜单最上方有“转到定义”和“转到引用”,前者可以找到定义这个函数的代码,后者则可以找到这个函数在哪里被调用过。
    • 在默认黑色主题中,函数名为黄色,函数参数为蓝色,字符串为棕色,变量的值为绿色,关键字为紫色。当你发现莫名其妙的错误时,不妨看看颜色是否有不对劲的地方。
      • 一大片内容全变成了棕色,说明前面有一个引号没有闭合。
      • 变量名是紫色,说明你用关键字做了变量名。
      • 函数名是白色,可能在 def 和函数名之间少了一个空格。
    • 选择一个变量 / 函数后,按下 F2 可以一键更名。

    课后作业

    作业一:可变参数是以什么形式保存多个值的?

    作业二:请说出至少两种让函数返回 None 的方法。

    作业三:请编写一个函数,接收一个数字 a 和一个指数 n,计算这个数的 n 次方并返回。

    提示:善用 *= 操作符,使用循环进行处理。

    注意:不可以使用 Python 的内置函数完成。

    下一篇文章,我们将学到 Python 的异常处理机制和一些有用的内置函数。

    相关文章

      网友评论

          本文标题:叶子带你学 Python | (四)函数初探

          本文链接:https://www.haomeiwen.com/subject/wdifvltx.html