Python 基础五-函数

今天学习 Python 的基础语法之函数。

函数

函数最重要的目的是方便我们重复使用相同的一段程序
将一些操作隶属于一个函数,以后你想实现相同的操作的时候,只用调用函数名就可以,而不需要重复敲所有的语句。

函数的定义

首先,我们要定义一个函数, 以说明这个函数的功能。

def square_sum(a,b):
    c = a**2 + b**2
    return c

这个函数的功能是求两个数的平方和。

首先,def,这个关键字通知python:我在定义一个函数。square_sum是函数名。

括号中的a, b是函数的参数,是对函数的输入。参数可以有多个,也可以完全没有(但括号要保留)。

我们已经在循环和选择中见过冒号和缩进来表示的隶属关系。

  • c = a2 + b2 # 这一句是函数内部进行的运算

  • return c # 返回c的值,也就是输出的功能。Python的函数允许不返回值,也就是不用return。

  • return可以返回多个值,以逗号分隔。相当于返回一个tuple(定值表)。

  • return a,b,c # 相当于 return (a,b,c) 在python中 # 代表注释,编译器将跳过#后的内容。
    在Python中,当程序执行到return的时候,程序将停止执行函数内余下的语句。return并不是必须的,当没有return, 或者return后面没有返回值时,函数将自动返回None。None是Python中的一个特别的数据类型,用来表示什么都没有,相当于C中的NULL。None多用于关键字参数传递的默认值。

默认参数

我们可以向函数中添加默认参数,以便为在函数调用中未指定的参数提供默认值。

def cylinder_volume(height, radius=5):
    pi = 3.14159
    return height * pi * radius ** 2

定义一个函数计算人口面积:

# write your function here
def population_density(population, lend_area):
    if lend_area == 0:
        return 0
    return population / lend_area

# test cases for your function
test1 = population_density(10, 1)
expected_result1 = 10
print("expected result: {}, actual result: {}".format(expected_result1, test1))

test2 = population_density(864816, 121.4)
expected_result2 = 7123.6902801
print("expected result: {}, actual result: {}".format(expected_result2, test2))

变量作用域

变量作用域是指可以在程序的哪个部分引用或使用某个变量。

在函数中使用变量时,务必要考虑作用域。如果变量是在函数内创建的,则只能在该函数内使用该变量。你无法从该函数外面访问该变量。

像这样在函数之外定义的变量依然可以在函数内访问。

# This works fine
word = "hello"

def some_function():
    print(word)

print(word)

注意,我们可以在此函数内以及函数外输出 word。作用域对理解信息在用 Python 和任何编程语言编写的程序中的传递方式来说很关键。

关于变量作用域的更多信息
在编程时,你经常会发现相似的想法不断出现。你将使用变量进行计数、迭代和累积要返回的值。为了编写容易读懂的代码,你会发现你需要对相似的想法使用相似的名称。一旦你将多段代码放到一起(例如,一个脚本中有多个函数或函数调用),你可能需要为两个不同的概念使用相同的名称。

幸运的是,你不需要不断想出新的名称。可以为对象重复使用相同的名称,只要它们位于不同的作用域即可。

良好实践:建议将变量定义在所需的最小作用域内。虽然函数_可以_引用在更大的作用域内定义的变量,但是通常不建议这么做,因为如果程序有很多变量,你可能不知道你定义了什么变量。

练习题

egg_count = 0

def buy_eggs():
    egg_count += 12 # purchase a dozen eggs

buy_eggs()

运行这段代码后的结果是什么?如果不确定,在自己的计算机上运行一下!

  • A egg_count 等于0
  • B egg_couont 等于12
  • C 发生错误

答案选择:C,原因:会导致 UnboundLocalError,因为 Python 不允许函数修改不在函数作用域内的变量

练习解决方案:变量作用域

更好的编写方式为:

egg_count = 0
def buy_eggs(count):
    return count + 12  # purchase a dozen eggs

egg_count = buy_eggs(egg_count)

将这段代码与原始代码段进行比较:

egg_count = 0

def buy_eggs():
    egg_count += 12 # purchase a dozen eggs

buy_eggs()

下面的代码段导致 UnboundLocalError

在上个视频中,你发现在函数内,我们可以成功地输出外部变量的值。因为我们只是访问该变量的值。当我们尝试将此变量的值更改重新赋值为另一个值时,我们将遇到错误。Python 不允许函数修改不在函数作用域内的变量。

但是上面的原则仅适用于整数和字符串,列表、字典、集合、类中可以在子程序(子函数)中通过修改局部变量达到修改全局变量的目的

文档

文档使代码更容易理解和使用。函数尤其容易理解,因为它们通常使用文档字符串,简称 docstrings。文档字符串是一种注释,用于解释函数的作用以及使用方式。下面是一个包含文档字符串的人口密度函数。

def population_density(population, land_area):
    """Calculate the population density of an area. """
    return population / land_area

文档字符串用三个引号引起来,第一行简要解释了函数的作用。如果你觉得信息已经足够了,可以在文档字符串中只提供这么多的信息;一行文档字符串完全可接受,如上述示例所示。

def population_density(population, land_area):
    """Calculate the population density of an area.

    INPUT:
    population: int. The population of that area
    land_area: int or float. This function is unit-agnostic, if you pass in values in terms
    of square km or square miles the function will return a density in those units.

    OUTPUT: 
    population_density: population / land_area. The population density of a particular area.
    """
    return population / land_area

如果你觉得需要更长的句子来解释函数,可以在一行摘要后面添加更多信息。在上述示例中,可以看出我们对函数的参数进行了解释,描述了每个参数的作用和类型。我们经常还会对函数输出进行说明。

文档字符串的每个部分都是可选的。但是,提供文档字符串是一个良好的编程习惯。你可以在此处详细了解文档字符串惯例。

lambda表达式

你可以使用 Lambda 表达式创建匿名函数,即没有名称的函数。lambda 表达式非常适合快速创建在代码中以后不会用到的函数。尤其对高阶函数或将其他函数作为参数的函数来说,非常实用。

我们可以使用 lambda 表达式将以下函数

def multiply(x, y):
    return x * y

简写为:

double = lambda x, y: x * y

Lambda 函数的组成部分

  • 1、关键字 lambda 表示这是一个 lambda 表达式。
  • 2、lambda 之后是该匿名函数的一个或多个参数(用英文逗号分隔),然后是一个英文冒号 :。和函数相似,lambda 表达式中的参数名称是随意的。
  • 3、最后一部分是被评估并在该函数中返回的表达式,和你可能会在函数中看到的 return 语句很像。

鉴于这种结构,lambda 表达式不太适合复杂的函数,但是非常适合简短的函数。

为者常成,行者常至