《Composing Programs》(SICP python版) chap1 笔记
Posted 临风而眠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Composing Programs》(SICP python版) chap1 笔记相关的知识,希望对你有一定的参考价值。
《Composing Programs》(SICP python版) chap1 笔记(2)
文章目录
- 《Composing Programs》(SICP python版) chap1 笔记(2)
- Chapter 1: Building Abstractions with Functions
- basic knowledge and skills
- 致敬一下python tutor的作者 Or2
- 总结
- 总结
- 相关资源
呃 下面很多笔记是直接照搬的textbook,其实很多地方是想积累英文表达,
但这样子就缺乏了自己概括的过程,从下一篇笔记开始把积累英文表达和概括给分开来…
不要嫌配置环境麻烦, 这次代码用阿里云服务器来跑,再熟悉一下各种操作
Chapter 1: Building Abstractions with Functions
下面会介绍很多代码风格,感觉给出的python 官方的一些链接也要自己去看看
1.3 Defining New Functions
-
这里是怎么介绍abstraction 的呢
- Binding names to values provides a limited means of abstraction
- function definitions, a much more powerful abstraction technique by which a name can be bound to compound operation, which can be referred to as a unit.
-
How to define a function
-
Function consists of a
def
statement that idicates a<name>
and a comma-separated list of named<formal parameters>
, then areturn
statement, called the function body, that specifies the<return expression>
of the function, which is an expression to be evaluated whenever the function is applied:def <name> (<formal parameters>): return <return expression>
-
The second line must be indented(most programmers use four spaces to indent). The return expression is not evaluated right away; it is stored as part of the newly defined function and evaluated only when the function is eventually applied.
-
1.3.1 Environments
用pythontutor来讲真的太棒
-
引入,提出问题
Our subset of Python is now complex enough that the meaning of programs is non-obvious. What if a formal parameter has the same name as a built-in function? Can two functions share names without confusion?
-
An environment in which an expression is evaluated consists of a sequence of frames, depicted as boxes.
-
Each frame contains bindings, each of which associates a name with its corresponding value. There is a single global frame. Assignment and import statements add entries to the first frame of the current environment.
So far, our environment consists only of the global frame.
此处引入对pythontutor的介绍
This environment diagram shows the bindings of the current environment, along with the values to which names are bound. The environment diagrams in this text are interactive: you can step through the lines of the small program on the left to see the state of the environment evolve on the right. You can also click on the “Edit code in Online Python Tutor” link to load the example into the Online Python Tutor, a tool created by Philip Guo for generating these environment diagrams. You are encouraged to create examples yourself and study the resulting environment diagrams.
-
Functions appear in environment diagrams as well, An
import
statement(语句) binds a name to a built-in function. Adef
statement binds a name to a user-defined function created by the definition.
The resulting environment after importing
mul
and definingsquare
appears above.
-
Each function is a line that starts with
func
, followed by the function name and formal parameters(形式参数). Built-in functions such asmul
do not have formal parameter names, and so...
is always used instead. -
The name of a function is repeated twice, once in the frame and again as part of the function itself. The name appearing in the function is called the intrinsic name. The name in a frame is a bound name. There is a difference between the two: different names may refer to the same function, but that function itself has only one intrinsic name.
The name bound to a function in a frame is the one used during evaluation. The intrinsic name of a function does not play a role in evaluation. Step through the example below using the Forward button to see that once the name
max
is bound to the value 3, it can no longer be used as a function.The error message
TypeError: 'int' object is not callable
is reporting that the namemax
(currently bound to the number 3) is an integer and not a function. Therefore, it cannot be used as the operator in a call expression.我再来试试
Function Signatures(看语境翻译为函数原型比较好)
- Functions differ in the number of arguments that they are allowed to take. To track these requirements, we draw each function in a way that shows the function name and its formal parameters. The user-defined function
square
takes onlyx
; providing more or fewer arguments will result in an error. A description of the formal parameters of a function is called the function’s signature. - The function
max
can take an arbitrary number of arguments. It is rendered asmax(...)
. Regardless of the number of arguments taken, all built-in functions will be rendered as<name>(...)
, because these primitive functions were never explicitly defined.
1.3.2 Calling User-Defined Funcitons
-
调用函数的过程:
To evaluate a call expression whose operator names a user-defined function, the Python interpreter follows a computational process. As with any call expression, the interpreter evaluates the operator and operand expressions, and then applies the named function to the resulting arguments.
-
Applying a user-defined function introduces a second local frame, which is only accessible to that function. To apply a user-defined function to some arguments:↳
- Bind the arguments to the names of the function’s formal parameters in a new local frame.
- Execute the body of the function in the environment that starts with this frame.
Name Evaluation
The order of frames in an environment affects the value returned by looking up a name in an expression. We stated previously that a name is evaluated to the value associated with that name in the current environment.
We can now be more precise:
- A name evaluates to the value bound to that name in the earlist frame of the current environment in which that name is found.
1.3.3 Example: Calling a User-Defined Function
例1(我把1.3.2的搬过来了)
from operator import mul
def square(x):
return mul(x, x)
square(-2)
-
After executing the first import statement, only the name
mul
is bound in the global frame -
First, the definition statement for the function
square
is executed. Notice that the entiredef
statement is processed in a single step. The body of a function is not executed until the function is called (not when it is defined). -
Next, the
square
function is called with the argument -2, and so a new frame is created with the formal parameterx
bound to the value -2.
-
Then, the name
x
is looked up in the current environment, which consists of the two frames shown. In both occurrences,x
evaluates to -2, and so thesquare
function returns 4.The “Return value” in the
square()
frame is not a name binding; instead it indicates the value returned by the function call that created the frame.
Even in this simple example, two different environments are used. The top-level expression square(-2)
is evaluated in the global environment, while the return expression mul(x, x)
is evaluated in the environment created for by calling square
. Both x
and mul
are bound in this environment, but in different frames.
例2
Let us again consider our two simple function definitions and illustrate the process that evaluates a call expression for a user-defined function.
from operator import add, mul
def square(x):
return mul(x, x)
def sum_squares(x, y):
return add(square(x), square(y))
result = sum_squares(5, 12)
-
Python first evaluates the name
sum_squares
, which is bound to a user-defined function in the global frame. The primitive numeric expressions 5 and 12 evaluate to the numbers they represent. -
Next, Python applies
sum_squares
, which introduces a local frame that bindsx
to 5 andy
to 12. -
The body of
sum_squares
contains this call expression:add ( square(x) , square(y) ) ________ _________ _________ operator operand 0 operand 1
- All three subexpressions are evaluated in the current environment, which begins with the frame labeled
sum_squares()
. - The operator subexpression
add
is a name found in the global frame, bound to the built-in function for addition. - The two operand subexpressions must be evaluated in turn(依次,轮流), before addition is applied.
- Both operands are evaluated in the current environment beginning with the frame labeled
sum_squares
.
- All three subexpressions are evaluated in the current environment, which begins with the frame labeled
-
In operand 0,
squares
names a user-defined function in the global frame, whilex
names the number 5 in the local frame. Python appliessquare
to 5 by introducing yet another local frame that bindsx
to 5. -
Using this environment, the expression
mul(x, x)
evaluates to 25. -
Our evaluation procedure now turns to
operand 1
,for whichy
names the number 12. Python evaluates the body ofsquare
again, this time introducing yet another local frame that bindsx
to 12. Hence,operand 1
evaluates to 144. -
Finally, applying addition to the arguments 25 and 144 yields a final return value for
sum_squares
: 169
This example illustrates many of the fundamental ideas we have developed so far.
- Names are bound to values, which are distributed across many independent local frames, along with a single global frame that contains shared names.
- A new local frame is introduced every time a function is called, even if the same function is called twice.
All of this machinery exists to ensure that names resolve to the correct values at the correct times during program execution. This example illustrates why our model requires the complexity that we have introduced. All three local frames contain a binding for the name x
, but that name is bound to different values in different frames. Local frames keep these names separate.
1.3.4 Local Names
One detail of a function’s implementation that should not affect the function’s behavior is the implementer’s choice of names for the function’s formal parameters. Thus, the following functions should provide the same behavior:
>>> def square(x):
return mul(x, x)
>>> def square(y):
return mul(y, y)
This principle – that the meaning of a function should be independent of the parameter names chosen by its author – has important consequences for programming languages. The simplest consequence is that the parameter names of a function must remain local to the body of the function.
If the parameters were not local to the bodies of their respective functions, then the parameter x
in square
could be confused with the parameter x
in sum_squares
. Critically, this is not the case: the binding for x
in different local frames are unrelated. The model of computation is carefully designed to ensure this independence.
We say that the scope of a local name is limited to the body of the user-defined function that defines it. When a name is no longer accessible, it is out of scope. This scoping behavior isn’t a new fact about our model; it is a consequence of the way environments work.
1.3.5 Choosing Names
-
The interchangeability of names does not imply that formal parameter names do not matter at all. On the contrary, well-chosen function and parameter names are essential for the human interpretability of function definition.
-
下面的一些 guidelines are adapted from the style guide for Python code
A shared set of conventions smooths communication among members of a developer community.
- Function names are lowercase, with words separated by underscores. Descriptive names are encouraged.(鼓励见名知意)
- Function names typically evoke operations applied to arguments by the interpreter (e.g.,
print
,add
,square
) or the name of the quantity that results (e.g.,max
,abs
,sum
). - Parameter names are lowercase, with words separated by underscores. Single-word names are preferred.
- Parameter names should evoke the role of the parameter in the function, not just the kind of argument that is allowed.
- Single letter parameter names are acceptable when their role is obvious, but avoid “l” (lowercase ell), “O” (capital oh), or “I” (capital i) to avoid confusion with numerals.
There are many exceptions to these guidelines, even in the Python standard library. Like the vocabulary of the English language, Python has inherited words from a variety of contributors, and the result is not always consistent.
1.3.6 Funcitons as Abstractions
-
1.3.3 中例二的
sum_squares
是根据函数square
定义的,但是只依赖于square
定义的输入参数和输出值之间的关系只关心square的输入输出,中间是怎样的并不关心
-
We can write
sum_squares
without concerning ourselves with how to square a number. The details of how the square is computed can be supressed, to be considered at a later time. -
As far as
sum_squares
is concerned,square
is not a particular function body, but rather an abstraction of a function, a so-called functional abstraction. At this level of abstraction, any function tha computes the square is equally good. -
Thus, considering only the values they return, the following two funcitons for squaring a number should be indistinguishable. Each takes a numerical argument and produces the square of that number as the value.
>>> def square(x):
return mul(x, x)
>>> def square(x):
return mul(x, x-1) + x
-
In other words, a function definition should be able to suppress details.
这里就是封装思想
-
The users of the function may not have written the function themselves, but may have obtained it from another programmer as a “black box”. A programmer should not need to know how the function is implemented in order to use it. The Python Library has this property. Many developers use the functions defined there, but few ever inspect their implementation.
Aspects of a functional abstraction
To master the use of a functional abstraction, it is often useful to consider its three core attributes.
- The domain of a function is the set of arguments it can take.
- The range of a function is the set of values it can return.
- The intent of a function is the relationship it computes between inputs and output (as well as any side effects it might generate).
- Understanding functional abstractions via their domain, range, and intent is critical to using them correctly in a complex program.
For example, any square
function that we use to implement sum_squares
should have these attributes:
- The domain is any single real number.
- The range is any non-negative real number.
- The intent is that the output is the square of the input.
These attributes do not specify how the intent is carried out; that detail is abstracted away.
1.3.7 Operations
- Mathematical operators (such as
+
and-
) provided our first example of a method of combination, but we have yet to define an evaluation procedure for expressions that contain these operators. - Python expressions with infix operators (中缀运算符)each have their own evaluation procedures, but you can often think of them as short-hand(简写形式) for call expressions.
比如
>>> 2 + 3
5
# simply consider it to be short-hand for
>>> add(2, 3)
5
- Infix notation can be nested, just like call expressions. Python applies the normal mathematical rules of operator precedence, which dictate how to interpret a compound expression with multiple operators.
>>> 2 + 3 * 4 + 5
19
evaluates to the same result as
>>> add(add(2, mul(3, 4)), 5)
19
-
The nesting in the call expression is more explicit than the operator version, but also harder to read.
Python also allows subexpression grouping with parentheses(圆括号), to override the normal precedence(优先) rules (优先级) or make the nested structure of an expression more explicit.
>>> (2 + 3) * (4 + 5) 45 evaluates to the same result as >>> mul(add(2, 3), add(4, 5)) 45
-
Python的除法
- Python provides two infix operators:
/
and//
.
- Python provides two infix operators:
-
The former is normal division, so that it results in a floating point, or decimal value, even if the divisor evenly divides the dividend:↳
>>> 5 / 4 1.25 >>> 8 / 4 2.0
The
//
operator, on the other hand, rounds the result down to an integer:>>> 5 // 4 1 >>> -5 // 4 -2
These two operators are shorthand for the
truediv
andfloordiv
functions.>>> from operator import truediv, floordiv >>> truediv(5, 4) 1.25 >>> floordiv(5, 4) 1
You should feel free to use infix operators and parentheses in your programs. Idiomatic Python prefers operators over call expressions for simple mathematical operations.
1.4 Designing Functions
We now turn to the topic of what makes a good function.
Fundamentally, the qualities of good functions all reinforce the idea that functions are good abstractions.
- Each function should have exactly one job.
- That job should be identifiable(能被识别的) with a short name and characterizable in a single line of text.
- Functions that perform multiple jobs in sequence should be divided into multiple functions.
- Don’t repeat yourself is a central tenet(原则) of software engineering. The so-called DRY principle states that multiple fragments of code should not describe redundant(多余的) logic.
- Instead, that logic should be implemented once, given a name, and applied multiple times.
- If you find yourself copying and pasting a block of code, you have probably found an opportunity for functional abstraction.
- Functions should be defined generally. Squaring is not in the Python Library precisely because it is a special case of the
pow
function, which raises numbers to arbitrary powers(任意幂).
1.4.1 Documentation
-
A function definition will often include documentation describing the function, called a docstring, which must be intended along with the function body.
-
Docstrings are conventionally triple quoted.
-
The first line describes the job of the function in one line. The following lines can describe arguments and clarify the behavior of the function:
def pressure(v, t, n): """Compute the pressure in pascals of an ideal gas. Applies the ideal gas law: http://en.wikipedia.org/wiki/Ideal_gas_law v -- volume of gas, in cubic meters t -- absolute temperature in degrees kelvin n -- particles of gas """ k = 1.38e-23 # Boltzmann's constant return n * k * t / v
-
When you call
help
with the name of a function as an argument, you see its docstring (typeq
to quit Python help).Orz 原来help也能看自己写的func
-
When writing Python programs, include docstrings for all but the simplest functions. (除了最简单的函数之外,所有的函数都要包含文档)
-
Remember, code is written only once, but often read many times.
-
The Python docs include docstring guidelines that maintain consistency across different Python projects.
Comment 注释
- Comments in Python can be attached to the end of a line following the
#
symbol. - 比如上面那段代码中
- the comment
Boltzmann's constant
above describesk
.
- the comment
- These comments don’t ever appear in Python’s
help
, and they are ignored by the interpreter. They exist for humans alone.
1.4.2 Default Argument Values
A consequence of defining general functions is the introduction of additional arguments. Functions with many arguments can be awkward to call and difficult to read.
In Python, we can provide default values for the arguments of a function. When calling that function, arguments with default values are optional. If they are not provided, then the default value is bound to the formal parameter name instead. For instance, if an application commonly computes pressure for one mole of particles, this value can be provided as a default:
def pressure(v, t, n=6.022e23):
"""Compute the pressure in pascals of an ideal gas.
v -- volume of gas, in cubic meters
t -- absolute temperature in degrees kelvin
n -- particles of gas (default: one mole)
"""
k = 1.38e-23 # Boltzmann's constant
return n * k * t / v
The =
symbol means two different things in this example, depending on the context in which it is used.
In the def
statement header, =
does not perform assignment, but instead indicates a default value to use when the pressure
function is called. By contrast, the assignment statement to k
in the body of the function binds the name k
to an approximation of Boltzmann’s constant.
The pressure
function is defined to take three arguments, but only two are provided in the first call expression above. In this case, the value for n
is taken from the def
statement default. If a third argument is provided, the default is ignored.
As a guideline, most data values used in a function’s body should be expressed as default values to named arguments, so that they are easy to inspect and can be changed by the function caller. Some values that never change, such as the fundamental constant k
, can be bound in the function body or in the global frame.
1.5 Control
感觉每一小节的引言都写得很好,娓娓道来,承上启下,令人恍然大悟
The expressive power of the functions that we can define at this point is very limited, because we have not introduced a way to make comparisons and to perform different operations depending on the result of a comparison. Control statements will give us this ability. They are statements that control the flow of a program’s execution based on the results of logical comparisons.
Statements differ fundamentally from the expressions that we have studied so far. They have no value. Instead of computing something, executing a control statement determines what the interpreter should do next.
1.5.1 Statements
-
So far, we have primarily considered how to evaluate expressions(计算表达式).
-
我们已学的三种statements(语句)
- assignment
def
return
These lines of Python code are not themselves expressions, although they all contain expressions as components.
-
Rather than being evaluated, statements are executed.
- Each statement describes some change to the interpreter state, and executing a statement applies that change.
- As we have seen for
return
and assignment statements, executing statements can involve evaluating subexpressions contained within them.
-
Expressions can also be executed as statements, in which case they are evaluated, but their value is discarded. Executing a pure function has no effect, but executing a non-pure function can cause effects as a consequence of function application.
例如
>>> def square(x): mul(x, x) # Watch out! This call doesn't return a value.
This example is valid Python, but probably not what was intended. The body of the function consists of an expression. An expression by itself is a valid statement, but the effect of the statement is that the
mul
function is called, and the result is discarded. If you want to do something with the result of an expression, you need to say so: you might store it with an assignment statement or return it with a return statement:>>> def square(x): return mul(x, x)
-
Sometimes it does make sense to have a function whose body is an expression, when a non-pure function like
print
is called.>>> def print_square(x): print(square(x))
At its highest level, the Python interpreter’s job is to execute programs, composed of statements. However, much of the interesting work of computation comes from evaluating expressions. Statements govern the relationship among different expressions in a program and what happens to their results.
- 小结一下
- 要分清statement 和 expression
- interpreter 是去 execute statement
1.5.2 Compound Statements
-
In general, Python code is a sequence of statements.
-
A simple statement is a single line that doesn’t end in a colon. A compound statement is so called because it is composed of other statements (simple and compound). Compound statements typically span multiple lines and start with a one-line header ending in a colon(冒号), which identifies the type of statement. Together, a header and an indented suite of statements is called a clause. A compound statement consists of one or more clauses:
<header>: <statement> <statement> ... <separating header>: <statement> <statement> ... ...
-
We can understand the statements we have already introduced in these terms.
- Expressions, return statements, and assignment statements are simple statements.
- A
def
statement is a compound statement. The suite that follows thedef
header defines the function body.
-
Specialized evaluation rules for each kind of header dictate when and if the statements in its suite are executed. We say that the header controls its suite. For example, in the case of
def
statements, we saw that the return expression is not evaluated immediately, but instead stored for later use when the defined function is eventually called. -
We can also understand multi-line programs now.
- To execute a sequence of statements, execute the first statement. If that statement does not redirect(改变方向) control, then proceed(继续) to execute the rest of the sequence of statements, if any remain.
-
This definition exposes the essential structure of a recursively defined sequence: a sequence can be decomposed(分解) into its first element and the rest of its elements. The “rest” of a sequence of statements is itself a sequence of statements! Thus, we can recursively apply this execution rule. This view of sequences as recursive data structures will appear again in later chapters.
-
The important consequence of this rule is that statements are executed in order, but later statements may never be reached, because of redirected control(重定向控制).
Practical Guidance. When indenting a suite, all lines must be indented the same amount and in the same way (use spaces, not tabs). Any variation in indentation will cause an error.
- 小总结一下
- 函数的
def
statement 其实就是复合语句 - 多行程序的执行
- 首先执行第一个语句,如果这个语句没有重定向控制,就往后继续执行
- 复合语句可以用递归的思想来看,看作一个递归定义的sequence结构,每次都分为 first element 和 the rest of its elements.
- 函数的
1.5.3 Defining Functions II: Local Assignment
Originally, we stated that the body of a user-defined function consisted only of a return
statement with a single return expression. In fact, functions can define a sequence of operations that extends beyond a single expression.
Whenever a user-defined function is applied, the sequence of clauses in the suite of its definition is executed in a local environment — an environment starting with a local frame created by calling that function. A return
statement redirects control: the process of function application terminates whenever the first return
statement is executed, and the value of the return
expression is the returned value of the function being applied.
Assignment statements can appear within a function body. For instance, this function returns the absolute difference between two quantities as a percentage of the first, using a two-step calculation:
The effect of an assignment statement is to bind a name to a value in the first frame of the current environment.
As a consequence, assignment statements within a function body cannot affect the global frame.
The fact that functions can only manipulate their local environment is critical to creating modular programs, in which pure functions interact only via the values they take and return.
Of course, the percent_difference
function could be written as a single expression, as shown below, but the return expression is more complex.
>>> def percent_difference(x, y):
return 100 * abs(x-y) / x
>>> percent_difference(40, 50)
25.0
So far, local assignment hasn’t increased the expressive power of our function definitions. It will do so, when combined with other control statements.
In addition, local assignment also plays a critical role in clarifying the meaning of complex expressions by assigning names to intermediate quantities.
- 小结
return
statement 可以 redirect control- 函数内部的赋值语句不会影响global frame , functions can only manipulate their local environment
1.5.4 Conditional Statements
从绝对值(absolute values)引入
-
We would like to express that if
x
is positive,abs(x)
returnsx
. Furthermore, ifx
is 0,abs(x)
returns 0. Otherwise,abs(x)
returns-x
. In Python, we can express this choice with a conditional statement.def absolute_value(x): """Compute abs(x).""" if x > 0: return x elif x == 0: return 0 else: return -x result = absolute_value(-2)
-
This implementation of
absolute_value
raises several important issues:Conditional statements. A conditional statement in Python consists of a series of headers and suites: a required
if
clause, an optional sequence ofelif
clauses, and finally an optionalelse
clause:if <expression>: <suite> elif <expression>: <suite> else: <suite>
When executing a conditional statement, each clause is considered in order. The computational process of executing a conditional clause follows.
- Evaluate the header’s expression.
- If it is a true value, execute the suite. Then, skip over all subsequent clauses in the conditional statement.
If the
else
clause is reached (which only happens if allif
andelif
expressions evaluate to false values), its suite is executed.Boolean contexts. Above, the execution procedures mention “a false value” and “a true value.” The expressions inside the header statements of conditional blocks are said to be in boolean contexts: their truth values matter to control flow, but otherwise their values are not assigned or returned. Python includes several false values, including 0,
None
, and the boolean valueFalse
. All other numbers are true values.Boolean values. Python has two boolean values, called
True
andFalse
. Boolean values represent truth values in logical expressions. The built-in comparison operations,>, <, >=, <=, ==, !=
, return these values.>>> 4 < 2 False >>> 5 >= 5 True
This second example reads “5 is greater than or equal to 5”, and corresponds to the function
ge
in theoperator
module.>>> 0 == -0 True
This final example reads “0 equals -0”, and corresponds to
eq
in theoperator
module. Notice that Python distinguishes assignment (=
) from equality comparison (==
), a convention shared across many programming languages.Boolean operators. Three basic logical operators are also built into Python:
>>> True and False False >>> True or False True >>> not False True
短路效应
Logical expressions have corresponding evaluation procedures. These procedures exploit the fact that the truth value of a logical expression can sometimes be determined without evaluating all of its subexpressions, a feature called short-circuiting.(短路)
-
To evaluate the expression
<left> and <right>
:- Evaluate the subexpression
<left>
. - If the result is a false value
v
, then the expression evaluates tov
. - Otherwise, the expression evaluates to the value of the subexpression
<right>
.
- Evaluate the subexpression
-
To evaluate the expression
<left> or <right>
:- Evaluate the subexpression
<left>
. - If the result is a true value
v
, then the expression evaluates tov
. - Otherwise, the expression evaluates to the value of the subexpression
<right>
.
- Evaluate the subexpression
-
To evaluate the expression
not <exp>
:- Evaluate
<exp>
; The value isTrue
if the result is a false value, andFalse
otherwise.
- Evaluate
These values, rules, and operators provide us with a way to combine the results of comparisons. Functions that perform comparisons and return boolean values typically begin with is
, not followed by an underscore (e.g., isfinite
, isdigit
, isinstance
, etc.).
1.5.5 Iteration
Only through repeated execution of statements do we unlock the full potential of computers. Iterative control structures can execute the same statements many times.
Consider the sequence of Fibonacci numbers, in which each number is the sum of the preceding two:
0, 1, 1, 2, 3, 5, 8, 13, 21, ...
Each value is constructed by repeatedly applying the sum-previous-two rule. The first and second are fixed to 0 and 1. For instance, the eighth Fibonacci number is 13.
We can use a while
statement to enumerate n
Fibonacci numbers. We need to track how many values we’ve created (k
), along with the kth value (curr
) and its predecessor (pred
). Step through(单步调试) this function and observe how the Fibonacci numbers evolve one by one, bound to curr
.
def fib(n):
"""Compute the nth Fibonacci number, for n >= 2."""
pred, curr = 0, 1 # Fibonacci numbers 1 and 2
k = 2 # Which Fib number is curr?
while k < n:
pred, curr = curr, pred + curr
k = k + 1
return curr
result = fib(8)
-
pred, curr = curr, pred + curr
是python里的多重赋值 -
A while clause contains a header expression followed by a suite:
while <expression>: <suite>
To execute a
while
clause:- Evaluate the header’s expression.
- If it is a true value, execute the suite, then return to step 1.
In step 2, the entire suite of the
while
clause is executed before the header expression is evaluated again.In order to prevent the suite of a
while
clause from being executed indefinitely, the suite should always change some binding in each pass.A
while
statement that does not terminate is called an infinite loop. Press<Control>-C
to force Python to stop looping.
1.5.6 Testing
-
Testing a function is the act of verifying that the function’s behavior matches expectations.
A test is a mechanism for systematically performing this verification. Tests typically take the form of another function that contains one or more sample calls to the function being tested. The returned value is then verified against an expected result. Unlike most functions, which are meant to be general, tests involve selecting and validating calls with specific argument values. Tests also serve as documentation: they demonstrate how to call a function and what argument values are appropriate.
Assertions
Programmers use assert statements to verify expectations, such as the output of a fu
以上是关于《Composing Programs》(SICP python版) chap1 笔记的主要内容,如果未能解决你的问题,请参考以下文章
5.8 Components — Composing Components(组合组件)
Android Studio使用Composing builds统一依赖管理
Android Studio使用Composing builds统一依赖管理
Codeforce 1335C - Two Teams Composing 统计技能种类数量+统计同一技能最大数量
Extracting and composing robust features with denosing autoencoders 论文