MIT 6.00 1x Lecture 4 - Functions 学习笔记

l MIT6.00 1x (麻省理工:计算机科学和Python编程导论)

Lecture 4 - Functions 函数

4.1 CREATING FUNCTIONS 创建函数

Functions 函数

• So far, have seen numbers, assignments,input/ output, comparisons, looping constructs   我们已经学习了数值、字符串、输入输出、对比、循环结构(当型循环)

– Sufficient to be TuringComplete  足够完成所谓的图灵完整性(我们可以计算任何可计算的东西)

• But code lacks abstraction  但是代码缺少抽象化

– Have to reload file every time want to use   每当我想重新使用脚本时,我必须重新载入文件

– Can’t use same variable names in other pieces of code   在代码的不同地方不能使用不相同的变量名

– Can quickly get cumbersome to read and maintain   不可以快速读取和维护出现的麻烦

• Functions give us abstraction  函数给了我们抽象化

– allow us to capture computation and treat as if primitive 函数允许我们捕捉计算,整合包装,并将函数作为原语

A simple example 一个简单的例子

• Suppose we want to z to be the maximum oftwo numbers, x and y  假设我们想要获取两种数字x y的最大值并将他与z绑定

• A simple script would be 一个简单的脚本

Capturing computation as a function  定义函数

• Idea is to encapsulate this computationwithin a scope such that can treat as primitive    这意味着我们想总结计算,总结一系列的机械步骤,总结特殊范围内的方法,这样我们就可以将这一函数计算作为原语使用

– Use by simply calling name, and providing input  通过调用名称,使用名称,我就可以获得程序对象

– Internal details hidden from users 内部细节(需要将计算包含的步骤)隐藏,不对用户显示

• Syntax 语法

def<函数名称><(形式参数)>

<函数主体>

def is a keyword 关键词 def(告诉Python我要对一项程序进行定义)

• Name is any legal Python name 名称可以是任何合法的Python名称

• Within parenthesis are zero or moreformal parameters  括号里为0或者其他的形式参数

– each is a variable name to be used inside function body 每一个形式参数作为变量名用在函数主体中

A simple example 一个简单的例子

• We can then invoke by  然后我们就可以调用函数了

z = max(3, 4)

• When we call or invoke max(3, 4), x isbound to 3, y is bound to 4, and then body expression(s) are evaluated  当我们调用函数之后,x绑定到3,y绑定到4,主体表达式(if……return y)会进行求值

Function returns 函数返回

• Body can consist of any number of legalPython expressions  主体表达式可以是任意的合法的Python表达式

• Expressions are evaluated until 表达式会求值直到

– Run out of expressions, in which case special value None isreturned  运行完了表达式,这种情况将会返回none

– Or until special keyword return is reached, in which case subsequentexpression is evaluated and that value is returned as value of function call  或者直到我们碰到了关键词return,在这种情况下,紧随着return的表达式将会求值,而这一数值也将返回,作为函数调用的数值(调用函数的语义值)

Summary of function call 函数调用总结

1. Expressions for each parameter areevaluated, bound to formal parameter names of function  当我们调用函数时,每个参数表达式会按照Python中的正常方式求值,它们会与函数中的形式参数所绑定

2. Control transfers to first expression inbody of function  将控制转移到函数主体的第一个表达式中

3. Body expressions executed until returnkeyword reached (returning value of next expression) or run out of expressions(returning None)   主体表达式会运算直到遇到return(返回retuen后面的表达式),或者执行完所有的主体,(返回none)

4. Invocation is bound to the returnedvalue  程序一定会返回数值

5. Control transfers to next piece of code  然后控制程序移动到下一段代码中

 

函数文档字符串:docstringof thefunction

