Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
data8-textbook-zh
提交
ac060eed
D
data8-textbook-zh
项目概览
OpenDocCN
/
data8-textbook-zh
9 个月 前同步成功
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
data8-textbook-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
ac060eed
编写于
11月 18, 2017
作者:
W
wizardforcel
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ch7.
上级
9e60c95e
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
243 addition
and
0 deletion
+243
-0
7.md
7.md
+243
-0
未找到文件。
7.md
0 → 100644
浏览文件 @
ac060eed
#
通过使用 Python 中已有的函数,我们正在建立一个使用的技术清单,用于识别数据集中的规律和主题。 现在我们将探索Python编程语言的核心功能:函数定义。
我们在本书中已经广泛使用了函数,但从未定义过我们自己的函数。定义一个函数的目的是,给一个计算过程命名,它可能会使用多次。计算中有许多需要重复计算的情况。 例如,我们常常希望对表的列中的每个值执行相同的操作。
## 定义函数
`double`
函数的定义仅仅使一个数值加倍。
```
py
# Our first function definition
def
double
(
x
):
""" Double x """
return
2
*
x
```
我们通过编写
`def`
来开始定义任何函数。 下面是这个小函数的其他部分(语法)的细分:
当我们运行上面的单元格时,没有使特定的数字加倍,并且
`double`
主体中的代码还没有求值。因此,我们的函数类似于一个菜谱。 每次我们遵循菜谱中的指导,我们都需要以食材开始。 每次我们想用我们的函数来使一个数字加倍时,我们需要指定一个数字。
我们可以用和调用其他函数完全相同的方式,来调用
`double`
。 每次我们这样做的时候,主体中的代码都会执行,参数的值赋给了名称
`x`
。
```
py
double
(
17
)
34
double
(
-
0.6
/
4
)
-
0.3
```
以上两个表达式都是调用表达式。 在第二个里面,计算了表达式
`-0.6 / 4`
的值,然后将其作为参数
`x`
传递给
`double`
函数。 每个调用表达式最终都会执行
`double`
的主体,但使用不同的
`x`
值。
`double`
的主体只有一行:
```
py
return
2
*
x
```
执行这个
`return`
语句会完成
`double`
函数体的执行,并计算调用表达式的值。
`double`
的参数可以是任何表达式,只要它的值是一个数字。 例如,它可以是一个名称。
`double`
函数不知道或不在意如何计算或存储参数。 它唯一的工作是,使用传递给它的参数的值来执行它自己的主体。
```
py
any_name
=
42
double
(
any_name
)
84
```
参数也可以是任何可以加倍的值。例如,可以将整个数值数组作为参数传递给
`double`
,结果将是另一个数组。
```
py
double
(
make_array
(
3
,
4
,
5
))
array
([
6
,
8
,
10
])
```
但是,函数内部定义的名称(包括像double的x这样的参数)只存在一小会儿。 它们只在函数被调用的时候被定义,并且只能在函数体内被访问。 我们不能在
`double`
之外引用
`x`
。 技术术语是
`x`
具有局部作用域。
因此,即使我们在上面的单元格中调用了
`double`
,名称
`x`
也不能在函数体外识别。
```
py
x
---------------------------------------------------------------------------
NameError
Traceback
(
most
recent
call
last
)
<
ipython
-
input
-
18
-
401
b30e3b8b5
>
in
<
module
>
()
---->
1
x
NameError
:
name
'x'
is
not
defined
```
文档字符串。 虽然
`double`
比较容易理解,但是很多函数执行复杂的任务,并且没有解释就很难使用。 (你自己也可能已经发现了!)因此,一个组成良好的函数有一个唤起它的行为的名字,以及文档。 在 Python 中,这被称为文档字符串 - 描述了它的行为和对其参数的预期。 文档字符串也可以展示函数的示例调用,其中调用前面是
`>>>`
。
文档字符串可以是任何字符串,只要它是函数体中的第一个东西。 文档字符串通常在开始和结束处使用三个引号来定义,这允许字符串跨越多行。 第一行通常是函数的完整但简短的描述,而下面的行则为将来的用户提供了进一步的指导。
下面是一个名为
`percent`
的函数定义,它带有两个参数。定义包括一个文档字符串。
```
py
# A function with more than one argument
def
percent
(
x
,
total
):
"""Convert x to a percentage of total.
More precisely, this function divides x by total,
multiplies the result by 100, and rounds the result
to two decimal places.
>>> percent(4, 16)
25.0
>>> percent(1, 6)
16.67
"""
return
round
((
x
/
total
)
*
100
,
2
)
percent
(
33
,
200
)
16.5
```
将上面定义的函数
`percent`
与下面定义的函数
`percents`
进行对比。 后者以数组为参数,将数组中的所有数字转换为数组中所有值的百分数。 百分数都四舍五入到两位,这次使用
`round`
来代替
`np.round`
,因为参数是一个数组而不是一个数字。
```
py
def
percents
(
counts
):
"""Convert the values in array_x to percents out of the total of array_x."""
total
=
counts
.
sum
()
return
np
.
round
((
counts
/
total
)
*
100
,
2
)
```
函数
`percents`
返回一个百分数的数组,除了四舍五入之外,它总计是 100。
```
py
some_array
=
make_array
(
7
,
10
,
4
)
percents
(
some_array
)
array
([
33.33
,
47.62
,
19.05
])
```
理解 Python 执行函数的步骤是有帮助的。 为了方便起见,我们在下面的同一个单元格中放入了函数定义和对这个函数的调用。
```
py
def
biggest_difference
(
array_x
):
"""Find the biggest difference in absolute value between two adjacent elements of array_x."""
diffs
=
np
.
diff
(
array_x
)
absolute_diffs
=
abs
(
diffs
)
return
max
(
absolute_diffs
)
some_numbers
=
make_array
(
2
,
4
,
5
,
6
,
4
,
-
1
,
1
)
big_diff
=
biggest_difference
(
some_numbers
)
print
(
"The biggest difference is"
,
big_diff
)
The
biggest
difference
is
5
```
这就是当我们运行单元格时,所发生的事情。
## 多个参数
可以有多种方式来推广一个表达式或代码块,因此一个函数可以有多个参数,每个参数决定结果的不同方面。 例如,我们以前定义的百分比
`percents`
,每次都四舍五入到两位。 以下两个参的数定义允许不同调用四舍五入到不同的位数。
```
py
def
percents
(
counts
,
decimal_places
):
"""Convert the values in array_x to percents out of the total of array_x."""
total
=
counts
.
sum
()
return
np
.
round
((
counts
/
total
)
*
100
,
decimal_places
)
parts
=
make_array
(
2
,
1
,
4
)
print
(
"Rounded to 1 decimal place: "
,
percents
(
parts
,
1
))
print
(
"Rounded to 2 decimal places:"
,
percents
(
parts
,
2
))
print
(
"Rounded to 3 decimal places:"
,
percents
(
parts
,
3
))
Rounded
to
1
decimal
place
:
[
28.6
14.3
57.1
]
Rounded
to
2
decimal
places
:
[
28.57
14.29
57.14
]
Rounded
to
3
decimal
places
:
[
28.571
14.286
57.143
]
```
这个新定义的灵活性来源于一个小的代价:每次调用该函数时,都必须指定小数位数。默认参数值允许使用可变数量的参数调用函数;在调用表达式中未指定的任何参数都被赋予其默认值,这在
`def`
语句的第一行中进行了说明。 例如,在
`percents`
的最终定义中,可选参数
`decimal_places`
赋为默认值
`2`
。
```
py
def
percents
(
counts
,
decimal_places
=
2
):
"""Convert the values in array_x to percents out of the total of array_x."""
total
=
counts
.
sum
()
return
np
.
round
((
counts
/
total
)
*
100
,
decimal_places
)
parts
=
make_array
(
2
,
1
,
4
)
print
(
"Rounded to 1 decimal place:"
,
percents
(
parts
,
1
))
print
(
"Rounded to the default number of decimal places:"
,
percents
(
parts
))
Rounded
to
1
decimal
place
:
[
28.6
14.3
57.1
]
Rounded
to
the
default
number
of
decimal
places
:
[
28.57
14.29
57.14
]
```
## 注:方法
函数通过将参数表达式放入函数名称后面的括号来调用。 任何独立定义的函数都是这样调用的。 你也看到了方法的例子,这些方法就像函数一样,但是用点符号来调用,比如
`some_table.sort(some_label)`
。 你定义的函数将始终首先使用函数名称,并传入所有参数来调用。
## 在列上应用函数
我们已经看到很多例子,通过将函数应用于现有列或其他数组,来创建新的表格的列。 所有这些函数都以数组作为参数。 但是我们经常打算,通过一个函数转换列中的条目,它不将数组作为它的函数。 例如,它可能只需要一个数字作为它的参数,就像下面定义的函数
`cut_off_at_100`
。
```
py
def
cut_off_at_100
(
x
):
"""The smaller of x and 100"""
return
min
(
x
,
100
)
cut_off_at_100
(
17
)
17
cut_off_at_100
(
117
)
100
cut_off_at_100
(
100
)
100
```
如果参数小于或等于 100,函数
`cut_off_at_100`
只返回它的参数。但是如果参数大于 100,则返回 100。
在我们之前使用人口普查数据的例子中,我们看到变量
`AGE`
的值为 100,表示“100 岁以上”。 以这种方式将年龄限制在 100 岁,正是
`cut_off_at_100`
所做的。
为了一次性对很多年龄使用这个函数,我们必须能够引用函数本身,而不用实际调用它。 类似地,我们可能会向厨师展示一个蛋糕的菜谱,并要求她用它来烤 6 个蛋糕。 在这种情况下,我们不会使用这个配方自己烘烤蛋糕, 我们的角色只是把菜谱给厨师。 同样,我们可以要求一个表格,在列中的 6 个不同的数字上调用
`cut_off_at_100`
。
首先,我们创建了一个表,一列是人,一列是它们的年龄。 例如,
`C`
是 52 岁。
```
py
ages
=
Table
().
with_columns
(
'Person'
,
make_array
(
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
),
'Age'
,
make_array
(
17
,
117
,
52
,
100
,
6
,
101
)
)
ages
```
| Person | Age |
| --- | --- |
| A | 17 |
| B | 117 |
| C | 52 |
| D | 100 |
| E | 6 |
| F | 101 |
### 应用
要在 100 岁截断年龄,我们将使用一个新的
`Table`
方法。
`apply`
方法在列的每个元素上调用一个函数,形成一个返回值的新数组。 为了指出要调用的函数,只需将其命名(不带引号或括号)。 输入值的列的名称必须是字符串,仍然出现在引号内。
```
py
ages
.
apply
(
cut_off_at_100
,
'Age'
)
array
([
17
,
100
,
52
,
100
,
6
,
100
])
```
我们在这里所做的是,将
`cut_off_at_100`
函数应用于
`age`
表的
`Age`
列中的每个值。 输出是函数的相应返回值的数组。 例如,17 还是 17,117 变成了 100,52 还是 52,等等。
此数组的长度与
`age`
表中原始
`Age`
列的长度相同,可用作名为
`Cut Off Age`
的新列中的值,并与现有的
`Person`
和
`Age`
列共存。
```
py
ages
.
with_column
(
'Cut Off Age'
,
ages
.
apply
(
cut_off_at_100
,
'Age'
)
)
```
| Person | Age | Cut Off Age |
| --- | --- | --- |
| A | 17 | 17 |
| B | 117 | 100 |
| C | 52 | 52 |
| D | 100 | 100 |
| E | 6 | 6 |
| F | 101 | 100 |
### 作为值的函数
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录