Chapter 1 Building Abstractions with Functions

1.1 Getting Started

A language isn’t something you learn so much as something you join.

The line of Python code

>>> from urllib.request import urlopen

is an import statement that loads functionality for accessing data on the Internet . In particular, it makes available a function called urlopen, which can access the content at a uniform resource locator (URL), a location of something on the Internet.

The assignment statement

>>> Shakespeare = urlopen('http://'composingprograms.com/shakespeare.txt)

associates the name Shakespeare with the value of the expression that follows = . That expression applies the urlopen function to a URL that contains the complete text of William Shakespeare’s 37 plays, all in a single text document.

Another assignment statement

>>> words = set(shakespeare.read().decode().split() )

associates the name words to the set of all unique words that appear in Shakespeare’s plays, all 33721 of them. The chain of commands to read, decode, and spilt, each operate on an intermediate computational entity: we read the data from the opened URL, then decode the data into text, and finally spilt the text into words, All of those words are placed in a set.

A set is a type of object , Objects are the primary topic of Chapter 2

The expression

>>> {w for w in words if len(w) == 6 and w[::-1] in words}
{'redder', 'drawer', 'reward', 'diaper', 'repaid'}

is a compound expression that evaluates to the set of all Shakespearian words that are simultaneously a word spelled in reverse. The cryptic notation w[::-1] enumerates each letter in a word, but the -1 dictates to step backwards. When you enter an expression in an interactive session, Python prints its value on following line.

An interpreter is a program that implements such a procedure, evaluating compound expressions, is called an interpreter. The design and implementation of interpreters is the primary topic of Chapter 3.

Functions are objects, objects are functions, and interpreters are instances of both.

computer = powerful + stupid

Debugging: learning to interpret errors and diagnose the cause of unexpected errors.

Some guiding principles of debugging are:

  1. Test incrementally
  2. Isolate errors
  3. Check your assumptions
  4. Consult others
1.2 Elements of Programming

programs must be written for people to read, and only incidentally for machines to execute.

Every powerful language has three such mechanisms:

  • primitive expression and statements, which represent the simplest building blocks that the language provides,
  • means of combination, by which compound elements are built from simpler ones, and
  • means of abstraction, by which compound elements can be named and manipulated as units.

In programming, we deal with two kinds of elements: functions and data.

Expressions

>>> 42
42

Expressions representing numbers may be combined with mathematical operators to form a compound expression, which the interpreter will evaluate:

>>> -1 - -1
0
>>> 1/2 + 1/4 + 1/8 + 1/16 + 1/32 + 1/64 + 1/128
0.9921875

These mathematical expressions use infix (中缀)notation, where the operator appears in between the operands.

Call Expressions

>>> max(7.5, 9.5) 
9.5

we say that the function max is called with arguments 7.5 and 9.5, and returns a value of 9.5.

>>> pow(100, 2)
10000

>>> pow(2, 100)
1267650600228229401496703205376

Function notation has three principle advantages over the mathematical convention of infix notation.

First, functions may take an arbitrary(任意的) number of argument.

>>> max(min(1, -2), min(pow(3, 5), -4))
-2

No ambiguity can arise, because the function name always precedes its arguments.

Second, function notation extends in a straightforward way to nested (嵌套) expressions, where the elements are themselves compound expressions. In nested call expressions, unlike compound infix expressions, the structure of the nesting is entirely explicit in the parentheses.

>>> max(min(1, -2), min(pow(3, 5), -4))
-2

There is no limit (in principle) to the depth of such nesting and to the overall complexity of the expressions that the Python interpreter can evaluate.

Third, mathematical notation has a great variety of forms: multiplication appears between terms, exponents appear as superscripts, division as a horizontal bar, and a square root as a roof with slanted siding. Some of this notation is very hard to type! However, all of this complexity can be unified via the notation of call expressions. While Python supports common mathematical operators using infix notation (like + and -), any operator can be expressed as a function with a name.

Importing Library Functions

the math module provides a variety of familiar mathematical functions:

>>> from math import sqrt
>>> sqrt(256)
16.0

and the operator module provides access to functions corresponding to infix operators:

>>> from operator import add, sub, mul
>>> add(14, 28)
42
>>> sub(100, mul(7, add(8, 4)))
16

An import statement designates a module name (E.g., operator or math), and then lists the named attributes of that module to import (E.g., sqrt). Once a function is imported, it can be called multiple times.

There is no difference between using these operator functions (E.g., add) and the operator symbols themselves (E.g., +). Conventionally, most programmers use symbols and infix notation to express simple arithmetic.

Python 3 Library Docs

Names and the Environment

establish new bindings using the assignment statement, which contains a name to the left of = and a value to the right:

>>> radius = 10
>>> radius
10
>>> 2 * radius
20

Names are also bound via import statements.

>>> from math import pi
>>> pi * 71 / 223
1.0002380197528042

The = symbol is called the assignment operator in Python (and many other languages). Assignment is our simplest means of abstraction, for it allows us to use simple names to refer to the results of compound operations, such as the area computed above. In this way, complex programs are constructed by building, step by step, computational objects of increasing complexity.

The possibility of binding names to values and later retrieving(检索) those values by name means that the interpreter must maintain some sort of memory that keeps track of the names, values, and bindings. This memory is called an environment.

Names can also be bound to functions. For instance, the name max is bound to the max function we have been using. Functions, unlike numbers, are tricky to render as text, so Python prints an identifying description instead, when asked to describe a function:

>>> max
<built-in function max>

We can use assignment statements to give new names to existing functions.

>>> f = max
>>> f
<built-in function max>
>>> f(2, 3, 4)
4

And successive assignment statements can rebind a name to a new value.

>>> f = 2
>>> f
2

In Python, names are often called variable names or variables because they can be bound to different values in the course of executing a program. When a name is bound to a new value through assignment, it is no longer bound to any previous value. One can even bind built-in names to new values.

>>> max = 5
>>> max
5

After assigning max to 5, the name max is no longer bound to a function, and so attempting to call max(2, 3, 4) will cause an error.

When executing an assignment statement, Python evaluates the expression to the right of = before changing the binding to the name on the left. Therefore, one can refer to a name in right-side expression, even if it is the name to be bound by the assignment statement.

>>> x = 2
>>> x = x + 1
>>> x
3

We can also assign multiple values to multiple names in a single statement, where names on the left of = and expressions on the right of = are separated by commas.

>>> area, circumference = pi * radius * radius, 2 * pi * radius
>>> area
314.1592653589793
>>> circumference
62.83185307179586

Changing the value of one name does not affect other names. Below, even though the name area was bound to a value defined originally in terms of radius, the value of area has not changed. Updating the value of area requires another assignment statement.

>>> radius = 11
>>> area
314.1592653589793
>>> area = pi * radius * radius
380.132711084365

With multiple assignment, all expressions to the right of = are evaluated before any names to the left are bound to those values. As a result of this rule, swapping the values bound to two names can be performed in a single statement.

>>> x, y = 3, 4.5
>>> y, x = x, y
>>> x
4.5
>>> y
3

Evaluating Nested Expressions

见Lecture 1

The Non-Pure Print Function

Pure functions: Functions have some input (their arguments) and return some output (the result of applying them).

Pure functions have the property that applying them has no effects beyond returning a value. Moreover, a pure function must always return the same value when called twice with the same arguments.

Non-pure functions: In addition to returning a value, applying a non-pure function can generate side effects, which make some change to the state of the interpreter or computer. A common side effect is to generate additional output beyond the return value, using the print function.

A nested expression of calls to print highlights the non-pure character of the function.

>>> print(print(1), print(2))
1
2
None None

If you find this output to be unexpected, draw an expression tree to clarify why evaluating this expression produces this peculiar output.

Be careful with print! The fact that it returns None means that it should not be the expression in an assignment statement.

>>> two = print(2)
2
>>> print(two)
None
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值