def a(x):

  '''

  x: int or float.

  '''

  return x + 1

  中间那三行就是文档字符串(docstring是一种特殊类型的注释,通常来解释函数的的数值类型,函数的功能或者函数返回什么之类的

Docstring 紧跟着def语句,在函数主体之前docstring文档字符串开始和结束都有三个单引号或者双引号语句

 

 

“”“三个点后不换行紧跟着的语句会显示在shell中



:python3中函数不可比较函数

4.2 ENVIRONMENTS 环境

Environments to understand bindings 我们用环境的概念理解绑定

• Environments are formalism for trackingbindings of variables and values  它是一套形式体系,用于追踪变量和数值间的绑定关系

• Assignments pair name and value inenvironment   赋值语句就是把名字和值配对,然后放到一张表(环境)中去

• Asking for value of name just looks up incurrent environment   如果你想获得你一个变量的名称对应的数值,你只需在环境中提取就可以

• Python shell is default (or global)environment  python shell就是一个默认环境或者说全局环境

• Definitions pair function name withdetails of function 当我们对定义求值时,它会将函数名称和函数详情进行匹配,无需实际对那些细节进行求值(它将名字和所谓的程序对象相匹配)

运行完之后,环境里是这样的

Back to functions 回到函数上来

When we call a function 当我们调用一个函数时

• Want to evaluate   如果我想要计算表达式一(这个表达式后面还跟着用括号括起来的其他函数)

• First evaluate , which looks up procedure object in environment   首先,求表达式的数值,需要在环境中进行查询

• Then evaluate each of the other  to get values ofparameters   之后我会对其他表达式进行求值

• Bind parameter names in procedure objectto values of arguments in a new frame, which has as a parent the environment inwhich procedure was defined   我会将这些程序对象中的参数名称与新的框架中的参数的数值相绑定,而且那也会创建新的框架,那看起来跟原来的环境(框架)是一样的

• Evaluate body of procedure relative tothis new frame  需要求得与新框架相关的程序主体数值

When we call the function 当我们调用函数时

 E2————函数的新环境(与原环境不相关联,相隔离了)

4.3  COMPUTINGPOWERS AS AN EXAMPLE 以计算多次幂为例

Another simple example 另一个例子

• Suppose we want to compute powers of anumber by successive multiplication  假设我想将某些数字的指数换成其他数字,计算新的乘幂,通过连续相乘的方式

• Idea would be to keep track of number ofmultiplications, plus intermediate product  想法是跟踪乘法数

• Stop when have multiplied number x byitself p times, and return final product  使a自乘,储存结果,然后用a乘以结果,直到我完成了p次,然后纪录结果

• Here is simple code  这里有一个简单的例子

Computing powers 计算多次幂

Let’s define our procedure 让我们定义我们的程序

And this creates 这造成了

Example 例子

• Call iterativePower(2, 5)  调用函数iterativePower(2,5)

• Evaluating body of procedure initiallycauses… 把x和p放到新环境E2之后,对程序主体进行求值

• and for loop rebinds local variable untilexit, when return statement returns value of result   执行循环语句直到执行完,然后当遇到return语句的时候返回结果的值

Scoping is local 函数里定义的值只存在于函数的环境E2中

• Imagine we had evaluated  假设我们定义了

x = 3

p = 4

print(iterativePower(2, 5))

• Then our local environment would haveseparate bindings for x and p, which would not be visible to the environment ofthe function call  然后,我们的本地环境将有X和P的单独的绑定,这对函数调用的环境是不可见的

Example 例子

• Evaluating body of procedure initiallycauses… 总程序只会关注E1的值,函数只会关注E2的值

• But now evalua8on of body only seesbindings in E2

4.4 UNDERSTANDING VARIABLE BINDING 了解变量绑定

Another example 另一个例子

在PYTHON SHELL中导致如下的代码

X=4

Z=4

X=3

Y=2

Let’s see why 让我们看看为什么

在全局环境中x=3,y=2,z=4

在函数环境中x=4,y=1

现在控制语句转回全局环境,xyz的值在这里显示

Some observations  一些现象

• Each function call creates a newenvironment, which scopes bindings of formal parameters and values, and oflocal variables (those created with assignments within body)   每个函数都会创建一个新的环境,新的作用域。形式函数与输入值在这里绑定

• Scoping often called static or lexicalbecause scope within which variable has value is defined by extent of codeboundaries  这种辖域通常被称为静态辖域或者语汇辖域,因为在此辖域内变量的数值由代码界限定义

 

就是说 函数内部定义的变量啦啥的,在外部都不是不适用的,如果在外部我定义了x=3,在函数内部x若重新定义x=x+2,则函数内部主体x=5,外部x依然等于3

4.5 HOW ENVIRONMENTS SEPARATE VARIABLE BINDINGS  如何让环境单独绑定变量

Another example  例子

Let’s try it out  让我们尝试一下

 

Some observations  一些现象

• Notice how each call to square created anew frame, with a local binding for x  注意每次调用平方函数都会产生一个新的框架,x会为了平方进行局部绑定

• The value of x in the global environmentwas never confused with values within frames from function calls  全局环境中x的数值永远不会和用于计算平方的数值或者用在twopover中的迭代循环里的数值混淆

• The value of x used by the call to squareis different from the binding for x in the call to twoPower   调用平方的数值与towpower中的数值不一样,他们每一个都相互独立

• The rules we described can be followedmechanically to determine scoping of variables 这些规则可以让我们从机械角度清清楚楚的追踪到正确的数值

 

 

就是说,每次调用函数都会产生一个新的环境,新环境继承原来上层环境中的变量绑定,然后执行形式变量绑定,进行函数主体运算,并不会将新环境的变量绑定再输出回上层环境

4.6 UNDERSTANDING ROOT FINDING  理解寻根

Capturing a more interesting example 一个更有趣的例子

这个函数不能计算负数,所以需要改进

 

 

改进之后可以了

 

 

 

不能计算小数的幂值

 

 

 

Think about our bisection search  思考一下我们的二分法

• When we call with a fractional argument,like 0.25, we are searching  当我们输入小数的时候,就像0.25

• Which means our first guess will be theaverage, or .125  意味着我们的第一次猜测是平均值0.125

– Our original idea used the fact that the root of x was between 0and x, but when x is fractional, the root is between x and 1  我们最开始的想法是对于整数的,根在x到0之间,但是现在对于小数,根在x到1之间

Capturing a more interesting example 一个更有趣的例子

现在可以了

 

 

 

Adding a specification 添加一个规格 (文档字符串)

三个引号之间的部分,作用类似于#,定义了形式参数的范围,返回值的范围,函数的功能等等

Specifications  规格

• Are a contract between implementer offunction and user  规格现在已经成为编函数的人和使用函数的人之间的“合同”

– Assumptions: conditions that must be met by users of function.Typically constraints on parameters, such as type, and sometimes acceptableranges of values  它定义假设,编函数的人所假设的情况中,有哪些情况使用函数的人必须遵守,它通常对函数进行限制,比方说函数的类型,或者范围 本质上,它告诉使用者,如果不满足这些情况,函数将不能正常使用

– Guarantees: Conditions that must be met by function, provided thatit has been called in way that satisfies assumptions 它还提供保证,意思就是如果你按我的规格输入,我就可以保证答案

Functions close the loop 函数的作用

• Can now create new procedures and treatas if Python primitives  我们现在可以创建新的程序,并将它们看作原语

• Properties  属性(两个非常好的属性)

– Decomposition: Break problems into modules that areself-contained, and can be reused in other settings  分解的属性,我们可以将问题分解成独立的模块,而且他们可以在其他设置中重复利用

– Abstraction: Hide details. User need not know interior details,can just use as if a black box. 抽象的属性:函数可以隐藏细节,用户仅需要知道如何使用函数,并不需要知道函数的内部细节函数可以简化设计,方法是压缩那些不必要的细节

4.7 MODULES 模块

Using functions in modules 在模块中使用函数

• Modularity suggests grouping functionstogether that share common theme    模块可以用来收集和分组拥有共同主题的函数

• Place in a single .py file  一种方法是我们可以将拥有共同主题的函数放在一个后缀名为py的python函数中

• Use import command to access 我们就可以使用导入命令将这些函数导入计算中

Example 例子

 

确保存到一个文件里取名circle.py

 

 

 

符号 . 表示从点之前的模块中读取点之后的函数或数

 

 

Pi=0 这是在全局环境中定义的

所以会输出pi=0

Area是circle中的函数,函数环境中的定义pi=3.14,所有使用这个3.14

 

两种导入模块的方法

其一,

 

import modname : 模块是指一个可以交互使用,或者从另一Python程序访问的代码段。只要导入了一个模块,就可以引用它的任何公共的函数、类或属性。模块可以通过这种方法来使用其它模块的功能。

 

用import语句导入模块,就在当前的名称空间(namespace)建立了一个到该模块的引用.这种引用必须使用全称,也就是说,当使用在被导入模块中定义的函数时,必须包含模块的名字。所以不能只使用 funcname,而应该使用 modname.funcname

 

其二,

from modname importfuncname

from modname import fa,fb, fc

或者  from modname import *

与第1种方法的区别:funcname 被直接导入到本地名字空间去了,所以它可以直接使用,而不需要加上模块名的限定

* 表示,该模块的所有公共对象(public objects)都被导入到 当前的名称空间,也就是任何只要不是以”_”开始的东西都会被导入。

modname没有被定义,所以modname.funcname这种方式不起作用。并且,如果funcname如果已经被定义,它会被新版本(该导入模块中的版本)所替代。如果funcname被改成指向其他对象,modname不能不会觉察到。

建议:

 

1)如果你要经常访问模块的属性和方法,且不想一遍又一遍地敲入模块名,使用 frommodule import

2)如果你想要有选择地导入某些属性和方法,而不想要其它的,使用 from moduleimport

3)如果模块包含的属性和方法与你的某个模块同名,你必须使用import module来避免名字冲突

4)尽量少用 from module import *,因为判定一个特殊的函数或属性是从哪来的有些困难,并且会造成调试和重构都更困难。

 

 

 

 

 

总结

我们学习了函数内的计算方法,函数是允许我们将计算细节和函数的使用分开来的一种功能,也叫黑盒抽象。

还引入了名为环境的形式,环境帮助我们进行可视化处理,观察如何使用python解释器中的函数将名字分配给相应的值,如何检索数值 

 

 

 

Yeah~~~~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值