第 01 章

函数与变量:从 hello, world 到自己的函数

CS50P 第一讲:用文本编辑器与终端写出第一个 Python 程序,理解函数、参数与副作用,掌握变量、字符串方法、int 与 float 的转换和格式化,最后用 def、return 与作用域写出自己的函数。

Functions and Variables: From hello, world to Your Own Functions

CS50P week 0: write a first Python program with a text editor and a terminal, understand functions, arguments and side effects, work with variables, string methods, int and float conversions and formatting, then define your own functions with def, return and scope.

首发于 2023.05.01中 / EN
系统课程pythonfunctionsvariablesstringscs50
语言
字号
目录
篇内目录

这一章在讲什么

这是 CS50P 十次讲座里的第一次,主题是函数与变量。整门课原本是一个约 16 小时、没有分章的长视频,本章对应开头的课程导论与第 0 周讲座(00:00–1:50:39)。

导论部分先交代整门课的路线:函数与变量 → 条件 → 循环 → 异常 → 库 → 单元测试 → 文件读写 → 正则表达式 → 面向对象 → 收尾。随后正式开讲,从一行 print 出发,把「写代码、跑代码、出错、修错」的完整循环走一遍,再逐步加入输入、变量、字符串处理、数值类型,最后落到自定义函数与作用域。

这一章的目标不是记住语法,而是建立几个会贯穿全课的心智模型:函数是动词,参数是输入,副作用是函数对外界的影响,返回值是函数交还给调用者的东西;变量是内存里的容器,= 是赋值而不是相等;Python 按顺序、逐字面地解释你的代码。

时间轴

时间内容
0:00课程介绍:整门课的十个主题与学习方式
5:02第 0 周开始:文本编辑器、VS Code、终端
6:20第一个程序 print("hello, world") 与 python hello.py
10:00函数、参数与副作用(side effect)
12:59故意制造语法错误:未闭合的括号
16:37用 input() 让程序与用户交互
19:46变量、赋值运算符(从右到左)
24:31注释与伪代码(pseudo-code)
29:48字符串拼接:+、多参数、sep 与 end
45:34引号套引号与转义字符 \
48:10f-string:在字符串里嵌入变量
50:02字符串方法:strip、capitalize、title、split
1:03:59整数 int、算术运算与取模 %
1:05:18交互模式(REPL)
1:07:23计算器例子,以及 input 返回字符串的坑
1:19:20浮点数 float、round 与数字格式化
1:30:51自定义函数:def、参数、默认值
1:40:10函数必须先定义后使用;main() 约定
1:44:00作用域(scope)与 NameError
1:45:54return:返回值与副作用的分工

从一行代码开始

写 Python 只需要两样东西:一个文本编辑器(写代码)和一个终端(运行代码)。VS Code 同时提供两者。代码文件以 .py 结尾,告诉计算机这是 Python 程序。

第一个程序只有一行:

print("hello, world")

在终端里运行:

python hello.py

输出:

hello, world

这一行里已经包含三个核心概念:

  • 函数(function):print 是一个动作,一个动词。Python 自带一批这样的动词。
  • 参数(argument):括号里的 "hello, world" 是传给函数的输入,决定它打印什么。
  • 副作用(side effect):函数对外界产生的影响。print 的副作用就是把文字显示到屏幕上。

计算机只理解 0 和 1,print(...) 显然不是 0 和 1。负责翻译的是 Python 解释器:它从上到下、从左到右读你的文件,把每一行翻译成机器能执行的操作。

出错是常态:语法错误

漏掉右括号,程序连运行都不会开始:

