python入门之函数调用第3关_Python入门 - 第 3 节课:函数

目录

1. 函数定义

定义函数

函数定义示例:

def cylinder_volume(height, radius):

pi = 3.14159

return height * pi * radius ** 2

定义 cylinder_volume 函数后,我们可以如下所示地调用该函数。

cylinder_volume(10, 3)

函数定义包含几个重要部分。

函数头部

我们从函数头部开始,即函数定义的第一行。

函数头部始终以关键字 def 开始,表示这是函数定义。

然后是函数名称(在此例中是 cylinder_volume,因为函数名是要一个单词,所以需要用_进行连接),遵循的是和变量一样的命名规范。你可以在本页面下方回顾下命名规范。

名称之后是括号,其中可能包括用英文逗号分隔的参数(在此例中是 height 和 radius)。形参(或实参)是当函数被调用时作为输入传入的值,用在函数主体中。如果函数没有参数,这些括号留空。

头部始终以英文冒号 : 结束。

函数主体

函数的剩余部分包含在主题中,也就是函数完成操作的部分。

函数主体是在头部行之后缩进的代码。在此例中是定义 π 和返回体积的两行代码。

在此主体中,我们可以引用参数并定义新的变量,这些变量只能在这些缩进代码行内使用。

主体将经常包括 return 语句,用于当函数被调用时返回输出值。return 语句包括关键字 return,然后是经过评估以获得函数输出值的表达式。如果没有 return 语句,函数直接返回 None(例如内置 print() 函数)。

函数的命名规范

函数名称遵守和变量一样的命名规范。

仅在函数名称中使用普通字母、数字和下划线。不能有空格,需要以字母或下划线开头。

不能使用在 Python 中具有重要作用的保留字或内置标识符,我们将在这门课程中学习这方面的知识。要了解 python 保留字列表,请参阅此处。

尝试使用可以帮助读者了解函数作用的描述性名称。

默认参数

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

def cylinder_volume(height, radius=5):

pi = 3.14159

return height * pi * radius ** 2

在上述示例中,如果在函数调用中忽略了 radius,则将该参数设为 5。如果我们调用 cylinder_volume(10),该函数将使用 10 作为高度,使用 5 作为半径。但是,如果调用 cylinder_volume(10, 7),7 将覆盖默认的值 5。

此外注意,我们按照位置向参数传递值。可以通过两种方式传递值:按照位置和按照名称。下面两个函数的效果是一样的。

cylinder_volume(10, 7) # pass in arguments by position

cylinder_volume(height=10, radius=7) # pass in arguments by name

2. 变量作用域

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

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

# This will result in an error

def some_function():

word = "hello"

print(word)

这意味着你可以为在不同函数内使用的不同变量使用相同的名称。

# This works fine

def some_function():

word = "hello"

def another_function():

word = "goodbye"

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

# This works fine

word = "hello"

def some_function():

print(word)

print(word)

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

3. 文档

文档使代码更容易理解和使用。函数尤其容易理解,因为它们通常使用文档字符串,简称 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

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

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

4. Lambda 表达式

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

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

def multiply(x, y):

return x * y

简写为:

double = lambda x, y: x * y

Lambda 函数的组成部分

关键字lambda 表示这是一个lambda 表达式。

lambda 之后是该匿名函数的一个或多个参数(用英文逗号分隔),然后是一个英文冒号 :。和函数相似,lambda 表达式中的参数名称是随意的。

最后一部分是被评估并在该函数中返回的表达式,和你可能会在函数中看到的 return语句很像。

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

Lambda 与 Map

map()是一个高阶内置函数,接受函数和可迭代对象作为输入,并返回一个将该函数应用到可迭代对象的每个元素的迭代器。下面的代码使用 map() 计算 numbers 中每个列表的均值,并创建列表 averages。

通过将 mean 函数替换为在 map() 的调用中定义的 lambda表达式,重写这段代码,使代码更简练。

numbers = [

[34, 63, 88, 71, 29],

[90, 78, 51, 27, 45],

[63, 37, 85, 46, 22],

[51, 22, 34, 11, 18]

]

def mean(num_list):

return sum(num_list) / len(num_list)

# before

averages = list(map(mean, numbers))

print(averages)

# after

averages_2 = list(map((lambda x: sum(x) / len(x)), numbers))

print(averages_2)

Lambda 与 Filter

filter() 是一个高阶内置函数,接受函数和可迭代对象作为输入,并返回一个由可迭代对象中的特定元素(该函数针对该元素会返回 True)组成的迭代器。下面的代码使用filter()从 cities中获取长度少于 10 个字符的名称以创建列表 short_cities。

通过将is_short 函数替换为在filter() 的调用中定义的lambda 表达式,重写这段代码,使代码更简练。

cities = ["New York City", "Los Angeles", "Chicago", "Mountain View", "Denver", "Boston"]

def is_short(name):

return len(name) < 10

# before

short_cities = list(filter(is_short, cities))

print(short_cities)

# after

short_cities = list(filter((lambda s: len(s) < 10), cities))

print(short_cities)

5. 迭代器和生成器

迭代器是每次可以返回一个对象元素的对象,例如返回一个列表。我们到目前为止使用的很多内置函数(例如 enumerate)都会返回一个迭代器。

迭代器是一种表示数据流的对象。这与列表不同,列表是可迭代对象,但不是迭代器,因为它不是数据流。

生成器是使用函数创建迭代器的简单方式。也可以使用类定义迭代器,更多详情请参阅此处。

下面是一个叫做 my_range 的生成器函数,它会生成一个从 0 到 (x - 1) 的数字流。

def my_range(x):

i = 0

while i < x:

yield i

i += 1

注意,该函数使用了 yield 而不是关键字 return。这样使函数能够一次返回一个值,并且每次被调用时都从停下的位置继续。关键字 yield 是将生成器与普通函数区分开来的依据。

注意,因为这段代码会返回一个迭代器,因此我们可以将其转换为列表或用 for 循环遍历它,以查看其内容。例如,下面的代码:

for x in my_range(5):

print(x)

输出:

0

1

2

3

4

为何要使用生成器?

生成器是构建迭代器的 “懒惰” 方式。当内存不够存储完整实现的列表时,或者计算每个列表元素的代价很高,你希望尽量推迟计算时,就可以使用生成器。但是这些元素只能遍历一次。

另一种详细的解释如下(详细说明参见 该 stack overflow 页面。)

由于使用生成器是一次处理一个数据,在内存和存储的需求上会比使用list方式直接全部生成再存储节省很多资源。

由此区别,在处理大量数据时,经常使用生成器初步处理数据后,再进行长期存储,而不是使用 list。因为无论使用生成器还是 list,都是使用过就要丢弃的临时数据。既然功能和结果一样,那就不如用生成器。

但是生成器也有自己的局限,它产生的数据不能回溯,不像list可以任意选择。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值