学习日志18 python
1 输出的是单个字符or连续的字符串
在Python3中,有关于break的用法:for i in \'python\': if i == \'h\': break print(i)A \'p\',\'y\',\'t\',\'h\',\'o\',\'n\'B \'p\',\'y\',\'t\'C \'p\',\'y\',\'t\',\'h\'D \'pyt\'正确答案:B你的答案:D
在 Python 中,当你使用print()
函数时,默认情况下每次调用都会在输出后添加一个换行符。
不过,你能够借助end
参数对这一行为加以调整。下面通过具体例子来说明
python
运行
# 示例1:默认情形,每次打印后会换行for i in \'python\': if i == \'h\': break print(i) # 这里会逐个输出,并且每个字符占一行# 输出结果:# p# y# t# 示例2:把end参数设置为空字符串,就能让字符在同一行输出for i in \'python\': if i == \'h\': break print(i, end=\'\') # 所有字符会在同一行输出# 输出结果:# pyt
题目里的代码使用的是默认的print(i)
,所以输出结果是:
plaintext
pyt
这和选项 B 相契合。
选项 D(\'pyt\')要想成立,代码得写成print(i, end=\'\')
才行。所以,这道题的正确答案是 B。
2 index()方法
index()
方法是 Python 字符串对象的内置方法,用于查找子字符串在原字符串中首次出现的位置(即起始索引)。它的基本用法和特性如下:
语法
python
运行
str.index(sub[, start[, end]])
sub
:必需,要查找的子字符串。start
(可选):开始搜索的索引位置,默认为 0。end
(可选):结束搜索的索引位置(不包含),默认为字符串长度。
关键点
- 索引从 0 开始:字符串的第一个字符索引是 0,第二个是 1,依此类推。
- 区分大小写:
\"A\"
和\"a\"
被视为不同字符。 - 包含所有字符:空格、标点符号等均参与索引计算。
- 仅返回首次出现的位置:若子串多次出现,只返回第一次的索引。
- 找不到子串时抛出异常:与
find()
方法不同,index()
在未找到子串时会抛出ValueError
。
示例
python
运行
s = \"Hello,Python!\"# 查找 \"Python\" 的起始索引(P 在索引 6)print(s.index(\"Python\")) # 输出: 6# 从索引 7 开始查找 \"o\"print(s.index(\"o\", 7)) # 输出: 10(第二个 \"o\" 的位置)# 在索引 0~5 之间查找 \"l\"print(s.index(\"l\", 0, 5)) # 输出: 2(第一个 \"l\" 的位置)# 尝试查找不存在的子串(会报错)print(s.index(\"Java\")) # 抛出 ValueError: substring not found
常见误区
- 忽略非字母字符:例如
\"Hello,Python\"
中的逗号,
占索引 5,因此\"Python\"
从索引 6 开始。 - 混淆
index()
和find()
:index()
:找不到子串时抛出异常。find()
:找不到子串时返回-1
。
建议
在使用 index()
时,若不确定子串是否存在,可先通过 sub in str
进行检查,避免程序崩溃:
python
运行
s = \"Hello\"if \"World\" in s: print(s.index(\"World\"))else: print(\"子串不存在\")
理解索引的计算方式和 index()
的特性,就能轻松应对类似题目啦!
3 逗号在字符串中也是一个独立的字符,会占用一个索引位置
在字符串 \"Hello,Python\" 里,字符的排列和索引对应是这样的:
可以看到,逗号(,)在索引 5 的位置,它后面的字母 P 才是子串 \"Python\" 的起始位置,对应索引 6。所以计算子串起始索引时,字符串中所有的字符(包括标点、空格等)都要算在内,一个都不能少
4 闭包(Closure)
闭包(Closure)是编程中的一个重要概念,在 Python、JavaScript、Swift 等许多语言中都存在。简单来说,闭包是一个函数及其捆绑的周边环境状态( lexical environment)的引用的组合。
闭包的核心特性
- 嵌套函数:闭包必须包含一个嵌套在另一个函数内部的函数。
- 捕获变量:内部函数(闭包)会捕获外部函数的局部变量或参数。
- 延长作用域:即使外部函数执行结束,闭包仍能访问和修改外部函数的变量。
闭包的本质
闭包让函数可以 “记住” 它创建时的环境,即使该环境已经不存在(例如外部函数已返回)。闭包保存的是变量的引用,而非值的副本。
Python 中的闭包示例
python
运行
def outer(x): def inner(y): return x + y # 闭包捕获了外部变量x return inner # 返回闭包# 创建闭包实例closure = outer(10)# 调用闭包,此时outer函数已执行完毕,但闭包仍记得x=10print(closure(5)) # 输出: 15
关键点解析:
inner
是闭包:它嵌套在outer
内部,并引用了外部变量x
。x
被捕获:当outer(10)
执行时,x=10
被闭包捕获。- 闭包独立保存状态:即使
outer
执行结束,闭包仍保留对x
的引用。
闭包的常见场景
-
函数工厂:动态创建函数。
python
运行
def multiplier(factor): return lambda x: x * factor # 返回闭包double = multiplier(2)triple = multiplier(3)print(double(5)) # 输出: 10print(triple(5)) # 输出: 15
-
数据封装:模拟私有变量。
python
运行
def counter(): count = 0 def increment(): nonlocal count # 声明使用外部变量 count += 1 return count return incrementc = counter()print(c()) # 输出: 1print(c()) # 输出: 2
闭包的注意事项
1. 闭包捕获变量引用
闭包保存的是变量的引用,而非创建时的值。这可能导致意外结果:
python
运行
def create_closures(): closures = [] for i in range(3): closures.append(lambda: i) # 闭包捕获的是i的引用 return closures# 所有闭包共享同一个i,而i的最终值为2for c in create_closures(): print(c()) # 输出: 2, 2, 2
2. 解决方法:绑定变量值
通过默认参数将当前值绑定到闭包:
python
运行
def create_closures(): closures = [] for i in range(3): closures.append(lambda x=i: x) # 将i的值绑定到默认参数x return closures# 每个闭包保存了自己的x值for c in create_closures(): print(c()) # 输出: 0, 1, 2
闭包 vs. 普通函数
闭包的应用场景
- 事件处理:在 GUI 或前端框架中保存事件上下文。
- 装饰器:在不修改原函数的情况下扩展功能。
- 延迟计算:保存计算所需的参数,在需要时执行。
理解闭包的核心是 “捕获并保留变量引用”,这是掌握闭包行为的关键。在循环中创建闭包时,尤其要注意变量绑定的时机。
5 闭包捕获的是变量的引用,而不是变量的值
执行下列程序,输出结果为()def fn(): t = [] i = 0 while i < 2: t.append(lambda x: print(i*x,end=\",\")) i += 1 return tfor f in fn(): f(2)输出结果:4,4,
代码分析
这段代码的核心在于闭包对变量的引用方式,特别是在循环中创建闭包时容易出现的陷阱。我们分步来看:
-
函数
fn()
的执行过程:- 创建一个空列表
t
和计数器i
(初始值为 0)。 - 进入
while
循环(条件i < 2
):- 第一次循环:
i=0
,向列表t
中添加一个匿名函数(闭包),该函数接受参数x
,打印i*x
的值。 - 计数器
i
增加到 1。 - 第二次循环:
i=1
,再次向列表t
中添加一个相同结构的匿名函数。 - 计数器
i
增加到 2,循环结束。
- 第一次循环:
- 返回列表
t
,此时列表中包含两个闭包函数。
- 创建一个空列表
-
主程序的执行过程:
- 调用
fn()
得到包含两个闭包的列表t
。 - 遍历这个列表,依次调用每个闭包函数,并传入参数
2
(即执行f(2)
)。
- 调用
闭包的陷阱
关键问题在于:闭包捕获的是变量的引用,而不是变量的值。
当闭包在后续被调用时,它们并不会使用创建时的 i
值(0 和 1),而是使用当前 i
的值。由于循环结束后 i
的最终值为 2,因此两次调用闭包时,i
的值都是 2,导致输出结果为:
- 第一次调用:
2 * 2 = 4
- 第二次调用:
2 * 2 = 4
如何修正
如果希望闭包捕获循环变量的当前值,可以通过函数参数来传递:
python
运行
def fn(): t = [] i = 0 while i < 2: # 使用默认参数捕获当前i的值 t.append(lambda x, i=i: print(i*x, end=\",\")) i += 1 return tfor f in fn(): f(2) # 输出:0,2,
这里通过 i=i
将当前 i
的值绑定到闭包的默认参数中,使得每次创建的闭包都保存了当时的 i
值(0 和 1)。
总结
这个例子展示了 Python 闭包的一个重要特性:闭包捕获的是变量的引用,而不是变量的值。在循环中创建闭包时,需要特别注意这一点,避免所有闭包共享同一个变量的最终值。
逐行注释详解:
python
运行
def fn(): # 创建空列表t,用于存储后续生成的闭包函数 t = [] # 初始化计数器i,用于控制循环次数 i = 0 # 循环2次(i=0和i=1时满足条件) while i < 2: # 向列表t中添加一个匿名函数(闭包) # 该闭包接受参数x,打印i*x的结果(注意:闭包捕获的是i的引用,而非值) t.append(lambda x: print(i*x, end=\",\")) # 计数器i加1 i += 1 # 循环结束后,i的值为2(不满足循环条件i<2) # 返回包含两个闭包函数的列表t return t# 调用fn()获取闭包列表,并遍历调用每个闭包for f in fn(): # 调用闭包函数,传入参数2 # 由于闭包捕获的i最终值为2,因此两次调用都输出2*2=4 f(2) # 输出结果:4,4,
关键解释
-
闭包捕获变量引用:
- 闭包内部的
i
是对外部变量i
的引用,而非创建时的值。 - 当闭包被调用时,Python 会查找当前
i
的值(此时循环已结束,i=2
)。
- 闭包内部的
-
循环执行过程:
- 第一次循环(
i=0
):添加闭包lambda x: print(i*x, end=\",\")
- 第二次循环(
i=1
):添加另一个相同结构的闭包 - 循环结束后,
i
最终值为 2
- 第一次循环(
-
闭包调用结果:
- 每个闭包在调用时,
i
的值都是 2,因此:- 第一次调用
f(2)
输出2*2=4
- 第二次调用
f(2)
同样输出2*2=4
- 第一次调用
- 每个闭包在调用时,
修正方案(保存变量值)
python
运行
def fn(): t = [] i = 0 while i < 2: # 使用默认参数i=i将当前i的值绑定到闭包 t.append(lambda x, i=i: print(i*x, end=\",\")) i += 1 return tfor f in fn(): f(2) # 输出:0,2,(保存了创建时的i值)
通过默认参数 i=i
,将当前 i
的值(0 和 1)保存到闭包内部,避免后续 i
的变化影响闭包结果。