print("hello, world"
  File "hello.py", line 1
    print("hello, world"
         ^
SyntaxError: '(' was never closed

一句话总结: 计算机按字面理解你写的东西。人可以忽略的笔误,对解释器来说是「这句话没说完」。

错误信息有时精准(如上例),有时含糊甚至误导。课程的建议是:读错误信息、定位行号、从最小可运行版本重新加回代码。

输入、变量与赋值

让程序问候具体的人,需要 input():

name = input("What's your name? ")
print(f"hello, {name}")

这里出现了变量。name 是内存里的一个容器,保存用户输入的文本。

关键是那个等号:它不是「相等」,而是「赋值」,方向从右到左——先计算右边的 input(...),把它的返回值放进左边的 name。

赋值可以反复进行,覆盖旧值:

name = "David"
name = name.strip()   # 右边的旧值处理后,再存回左边

为什么不能直接写 print("hello, name")

因为引号里的内容会被原样打印。去掉引号才会读取变量:

print("hello, ", name)   # 两个参数,print 自动用空格分隔

所以引号的有无,决定你打印的是「字面文本」还是「变量的值」。

注释与伪代码

# 开头的内容是注释,解释器会忽略:

# Ask user for their name
name = input("What's your name? ")

# Say hello to user
print(f"hello, {name}")

注释的另一个用途是伪代码:先用人话把步骤列出来,再逐行翻译成 Python。程序越长,这个习惯越值钱。

把字符串拼起来:五种写法

同一个「你好,某人」有五种实现,课程用它们反复强调:Python 里解决问题的方式往往不止一种。

# 1. 字符串拼接
print("hello, " + name)

# 2. print 的多个参数(自动用空格分隔)
print("hello,", name)

# 3. 覆盖 end 参数,取消自动换行
print("hello, ", end="")
print(name)

# 4. f-string(推荐)
print(f"hello, {name}")

# 5. 先拼好再打印
greeting = "hello, " + name
print(greeting)

第 2 种和第 3 种揭示了 print 的两个命名参数:

  • sep:多个参数之间的分隔符,默认是一个空格;
  • end:结尾字符,默认是换行符 \n。

print("hello,", name, sep="???") 会输出 hello,???David。这两个参数都有默认值,所以平时不用写。

引号套引号

想打印带引号的句子,会遇到冲突:

print("hello, "friend"")   # 语法错误

两种解法:外层用单引号,或给内层引号加反斜杠转义:

print('hello, "friend"')
print("hello, \"friend\"")

\ 是转义字符:它告诉 Python「下一个字符是字面字符,不是语法符号」。\n 是换行,\" 是双引号本身。

字符串方法:清理用户输入

用户输入常常带多余空格、大小写混乱。字符串自带一批方法(method)——挂在某个值上的函数,用点号调用:

name = input("What's your name? ")
name = name.strip()        # 去掉首尾空白
name = name.title()        # 每个单词首字母大写
print(f"hello, {name}")

输入 " dAvId mAlAn ",输出 hello, David Malan。

方法可以链式调用,写成一行:

name = input("What's your name? ").strip().title()

注意求值顺序:先算等号右边,从左到右依次调用 input、strip、title,最后赋值给左边。

几个常用方法:

方法作用例子
strip()去掉首尾空白" hi ".strip() → "hi"
capitalize()首字母大写,其余小写"dAvId".capitalize() → "David"
title()每个单词首字母大写"david malan".title() → "David Malan"
split(sep)按分隔符切成列表"David Malan".split(" ") → ["David", "Malan"]
lower() / upper()全部小写 / 大写"Hi".lower() → "hi"

split 常与「一次赋多个变量」配合:

first, last = input("What's your name? ").split(" ")
print(f"hello, {first}")

整数、浮点数与转换

int

整数类型 int 没有小数点。常用运算:

运算符号例子
加+1 + 2 → 3
减-5 - 2 → 3
乘*3 * 4 → 12
除/6 / 2 → 3.0(结果是 float)
取余%7 % 3 → 1

% 不是百分比,是取模:除完之后的余数。

计算器的坑:input 永远返回字符串

x = input("What's x? ")
y = input("What's y? ")
print(x + y)

输入 1 和 2,输出却是 12。原因:input 返回的是字符串,+ 对字符串执行的是拼接,不是加法。

修复需要类型转换:

x = int(input("What's x? "))
y = int(input("What's y? "))
print(x + y)      # 3

int 既是类型名,也是函数:把「看起来像整数」的字符串转成真正的整数。可以嵌套调用——先 input,再 int:

print(int(input("What's x? ")) + int(input("What's y? ")))

嵌套越深越难读,课程的建议是优先可读性,不要为了少写一行而牺牲清晰。

float 与格式化

float 是带小数点的数:

x = float(input("What's x? "))
y = float(input("What's y? "))
print(x + y)

输入 1.2 和 3.4,输出 4.6。

round 可以四舍五入,第二个参数指定保留几位小数:

z = round(x + y)          # 4.6 → 5
z = round(x / y, 2)       # 2/3 → 0.67

f-string 也能直接格式化:

print(f"{z:,}")     # 1000 → 1,000
print(f"{z:.2f}")   # 0.666... → 0.67

:, 是千位分隔符,:.2f 是保留两位小数。这些格式说明符不必背,用的时候查文档即可。

两个精度事实:

  • Python 的 int 没有上限,可以表示任意大的整数;
  • float 精度有限(约 15–17 位有效数字),2/3 只能显示成 0.6666666666666666。

定义自己的函数

当同一件事反复出现,就该给它起个名字。用 def 定义函数:

def hello(to="world"):
    print("hello,", to)

name = input("What's your name? ")
hello()
hello(name)

输出:

hello, world
hello, David

拆解:

  • def 是 define 的缩写;
  • hello 是函数名;
  • to="world" 是带默认值的参数:调用时不传参就用 world;
  • 冒号与缩进划定函数体;
  • 调用时传入的 name 是实参,函数内部的 to 是形参,两者是不同的变量。

被调用时,实参的值被复制给形参,所以函数内部改 to 不会影响外面的 name。

顺序很重要

Python 从上到下执行。函数必须先定义、后调用:

hello()        # NameError: name 'hello' is not defined

def hello():
    print("hello")

修复有两种。第一种是把定义挪到调用之前。第二种更常见:定义一个 main(),把主逻辑放进去,在文件末尾调用 main():

def main():
    name = input("What's your name? ")
    hello(name)


def hello(to="world"):
    print("hello,", to)


main()

这样 main 在前面读起来像目录,具体实现放在后面,调用 main() 放在最后一行——既符合阅读顺序,也不会触发 NameError。

作用域

在 main 里创建的变量,不能在别的函数里直接使用:

def main():
    name = input("What's your name? ")
    hello()          # 不传参

def hello():
    print("hello,", name)   # NameError: name 'name' is not defined

main()

错误的原因是作用域:name 只存在于 main 的局部作用域里,hello 看不到它。

正确做法是通过参数传递:

def main():
    name = input("What's your name? ")
    hello(name)      # 把值交出去

def hello(to="world"):
    print("hello,", to)

返回值:函数的另一种产出

有些函数没有返回值,只有副作用(print);有些函数把结果交还给你(input、int、float)。自己定义函数时,用 return 显式返回:

def main():
    x = int(input("What's x? "))
    print("x squared is", square(x))


def square(n):
    return n * n


main()

return 让函数的结果可以被继续使用——传给 print、赋给变量、参与下一次计算。副作用与返回值是函数两种不同的「输出」,写函数时应当想清楚自己要哪一种。

同样地,平方有三种写法:

def square(n):
    return n * n        # 乘法
    # return n ** 2     # 幂运算
    # return pow(n, 2)  # 内置函数

本章结论

  • 写代码 = 文本编辑器 + 终端;Python 文件以 .py 结尾,用 python 文件.py 运行。
  • 函数是动词,参数是输入,副作用是它对外界的影响,返回值是它交还的结果。
  • = 是赋值,从右到左;变量是内存中的容器,可以被反复覆盖。
  • input 永远返回字符串;要参与算术,必须用 int() 或 float() 转换。
  • print 的 sep 与 end 是命名参数,都有默认值;\ 是转义字符。
  • f-string 用于嵌入变量与格式化数字(:,、:.2f)。
  • 字符串方法用点号调用,可以链式组合;strip、title、split 最常用。
  • def 定义函数,参数可以有默认值;函数必须先定义后调用。
  • main() + 末尾调用是组织程序的惯例;局部变量只在所属函数内可见。
  • return 返回结果,与 print 的副作用是两回事。

理解检验

1. 为什么 input() 拿到的 1 和 2 相加会得到 12?写出两种修复方式。

参考答案:input() 的返回值类型是 str,对字符串使用 + 执行的是拼接,所以 "1" + "2" 得到 "12"。修复一是转换类型:

x = int(input("What's x? "))
y = int(input("What's y? "))
print(x + y)

修复二是在使用处转换并嵌套调用:

print(int(input("What's x? ")) + int(input("What's y? ")))

两者结果相同,但第一种更易读、也更容易调试(可以单独检查 x、y 的类型)。

2. print("hello,", name) 与 print(f"hello, {name}") 的输出一样吗?如果名字前有空格会怎样?

参考答案:两者都会输出 hello, David,但机制不同。第一种把 "hello," 和 name 作为两个参数,print 用默认的 sep=" " 在中间插入一个空格;第二种把变量嵌进字符串,空格由字符串本身提供。

如果 name 是 " David ",第一种输出 hello, David (分隔空格 + 用户自己的空格),第二种输出 hello, David (原样嵌入)。要在两种情况下都得到干净结果,都应先 name = name.strip()。

3. 下面这段代码为什么会报 NameError: name 'name' is not defined?怎么改?

def main():
    name = input("What's your name? ")
    hello()

def hello():
    print("hello,", name)

main()

参考答案:name 定义在 main 的局部作用域内,hello 是另一个函数,看不到 main 的局部变量,因此报错。修改方式是通过参数把值传进去:

def main():
    name = input("What's your name? ")
    hello(name)

def hello(to="world"):
    print("hello,", to)

main()

这样 hello 只依赖自己的参数,不依赖调用者的局部变量,函数也更通用。

4. 用 strip() 和 title() 处理输入 " dAVid mAlAn ",写出代码和输出;再说明为什么 strip 去不掉单词中间的空格。

参考答案:

name = input("What's your name? ").strip().title()
print(f"hello, {name}")

输入 " dAVid mAlAn ",输出 hello, David Malan。strip() 只删除字符串首尾的空白,不碰中间;要去掉中间多余的空格,需要先用 split() 按空白切分,再用 " ".join(...) 重新拼接:

name = " ".join(input("What's your name? ").split())

5. return n * n 和 print(n * n) 有什么区别?在 print("x squared is", square(x)) 里,为什么必须用 return?

参考答案:print(n * n) 只产生副作用——把结果打到屏幕上,函数本身的返回值是 None;return n * n 把计算结果交还给调用者,函数调用表达式本身就等于这个值。

在 print("x squared is", square(x)) 中,square(x) 的值要作为参数传给外层 print。如果 square 只打印不返回,square(x) 的值就是 None,输出会变成 x squared is None。所以这里必须 return。

6. 为什么把 hello 的定义挪到文件末尾后,程序仍然能运行?如果直接把 hello(name) 放在文件开头调用,会怎样?

参考答案:把定义挪到末尾之所以可行,是因为文件末尾调用的 main() 会先执行 main 的函数体;此时整个文件已经被解释器读入并完成了所有 def 语句,hello 已经存在。关键在于调用发生的时刻晚于定义。

如果把 hello(name) 直接写在文件开头,解释器执行到那一行时还没有见过 def hello,于是抛出 NameError: name 'hello' is not defined。Python 只保证「执行到某行时,之前定义过的名字可用」,不做事先的整体声明。

与前后章的关系

这一章建立了所有后续内容的基础词汇:函数、参数、返回值、变量、类型、作用域。下一章引入条件语句,让程序根据布尔值走不同分支;再往后是循环、异常、库,都会直接复用这里的 input、print、类型转换与函数定义。

本章末尾的 main() 结构会在整门课里反复出现,后面加入文件读写、测试、面向对象时,程序骨架仍然是它。

What this chapter covers

This is the first of ten CS50P lectures, on functions and variables. The course was originally published as one very long, unchaptered video of about sixteen hours; this chapter covers the opening overview and week 0 (00:00–1:50:39).

The overview maps the whole course: functions and variables → conditionals → loops → exceptions → libraries → unit tests → file I/O → regular expressions → object-oriented programming → a final round of tools. The lecture then starts from a single print line and walks the full loop of writing, running, breaking and fixing code, before adding input, variables, string manipulation, numeric types, and finally custom functions and scope.

The goal is not to memorise syntax but to build mental models used for the rest of the course: a function is a verb, an argument is its input, a side effect is what it does to the world, and a return value is what it hands back; a variable is a container in memory; = assigns rather than asserts equality; Python interprets your file literally, top to bottom.

Timeline

TimeTopic
0:00Course overview: the ten topics and how the course works
5:02Week 0 begins: text editor, VS Code, terminal
6:20The first program print("hello, world") and python hello.py
10:00Functions, arguments and side effects
12:59A deliberate syntax error: an unclosed parenthesis
16:37Talking to the user with input()
19:46Variables and the assignment operator (right to left)
24:31Comments and pseudo-code
29:48Joining strings: +, multiple arguments, sep and end
45:34Quotes inside quotes and the escape character \
48:10f-strings: embedding variables in text
50:02String methods: strip, capitalize, title, split
1:03:59Integers, arithmetic and the modulo operator %
1:05:18Interactive mode (the REPL)
1:07:23A calculator, and the trap that input returns a string
1:19:20Floats, round and number formatting
1:30:51Custom functions: def, parameters, default values
1:40:10Functions must exist before they are called; the main() convention
1:44:00Scope and NameError
1:45:54return: separating return values from side effects

Starting with one line

Writing Python needs only two things: a text editor for the code and a terminal to run it. VS Code provides both. Files end in .py, which tells the computer this is a Python program.

The first program is one line:

print("hello, world")

Run it in the terminal:

python hello.py

Output:

hello, world

That line already contains three core ideas:

  • Function: print is an action, a verb. Python ships with a set of such verbs.
  • Argument: the "hello, world" in parentheses is the input that decides what gets printed.
  • Side effect: what the function does to the world. For print, it is displaying text on screen.

Computers only understand zeros and ones, and print(...) is plainly neither. The translator is the Python interpreter: it reads the file top to bottom and left to right, turning each line into operations the machine can execute.

Errors are normal: syntax errors

Drop the closing parenthesis and the program never starts:

print("hello, world"
  File "hello.py", line 1
    print("hello, world"
         ^
SyntaxError: '(' was never closed

Takeaway: the computer takes you literally. A typo a human would ignore is, to the interpreter, an unfinished sentence.

Error messages are sometimes precise, as above, and sometimes vague or even misleading. The lecture's advice: read the message, find the line number, and rebuild from a minimal working version.

Input, variables and assignment

To greet a specific person, use input():

name = input("What's your name? ")
print(f"hello, {name}")

A variable has appeared. name is a container in memory holding the text the user typed.

The key is the equals sign: it does not mean equality, it means assignment, and the direction is right to left — evaluate input(...), then place its return value into name.

Assignment can happen repeatedly, overwriting the old value:

name = "David"
name = name.strip()   # process the old value, store it back on the left

Why you cannot write print("hello, name")

Because whatever is inside quotes is printed literally. Remove the quotes to read the variable:

print("hello,", name)   # two arguments; print separates them with a space

So the presence or absence of quotes decides whether you print literal text or the value of a variable.

Comments and pseudo-code

Anything after # is a comment, which the interpreter ignores:

# Ask user for their name
name = input("What's your name? ")

# Say hello to user
print(f"hello, {name}")

Comments also serve as pseudo-code: outline the steps in plain language first, then translate them into Python one at a time. The longer the program, the more this habit pays off.

Joining strings: five ways

The same "hello, someone" has five implementations, which the lecture uses to make a point: in Python there is often more than one way to solve a problem.

# 1. Concatenation
print("hello, " + name)

# 2. Multiple arguments (separated by a space)
print("hello,", name)

# 3. Override end to suppress the newline
print("hello, ", end="")
print(name)

# 4. f-string (recommended)
print(f"hello, {name}")

# 5. Build the string first
greeting = "hello, " + name
print(greeting)

Ways 2 and 3 expose two named parameters of print:

  • sep: the separator between arguments, defaulting to one space;
  • end: the trailing character, defaulting to a newline \n.

print("hello,", name, sep="???") outputs hello,???David. Both parameters have defaults, so they are usually invisible.

Quotes inside quotes

Printing a quoted phrase creates a conflict:

print("hello, "friend"")   # syntax error

Two fixes: use single quotes outside, or escape the inner quotes with a backslash:

print('hello, "friend"')
print("hello, \"friend\"")

\ is an escape character: it tells Python the next character is literal rather than syntax. \n is a newline; \" is a double quote character.

String methods: cleaning user input

User input often carries stray spaces and erratic capitalisation. Strings come with methods — functions attached to a value, called with a dot:

name = input("What's your name? ")
name = name.strip()        # remove leading and trailing whitespace
name = name.title()        # capitalise each word
print(f"hello, {name}")

Input " dAvId mAlAn " produces hello, David Malan.

Methods can be chained on one line:

name = input("What's your name? ").strip().title()

Evaluation goes right to left: call input, then strip, then title, and finally assign to the left-hand side.

Some common methods:

MethodEffectExample
strip()Remove leading/trailing whitespace" hi ".strip() → "hi"
capitalize()Capitalise first letter, lower the rest"dAvId".capitalize() → "David"
title()Capitalise every word"david malan".title() → "David Malan"
split(sep)Split into a list on sep"David Malan".split(" ") → ["David", "Malan"]
lower() / upper()All lower / all upper"Hi".lower() → "hi"

split pairs well with multiple assignment:

first, last = input("What's your name? ").split(" ")
print(f"hello, {first}")

Integers, floats and conversion

int

The integer type int has no decimal point. Core operations:

OperationSymbolExample
Add+1 + 2 → 3
Subtract-5 - 2 → 3
Multiply*3 * 4 → 12
Divide/6 / 2 → 3.0 (a float)
Remainder%7 % 3 → 1

% is not a percentage; it is modulo, the remainder after division.

The calculator trap: input always returns a string

x = input("What's x? ")
y = input("What's y? ")
print(x + y)

Typing 1 and 2 prints 12. The reason: input returns a string, and + on strings concatenates rather than adds.

The fix is conversion:

x = int(input("What's x? "))
y = int(input("What's y? "))
print(x + y)      # 3

int is both a type name and a function: it turns a string that looks like an integer into an actual integer. Calls can be nested — input first, then int:

print(int(input("What's x? ")) + int(input("What's y? ")))

The deeper the nesting, the harder the line is to read, and the lecture's advice is to prioritise readability over saving a line.

Floats and formatting

A float is a number with a decimal point:

x = float(input("What's x? "))
y = float(input("What's y? "))
print(x + y)

Typing 1.2 and 3.4 gives 4.6.

round rounds, with an optional second argument for digits:

z = round(x + y)          # 4.6 → 5
z = round(x / y, 2)       # 2/3 → 0.67

f-strings can format directly:

print(f"{z:,}")     # 1000 → 1,000
print(f"{z:.2f}")   # 0.666... → 0.67

:, inserts thousands separators; :.2f keeps two decimals. These format specifiers are not worth memorising — look them up when needed.

Two precision facts:

  • Python's int has no upper bound and can represent arbitrarily large integers;
  • float has limited precision (about 15–17 significant digits), so 2/3 displays as 0.6666666666666666.

Defining your own functions

When the same job keeps recurring, give it a name. Use def:

def hello(to="world"):
    print("hello,", to)

name = input("What's your name? ")
hello()
hello(name)

Output:

hello, world
hello, David

Breaking it down:

  • def is short for define;
  • hello is the function name;
  • to="world" is a parameter with a default: if the caller passes nothing, world is used;
  • the colon and indentation delimit the body;
  • the name passed at the call site is an argument, while to inside the function is a parameter — different variables.

On a call, the argument's value is copied into the parameter, so changing to inside does not affect name outside.

Order matters

Python executes top to bottom. A function must be defined before it is called:

hello()        # NameError: name 'hello' is not defined

def hello():
    print("hello")

There are two fixes. Move the definition above the call, or — the more common convention — define a main() holding the program logic and call main() on the last line:

def main():
    name = input("What's your name? ")
    hello(name)


def hello(to="world"):
    print("hello,", to)


main()

Now main reads like a table of contents, details follow underneath, and the single call to main() sits at the end. Reading order is natural, and no NameError occurs.

Scope

A variable created inside main is not visible in another function:

def main():
    name = input("What's your name? ")
    hello()          # no argument

def hello():
    print("hello,", name)   # NameError: name 'name' is not defined

main()

The cause is scope: name exists only in main's local scope, and hello cannot see it.

The correct fix is to pass the value:

def main():
    name = input("What's your name? ")
    hello(name)      # hand the value over

def hello(to="world"):
    print("hello,", to)

Return values: a function's other output

Some functions have only side effects (print); others hand a result back (input, int, float). When defining your own, use return:

def main():
    x = int(input("What's x? "))
    print("x squared is", square(x))


def square(n):
    return n * n


main()

return lets the result be used further — passed to print, assigned to a variable, fed into another computation. Side effects and return values are two distinct kinds of output, and a well-written function knows which one it produces.

Squaring has three equivalent spellings:

def square(n):
    return n * n        # multiplication
    # return n ** 2     # exponentiation
    # return pow(n, 2)  # built-in function

Chapter summary

  • Writing code = a text editor + a terminal; Python files end in .py and run with python file.py.
  • A function is a verb; arguments are inputs; side effects affect the world; return values come back to the caller.
  • = assigns, right to left; a variable is a container in memory that can be overwritten.
  • input always returns a string; arithmetic requires int() or float().
  • print has named parameters sep and end, both with defaults; \ is the escape character.
  • f-strings embed variables and format numbers (:,, :.2f).
  • String methods are called with a dot and can be chained; strip, title and split are the most used.
  • def defines a function, whose parameters may have defaults; definitions must precede calls.
  • main() plus a final call is the standard structure; local variables stay local.
  • return hands back a value, which is not the same as print's side effect.

Comprehension check

1. Why does adding the 1 and 2 obtained from input() produce 12? Give two fixes.

Reference answer: input() returns a str, and + on strings concatenates, so "1" + "2" is "12". Fix one converts each value:

x = int(input("What's x? "))
y = int(input("What's y? "))
print(x + y)

Fix two converts inline:

print(int(input("What's x? ")) + int(input("What's y? ")))

Both give 3, but the first is easier to read and to debug, since x and y can be inspected separately.

2. Do print("hello,", name) and print(f"hello, {name}") produce the same output? What if the name has leading spaces?

Reference answer: both print hello, David, but the mechanisms differ. The first passes two arguments, and print inserts one space by default via sep. The second embeds the variable in the string, where the space is part of the literal text.

If name is " David ", the first prints hello, David (separator plus the user's spaces) and the second prints hello, David (embedded verbatim). To get a clean result in both cases, run name = name.strip() first.

3. Why does the following raise NameError: name 'name' is not defined, and how should it be fixed?

def main():
    name = input("What's your name? ")
    hello()

def hello():
    print("hello,", name)

main()

Reference answer: name is local to main, and hello is a different function with a different local scope, so it cannot see it. Pass the value as a parameter:

def main():
    name = input("What's your name? ")
    hello(name)

def hello(to="world"):
    print("hello,", to)

main()

Now hello depends only on its own parameter, which is more general and easier to test.

4. Using strip() and title(), process the input " dAVid mAlAn ". Give the code and the output, and explain why strip cannot remove spaces between words.

Reference answer:

name = input("What's your name? ").strip().title()
print(f"hello, {name}")

With " dAVid mAlAn " the output is hello, David Malan. strip() removes only leading and trailing whitespace, leaving interior characters untouched. To collapse interior runs of spaces, split and rejoin:

name = " ".join(input("What's your name? ").split())

5. What is the difference between return n * n and print(n * n), and why must the former be used inside print("x squared is", square(x))?

Reference answer: print(n * n) only has a side effect — the value appears on screen — and the function's own return value is None. return n * n hands the value back, so the call expression itself equals that value.

In print("x squared is", square(x)), the value of square(x) is passed to the outer print as an argument. If square merely printed, square(x) would evaluate to None, and the output would be x squared is None. Hence return is required.

6. Why does the program still work when hello is defined at the bottom of the file? What happens if hello(name) is called on the very first line instead?

Reference answer: defining hello at the bottom works because the call to main() on the last line runs after the interpreter has already executed every def statement in the file. What matters is that the call happens later than the definition.

Calling hello(name) on the first line instead raises NameError: name 'hello' is not defined, because the interpreter reaches that line before it has seen the def. Python only guarantees that names defined earlier in execution are available — it does not hoist function definitions ahead of the file.

Relation to neighbouring chapters

This chapter supplies the vocabulary for everything that follows: functions, parameters, return values, variables, types and scope. The next chapter introduces conditionals, letting a program branch on boolean values; loops, exceptions and libraries then reuse the input, print, conversion and function machinery established here.

The main() structure introduced at the end recurs throughout the course. When file I/O, testing and object-oriented programming arrive, the program skeleton is still this one.

来源