Python Day5 进阶语法(列表表达式/三元/断言/with-as/异常捕获/字符串方法/lambda函数

Python 列表推导式是什么

列表推导式是 Python 语言特有的一种语法结构,也可以看成是 Python 中一种独特的数据处理方式

它在 Python 中用于 转换过滤 数据。

其语法格式如下所示,其中 [if 条件表达式] 可省略。

[表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]]

注意:学习列表推导式的前提是掌握 Python for 循环。

列表推导式中存在两个名词,一个是 列表 ,另一个是 推导式 ,列表我们很清楚,就是 Python 的一种数据类型,

而推导式只是一个普通的语法定义词,有的教程里,会将其叫做 解析式,二者是一样的概念。

列表推导式会返回一个列表,因此它适用于所有需要列表的场景。

怎么用

基础使用

列表推导式最常见的场景就是优化简单循环。
for 循环写法

my_list = [1,2,3]
new_list = []
for i in my_list:
    new_list.append(i*2)

print(new_list)

列表推导式写法

nn_list = [i*2 for i in my_list]
print(nn_list)

是不是对比看就是将 for 循环语句做了变形之后,增加了一个 [],不过需要注意的是,列表推导式最终会将得到的各个结果组成一个新的列表。

再看一下列表推导式语法构成 nn_list = [i*2 for i in my_list]for 关键字后面就是一个普通的循环,前面的表达式 i*2 其中的 i 就是 for 循环中的变量,也就是说表达式可以用后面 for 循环迭代产生的变量,理解这个内容列表推导式就已经掌握 9 成内容了,剩下的是熟练度的问题。

在将 if 语句包含进代码中,运行之后,你也能掌握基本技巧,if 语句是一个判断,其中 i 也是前面循环产生的迭代变量。

nn_list = [i*2 for i in my_list if i>1]
print(nn_list)
优化两层 for 循环

这些都是一般技能,列表推导式能支持两层 for 循环,例如下述代码:

nn_list = [(x,y) for x in range(3) for y in range(3) ]
print(nn_list)

当然如果你想**加密(谁都看不懂你的代码)**你的代码,你可以无限套娃下去,列表推导式并没有限制循环层数,多层循环就是一层一层的嵌套,你可以展开一个三层的列表推导式,就都明白了

nn_list = [(x,y,z,m) for x in range(3) for y in range(3) for z in range(3) for m in range(3)]
print(nn_list)

当然在多层列表推导式里面,依旧支持 if 语句,并且 if 后面可以用前面所有迭代产生的变量,不过不建议超过 2 成,超过之后会大幅度降低你代码的可阅读性。

当然如果你希望你代码更加难读,下面的写法都是正确的。

nn_list = [(x, y, z, m) for x in range(3) if x > 1 for y in range(3) if y > 1 for z in range(3) for m in range(3)]
print(nn_list)
nn_list = [(x, y, z, m) for x in range(3) for y in range(3) for z in range(3) for m in range(3) if x > 1 and y > 1]
print(nn_list)
nn_list = [(x, y, z, m) for x in range(3) for y in range(3) for z in range(3) for m in range(3) if x > 1 if y > 1]
print(nn_list)

现在你已经对列表推导式有比较直观的概念了,列表推导式对应的英文是 list comprehension,有的地方写作列表解析式,基于它最后的结果,它是一种创建列表的语法,并且是很简洁的语法。

有了两种不同的写法,那咱们必须要对比一下效率,经测试小数据范围影响不大,当循环次数到千万级时候,出现了一些差异。

import time
def demo1():
    new_list = []
    for i in range(10000000):
        new_list.append(i*2)

def demo2():
    new_list = [i*2 for i in range(10000000)]
s_time = time.perf_counter()
demo2()
e_time = time.perf_counter()
print("代码运行时间:", e_time-s_time)

运行结果:

# for 循环
代码运行时间: 1.3431036140000001
# 列表推导式
代码运行时间: 0.9749278849999999

在 Python3 中列表推导式具备局部作用域,表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量还可以被正常引用,局部变量并不会影响到它们。所以其不会有变量泄漏的问题。例如下述代码:

x = 6
my_var = [x*2 for x in range(3)]

print(my_var)
print(x)

列表推导式还支持嵌套

参考代码如下,只有想不到,没有做不到的。

my_var = [y*4 for y in [x*2 for x in range(3)]]
print(my_var)
用于转换数据

可以将可迭代对象(一般是列表)中的数据,批量进行转换操作,例如将下述列表所有元素翻两倍。

my_list = [1,2,3]

代码如下所示:

my_list = [1, 2, 3]
new_list = [item * 2 for item in my_list]
print(new_list)

结果可以自行编译运行。

掌握上述语法的关键点是 item ,请重点关注 itemmy_list 遍历而来,并且 item*2 尾部与 for 循环存在一个空格。

用于过滤数据

列表表达式,可以将列表中满足条件表达式的值进行筛选过滤,获取目标数据。

my_list = [1, 2, 3]
new_list = [item for item in my_list if item > 1]
print(new_list)

掌握上述语法的关键是 if ,其余要点是注意语法编写结构。

接下来你可以尝试将上述编程逻辑,修改为 for 循环语法,学习过程中要着重理解以上两种语法结构可以相互转换,

当你可以无缝将二者进行转换时,该技能你就掌握了。

有些人会将列表推导式当做 for 循环的简化版。

字典推导式

有了列表推导式的概念,字典推导式学起来就非常简单了,语法格式如下:

{键:值 for 迭代变量 in 可迭代对象 [if 条件表达式]}

直接看案例即可

my_dict = {key: value for key in range(3) for value in range(2)}
print(my_dict)

得到的结果如下:

{0: 1, 1: 1, 2: 1}

此时需要注意的是字典中不能出现同名的 key,第二次出现就把第一个值覆盖掉了,所以得到的 value 都是 1。

最常见的哪里还是下述的代码,遍历一个具有键值关系的可迭代对象。

my_tuple_list = [('name', '橡皮擦'), ('age', 18),('class', 'no1'), ('like', 'python')]
my_dict = {key: value for key, value in my_tuple_list}
print(my_dict)
元组推导式与集合推导式

其实你应该能猜到,在 Python 中是具备这两种推导式的,而且语法相信你已经掌握了。不过语法虽然差不多,但是元组推导式运行结果却不同,具体如下。

my_tuple = (i for i in range(10))
print(my_tuple)

运行之后产生的结果:

<generator object <genexpr> at 0x0000000001DE45E8>

使用元组推导式生成的结果并不是一个元组,而是一个生成器对象,需要特别注意下,这种写法在有的地方会把它叫做生成器语法,不叫做元组推导式。

集合推导式也有一个需要注意的地方,先看代码:

my_set = {value for value in 'HelloWorld'}
print(my_set)

因为集合是无序且不重复的,所以会自动去掉重复的元素,并且每次运行显示的顺序不一样,使用的时候很容易晕掉。

提高场景

再次查看推导式语法结构中,涉及了一个关键字,叫做 可迭代对象 ,因为我们可以把自己目前掌握的所有可迭代对象,

都进行一下尝试,例如使用 range() 函数。

my_list = [1, 2, 3]
new_list = [item for item in range(1, 10) if item > 5]
print(new_list)

检验是否掌握,可以回答下述两个问题。

  • 如果可迭代对象是一个字典,你该如何操作?
  • 如果可迭代对象位置使用了 enumerate() 函数,你该如何操作?

除了可迭代对象部分可以扩展知识点, if 表达式 中的 条件表达式 也支持各种布尔运算,如果用中文进行翻译,

表示把满足条件的元素,放置到新的列表中

扩展知识

由于列表推导式涉及了数据类型,所以可大胆推断,还存在其它推导式语法,Python 也确实是这样设计的。

你可以继续学习下述内容,而且知识结构基本一致。

  • 字典推导式
  • 集合推导式
  • 生成器推导式

列表推导式的学习,不要过于在意细节,也无需要求学会即掌握,因为该知识点属于语法糖(编程小技巧),

所以在初学阶段,了解即可,随着编程学习的深入,你会自然而然的将可用推导式的地方,修改为推导式。

Python 三元表达式是什么

Python 中没有其它语言的三元表达式(三目运算符)相关说法,但是有类似的语法。

在 Python 中,三元表达式是一种语法结构,一般被 Python 开发者叫做条件表达式,它的结构如下所示:

表达式(1)为 True 执行语句 if 条件表达式(1) else 表达式(1)为 False 执行语句

怎么用

用于 if 语句简化

三元表达式可以将简单的 if 语句 缩减为一行代码。

age = 20

cn = "成年" if age >= 18 else "未成年"
print(cn)

if 语句 如下所示:

age = 20
if age >= 18 :
    cn = "成年"
else:
    cn = "未成年"
返回多个条语句

可以编写如下代码结构,在条件表达式中返回多条语句。

age = 20

cn = "成年", "大于18" if age >= 18 else "未成年"
print(cn)

代码返回一个元组,内容为 ('成年', '大于18') ,这里一定注意不要使用分号 ; ,否则只返回第一个语句的结果。

age = 20

cn = "成年"; "大于18" if age >= 18 else "未成年"
print(cn)

运行代码之后,输出 成年

在函数内部使用三元表达式

有些简单的判定逻辑,可以直接使用三元表达式简化,例如判断传入参数是否为偶数。

def even_num(num):
    return True if num % 2 == 0 else False
三元表达式用于列表推导式

在列表推导式知识点中,也存在三元表达式的落地应用,例如下述代码。

li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# ret = [i for i in li if i % 2 == 0]
ret = [i if i % 2 == 0 else None for i in li]
print(ret)

上述代码重点注意列表生成器部分代码,三元表达式所在位置。

三元表达式与 lambda

有时候可以将三元表达式与 lambda 进行结合,让代码变得更加简洁。

声明一个函数,返回较大值

def max(a, b):
    if a > b:
        ret = a
    else:
        ret = b

    return ret

r = max(5, 6)
print(r)

由于上述代码非常简单,可以直接使用 lambda 匿名函数实现。

max = lambda a, b: a if a > b else b
r = max(10, 15)
print(r)

提高场景

Python 条件表达式可以嵌套使用,但是建议最多嵌套两层,而且是在代码简单的情况下,具体编码如下所示,你需要重点学习下述问题。

在嵌套的时候,还需要注意 if 和 else 配对问题。

# 编写一个三元表达式,首先判断其值大于20,然后在判断是奇数(案例,无实际意义)
num = 19
ret = "小于20" if num < 20 else ("奇数" if num % 2 == 1 else "偶数")
print(ret)

扩展知识

在很多地方会将 Python 的条件表达式进行扩展,出现下述两种用法,但都属于炫技能力,实战性不强。

例如下述内容:

元组条件表达式

age = 20

cn = ("未成年", "成年")[age >= 18]
print(cn)

语法格式如下所示

 (当后面的表达式为假时返回,当后面的表达式为真时返回)[条件表达式]

字典条件表达式

age = 20

cn = {False: "未成年", True: "成年"}[age >= 18]
print(cn)

你会发现,上述两种写法都有一些故弄玄虚 ,而且代码 非常不易 阅读,所以不建议实战编码时使用。

Python 断言是什么

Python 断言,即 Python assert 语句,简单理解就是简易版的 if 语句,

用于判断某个表达式的值,结果为 True,程序运行,否则,程序停止运行,抛出 AssertionError 错误。

语法格式如下所示:

assert 表达式

类比 if 语句,如下所示:

if not 表达式:
	raise AssertionError

assert 表达式之后,可以增加一个参数 [, arguments],等价的 if 语句如下所示:

if not 表达式:
	raise AssertionError(arguments)

怎么用

模拟场景

在游戏里面设置一个未满 18 岁禁止访问的功能。

def overage18(age):
    assert age >= 18, "对不起未满18岁,无法进行游戏"
    print("享受欢乐游戏时光")

if __name__ == '__main__':
    overage18(15)

但是这个案例并不是一个完美的案例,因为断言 是为了告知 开发人员 ,你写的程序发生异常了。

如果一个潜在错误在程序编写前就能考虑到,例如程序运行时网络中断,这个场景就不需要使用断言。

断言主要为调试辅助而生,为的是程序自检,并不是为了处理错误,程序 BUG 还是要依赖 try... except 解决。

由于断言是给 开发人员看的,所以下述案例的断言是有效的。

def something():
	"""该函数执行了很多操作"""
	my_list = [] # 声明了一个空列表
	# do something
	return my_list

def func():
	"""调用 something 函数,基于结果实现某些逻辑"""
	ret = something()
	assert len(ret) == 18, "列表元素数量不对"
	# 完成某些操作

使用断言要注意:

不要用断言验证用户的输入,这是因为 python 通过命令行运行时,如果增加 -O 标识,断言就被全局禁止了,你的所有验证就都丢失了。

常用断言函数
  • assertEqual(a,b,msg=msg):判断两个值是否相等;
  • assertNotEqual(a,b,msg=msg):上一函数的反义;
  • self.assertTrue(a,msg=none):判断变量是否为 True;
  • assertFalse(a,msg=none):同上反义;
  • assertIsNone(obj=''):判断 obj 是否为空;
  • assertIsNotNone(obj=''):同上反义;

扩展知识

Python 断言的适用场景

进行防御性的编程

我们在使用断言的时候,应该捕捉不应该发生的非法情况。这里要注意非法情况异常错误 之间的区别,

后者是必然存在的并且是一定要作出处理的。而断言后的条件不一定发生。

对假定条件做验证

断言是对程序员的假定做验证,因此这些假定的异常不一定会触发。

with....as...

python操作文件时,需要打开文件,最后手动关闭文件。

通过使用with...as...不用手动关闭文件。当执行完内容后,自动关闭文件。

Python 异常捕获是什么

程序异常,就是程序出错了,程序员一般叫做 BUG(八哥),写程序不出错是不可能发生的事情,而程序员要做的事情就是及时的捕获错误,修改错误。

最常见的错误 - 除数为 0

在数学中也存在类似的问题,除数不可以为 0。相同的概念在编程中也是存在的。

num1 = 20
num2 = 0
num3 = num1 / num2
print(num3)

Traceback (most recent call last):
  File "D:/gun/2/demo7.py", line 3, in <module>
    num3 = num1 / num2
ZeroDivisionError: division by zero

错误内容就是末尾的 ZeroDivisionError: division by zero ,当出现错误程序崩溃,终止运行。错误异常中也提示了错误出现的行数 line 3 在第三行,但查看行号排查错误在很多时候无法直接解决问题,因为出错的地方不在行号那一行,修改 BUG 的效率一般会随着你对 Python 学习的深入逐步增强改善。

try ... except 语句

刚才的程序出现错误就终止运行了,如何避免程序被强迫终止,出现问题提示出问题,然后继续运行呢?这就是 try ... except 语句使用的场景了。

语法格式:

try:
	可能会出错的代码
except 异常对象:
	处理异常代码

按照上述语法格式修改上文代码。

num1 = 20
num2 = 0
try:
    num3 = num1 / num2
except ZeroDivisionError:
    print("除数不可以为 0 ")

此时程序不会报错,当发现除数为 0 会进入异常处理,直接输出除数不能为 0。

try 表示测试代码部分是否存在异常,except 表示捕获异常,前提是出现异常。如果 try 语句中没有任何错误,except 中的代码不会执行。

还有一点需要注意,在 except 后面是异常对象,该异常对象我们设置为 ZeroDivisionError 这是因为已经知道是会出现这个异常,如果在编码过程中不知道会出现哪种异常,依旧会出现错误。

num1 = 20
num2 = "abc"
try:
    num3 = num1 / num2
except ZeroDivisionError:
    print("除数不可以为 0 ")

上述代码依旧会报错,报错的异常为:

Traceback (most recent call last):
  File "D:/gun/2/demo7.py", line 4, in <module>
    num3 = num1 / num2
TypeError: unsupported operand type(s) for /: 'int' and 'str'

如果想在 except 后面支持本异常,需要添加上 TypeError

num1 = 20
num2 = "abc"
try:
    num3 = num1 / num2
except (ZeroDivisionError,TypeError):
    print("除数不可以为 0 ")

也可以分开编写:

num1 = 20
num2 = "abc"
try:
    num3 = num1 / num2
except ZeroDivisionError:
    print("除数不可以为 0 ")

except TypeError:
    print("除数类型不对")

该种写法在书写的时候需要预先知道会提示哪种异常,如果异常不清楚那可以省略异常对象,直接使用下述代码即可。

num1 = 20 num2 = "abc" try: num3 = num1 / num2 except: print("除数不可以为 0 ")

try ... except ... else 语句

在 try ... except 语句后面可以增加一个 else 语句,该语句表示的含义可以按照如下描述进行理解,当出现异常的时候执行 except 语句中的代码,当无异常执行 else 语句代码。

num1 = 20
num2 = 1
try:
    num3 = num1 / num2
except ZeroDivisionError:
    print("除数不可以为 0 ")

except TypeError:
    print("除数类型不对")

else:
    print("无异常,会被执行")

以上代码无错误,那 else 语句就会被执行到。

常见的异常类型

在编写代码的过程中,你需要掌握一些常见的异常类型,熟记它们可以帮助你快速进行错误排查。

  • AttributeError 某个对象没有属性
  • Exception 通用型异常对象
  • FileNotFoundError 找不到文件
  • IOError 输入输出异常
  • IndexError 索引异常
  • KeyError 键异常
  • NameError 对象名称异常
  • SyntaxError 语法错误
  • TypeError 类型错误
  • ValueError 值错误

以上错误都属于常见错误,其中重点以 Exception 通用异常对象与 SyntaxError 语法错误为主,它们两个是最常出现的。

很多时候其实直接使用通用异常对象 Exception 就可以了,不需要记住所有的异常类型的。

捕捉多个异常

在上文已经接触过捕捉多个异常的语法格式了,可以在学习一下。

try:
	可能出错的代码块
except 异常对象1:
	异常处理代码块
except 异常对象2:
	异常处理代码块
一个 except 捕获多个异常

Python 也支持使用一个 except 捕获多个异常,具体语法格式如下:

try:
	可能出错的代码块
except (异常对象1,异常对象2...):
	异常处理代码块
直接抛出异常

捕获到异常之后,可以直接抛出 Python 给内置好的异常信息,例如:

num1 = 20
num2 = 0
try:
    num3 = num1 / num2
except ZeroDivisionError as e:
    print(e)

except TypeError as e:
    print(e)

else:
    print("无异常,会被执行")

注意 except 后面异常对象使用 as 关键字起了一个别名叫做 e,然后直接输出 e 就是 Python 内置好的错误信息了。这里的 e 可以为任意名称,遵循变量命名规则即可。

finally 语句

try ... except 语句还可以和 finally 语句配合,形成下述语法格式:

try:
	可能出错的代码块
except:
	代码出错执行的代码块
else:
	代码正常执行的代码块
finally:
	无论代码是否有异常出现都会执行的的代码块

finally 语法需要与 try 语句配合使用,无论是否有异常出现都会执行该语句内容,具体代码大家可以自行测试即可。

Python 异常捕获扩展部分

本篇博客主要写的是异常相关知识,在 Python 代码的编写过程中经常会出现异常,一般情况下程序员都叫做 出 BUG 了,这个 BUG 就是臭虫的意思,表示程序出臭虫了。当然很多时候我们也戏称"无 BUG,不编程"。

发现 BUG,解决 BUG,程序员不是在写 BUG 的路上,就是在改 BUG 的路上,好友哲理。

关于异常部分,还有如下内容可以扩展。

  • 使用 raise 抛出异常
  • 使用 traceback 模块记录异常信息到文件中
  • 程序断言 assert

Python 字符串方法是什么

Python 字符串是 Python 内置的一种数据类型,本篇博客要学习的内容就是字符串对象的方法。

先来学习第一个知识点,Python 字符串,字符串是一个编程名词,翻译过来就是字符组成的串(跟没说一样)

在 Python 中,用引号来表示字符串,例如 双引号 ",单引号 ',还有一个奇葩的三引号 """,对应的三单引号 '''

所以下述代码都是在 声明 一个字符串。

name = "橡皮擦"
name = '橡皮擦'
name = """橡皮擦"""
name = '''橡皮擦'''

此时你应该尝试输入一下上述代码,找找编程的感觉,如果你能得到如下几个结论,证明水平还不错。

  • 引号都是成对出现的,前面一个后面一个;
  • 单引号对应单引号,双引号对应双引号,三引号对应三引号;
  • 所有引号都是在英文模式下输入的,不能用中文的引号。

字符串会伴随我们的整个编程生涯,几乎每段代码都会碰到,因此咱们将其放在一开始就进行讲解。

怎么用

截止目前,你只接触到了 Python 字符串的概念,那你来看一下 '1' 是字符串吗?

答案肯定是,因为 1 被单引号包裹起来了。

既然字符串是一个字符的串,那你就可以把它当成糖葫芦串,你可以对糖葫芦做什么,就能对字符串做什么,

例如吃第一个,吃最后一个,吃中间的 2 个,在头上插入一个山楂,在尾部插入一个山楂,数数山楂的数量......

这些对应到 Python 字符串中,就是各种编程语法,编程概念,咱们一起翻译翻译。

我有一个字符串(糖葫芦),我要吃第一个

tang_hu_lu = "都说冰糖葫芦儿酸" # 声明字符串
print(tang_hu_lu) # 打印输出字符串
print(tang_hu_lu[0]) # 打印字符串的第一个字符

注意代码都是在 jupyter 中进行编写,然后点击运行实现效果,运行的快捷键是 shift+enter

又是一段代码,里面又涉及了很多编程概念,例如 tang_hu_lu 你已经知道它是一个变量了,

但是 Python 变量是有命名规范的,例如 1_a 就是错误的,命名规范是啥呢?

学习建议是直接搜索,只有一个原则需要告诉你,就是命名尽量有含义,哪怕你用拼音。

# 表示注释,相当于备注的意思,写在 # 后面的内容不会被 Python 软件 执行。

tang_hu_lu[0] 这里就有趣了,在变量名称后面跟了一个中括号[],并且在里面写了一个数字 0

它表示取这个串 里面的第一个字符,在编程语言中,报数 一般从 0 开始,也就是 0 表示第一位,

知道二进制不?二进制用 01 表示,所以从 0 开始数。

取第一个字符咱们已经会了,那最后一个呢

tang_hu_lu = "都说冰糖葫芦儿酸" # 声明字符串
print(tang_hu_lu) # 打印输出字符串
print(tang_hu_lu[-1]) # 打印字符串的最后一个字符
print(tang_hu_lu[7]) # 打印字符串的最后一个字符

上述代码就实现了,注意中括号里面的数字 [-1] 就是倒着数最后一个,当然你可以顺着数,

数到 7 就是第八个山楂 了,这里尝试把 7 修改成 8 ,看一下会报什么错误吧。

到这里就不得不抛出一个新的名词了,索引 ,刚才中括号中的数字就是 索引值,又是一个新概念,这就是编程。

字符串的第一个和最后一个你都能获取到了,吃中间的怎么办

tang_hu_lu = "都说冰糖葫芦儿酸" # 声明字符串
print(tang_hu_lu) # 打印输出字符串
print(tang_hu_lu[2:4]) # 输出冰糖
print(tang_hu_lu[3:5]) # 输出糖葫

注意中括号扩展了,变成了 2 个数字,中间还有一个英文的冒号,此时一定要对比着原字符串进行学习。

- 都说冰糖葫芦儿酸
- 0 1 2 3 4 5 6 7

看好各个的位置

  • [2:4] 输出冰糖,分别对应索引 2,索引 3 位置的字符;
  • [3:5] 输出糖葫,分别对应索引 3,索引 4 位置的字符;

[0:6] 你知道输出什么了吗?能说出来,恭喜你,Python 字符串切片 你已经掌握 90%了,想不到吧,又是一个新概念,

切片,多么形象!

字符串扩展方法

字符串除了切片用法以外,还可以使用一个新的概念,叫做 对象的方法 ,在 Python 中有一个说法,叫做万物皆对象(对象的概念我们在后文展开学习,现在知道这么回事即可),例如现在有一个字符串,内容是 "都说冰糖葫芦儿酸"

先看代码

my_str = "都说冰糖葫芦儿酸"
a = my_str.find("糖")
print(a) # 输出内容为 3

find() 方法

上述代码中,在字符串变量 my_str 的后面增加一段代码 .find("糖"),其中 .find() 就是一个字符串对象的方法 ,它的用途你顺着刚才的代码在细琢磨,就能知道,是查找 "糖" 这个小字符串在大字符串中的索引值。

同理,还有哪些需要掌握的字符串对象方法呢?

my_str = "AaBbCcDd"
new_my_str = my_str.title()
print(new_my_str) # Aabbccdd

title() 方法

.title() 方法表示将字符串首字母大写

my_str = "AaBbCcDd"
new_my_str = my_str.upper()
print(new_my_str) # AABBCCDD

**upper() 方法和 lower() 方法 **

.upper() 方法表示将字符串全部大写,全部小写是 .lower()

字符串去除左右两端的空格。

my_str = " AaBbCcDd "
new_my_str = my_str.strip()
print(new_my_str)

除了这些,字符串对象的方法还有很多,但是不需要记忆,你需要去搜索一些相关的博客进行阅读,

搜索关键字为 Python 字符串方法,然后看上几篇博客,最终得到下面这个结论:

"哦~字符串对象有这些方法,可以大小写转换,可以去除空格,可以检索字符串,可以统计字符出现次数,

还能判断字符串中字符内容......"

子串搜索相关方法

count() 方法

语法格式如下所示:

my_str.count(sub_str[, start[, end]])

返回字符串 my_str 中子串 sub_str 出现的次数,可以指定从开始(start)计算到结束(end)。

print('abcaaabbbcccdddd'.count('a'))

endswith()和 startswith()

方法原型如下

my_str.endswith(suffix[, start[, end]])
my_str.startswith(prefix[, start[, end]])

endswith() 检查字符串 my_str 是否以 suffix(可以是一个元组) 结尾,返回布尔值的 True 和 False。
startswith() 用来判断字符串 my_str 是否是以 prefix 开头。

find(),rfind()和 index(),rindex()

函数原型如下所示:

my_str.find(sub[, start[, end]])
my_str.rfind(sub[, start[, end]])
my_str.index(sub[, start[, end]])
my_str.rindex(sub[, start[, end]])

find() 搜索字符串 my_str 中是否包含子串 sub,包含返回 sub 的索引位置,否则返回"-1"。

index()find() 不同点在于当找不到子串时,抛出ValueError错误。

替换相关方法

replace()

my_str.replace(old, new[, count])

将字符串中的 old 替换为 new 字符串,如果给定 count,则表示只替换前 count 个 old 子串。

分割和合并

split()、rsplit()和 splitlines()

my_str.split(sep=None, maxsplit=-1)
my_str.rsplit(sep=None, maxsplit=-1)
my_str.splitlines([keepends=True])

split() 根据 sep 对 my_str 进行分割,maxsplit用于指定分割次数。

splitlines() 用来分割换行符。

join()

my_str.join(iterable)

将可迭代对象中的元素使用字符 my_str 连接起来。

修剪

strip()、lstrip()和 rstrip()

my_str.strip([chars])
my_str.lstrip([chars])
my_str.rstrip([chars])

分别是移除左右两边、左边、右边的字符 char。默认移除空白(空格、制表符、换行符)。

上述代码中的 len() 就是一个 Python 内置函数,它表示统计长度,

注意看内置函数和刚才学到的方法之间的差异,len() 函数,前面并没有对象去调用它,
调用 其实也是一个编程概念,就是那个 . 符号。

统计过程,你也会注意到 " AaBbCcDd " 算上空格,恰好是 10 个 字符,所以得出空格也是字符,这个基本认知。

后续我们还会学习更多的内置函数,接下来在学习 2 个,这两个有助于提高编程效率。

第一个是 help(),该函数用来查看编程对象的帮助手册,例如下述代码

my_str = " AaBbCcDd "
help(my_str )

不过该代码无法在 jupyter 中运行,会得到如下结果

这里可以直接输入 help(),进入手册模式,在进行查询即可。

在文本框输入 str,就可以获取到帮助手册中的相关内容,也就是获取到了字符串对象的相关方法。

第 3 个要学习的内置函数是 dir(),使用该函数可以直接把对象支持的方法全部输出。

my_str = " AaBbCcDd " print(dir(my_str))

字符串格式化

在 Python 中,字符串格式化有三种方式,分别为 % 占位符格式化,format() 方法格式化,以及 f-string

重点学习的是第二种和第三种方式进行格式化,例如下述代码:

my_str = "小爱同学,今天天气"
answer_str = "今天的天气是: {}".format("晴")
print(answer_str)

第二个字符串中出现了一个大括号 {},然后通过 format() 函数对其进行了填充,

同理,大括号可以出现多个,也可以有名称,例如下述代码:

# 多个大括号,format() 方法中需要多个值进行填充
my_str = "小爱同学,今天天气"
answer_str = "今天上午的天气是: {},下午的天气是:{}".format("晴","多云")
print(answer_str)
# 大括号中有占位符
my_str = "小爱同学,今天天气"
answer_str = "今天上午的天气是: {shangwu},下午的天气是:{xiawu}".format(shangwu="晴",xiawu="多云")
print(answer_str)

在使用占位符的时候注意下,前后要一致,否则会出错的。

上述代码其实用到了函数相关支持,这些随着我们的学习,都将逐步展开,当下最有效的学习方式,就是临摹一遍代码啦。

在使用占位符的时候注意下,前后要一致,否则会出错的。

上述代码其实用到了函数相关支持,这些随着我们的学习,都将逐步展开,当下最有效的学习方式,就是临摹一遍代码啦。

Python lambda 表达式是什么

lambda 表达式也叫做匿名函数,在定义它的时候,没有具体的名称,一般用来快速定义单行函数,直接看一下基本的使用:

fun = lambda x:x+1
print(fun(1))

查看上面的代码就会发现,使用 lambda 表达式定义了一行函数,没有函数名,后面是是函数的功能,对 x 进行 +1 操作。

稍微整理一下语法格式:

lambda [参数列表]:表达式 # 英文语法格式 lambda [arg1[,arg2,arg3....argN]]:expression

语法格式中有一些注意事项:

  1. lambda 表达式必须使用 lambda 关键字定义;
  2. lambda 关键字后面,冒号前面是参数列表,参数数量可以从 0 到任意个数。多个参数用逗号分隔,冒号右边是 lambda 表达式的返回值。

本文开始的代码,如果你希望进行改写成一般函数形式,对应如下:

fun = lambda x:x+1
# 改写为函数形式如下:
def fun(x):return x+1

当然,如果你决定上述 fun() 也多余,匿名函数就不该出现这些多余的内容,你也可以写成下面这个样子,

不过代码的可读性就变低了。

print((lambda x:x+1)(1))

lambda 表达式一般用于无需多次使用的函数,并且该函数使用完毕就释放了所占用的空间。

怎么用

lambda 表达式与 def 定义函数的区别

第一点:一个有函数名,一个没有函数名

第二点:lambda 表达式 : 后面

只能有一个表达式,多个会出现错误,也就是下面的代码是不会出现的。

# 都是错误的
lambda x:x+1 x+2

由于这个原因的存在,很多人也会把 lambda 表达式称为单表达式函数

第三点:for 语句不能用在 lambda 中

有的地方写成了 if 语句和 print 语句不能应用在 lambda 表达式中,该描述不准确,例如 下述代码就是正确的。

lambda a: 1 if a > 10 else 0

基本结论就是:lambda 表达式只允许包含一个表达式,不能包含复杂语句,该表达式的运算结果就是函数的返回值。

第四点:lambda 表达式不能共享给别的程序调用

第五点:lambda 表达式能作为其它数据类型的值

例如下述代码,用 lambda 表达式是没有问题的。

my_list = [lambda a: a**2, lambda b: b**2]
fun = my_list[0]
print(fun(2))
lambda 表达式应用场景

在具体的编码场景中,lambda 表达式常见的应用如下:

1. 将 lambda 表达式赋值给一个变量,然后调用这个变量

上文涉及的写法多是该用法。

fun = lambda a: a**2
print(fun(2))

2. 将 lambda 表达赋值给其它函数,从而替换其它函数功能

一般这种情况是为了屏蔽某些功能,例如,可以屏蔽内置 sorted 函数。

sorted = lambda *args:None
x = sorted([3,2,1])
print(x)

3. 将 lambda 表达式作为参数传递给其它函数

在某些函数中,函数设置中是可以接受匿名函数的,例如下述排序代码:

my_list = [(1, 2), (3, 1), (4, 0), (11, 4)]
my_list.sort(key=lambda x: x[1])
print(my_list)

my_list 变量调用 sort 函数,参数 key 赋值了一个 lambda 表达式,

该式子表示依据列表中每个元素的第二项进行排序。

4. 将 lambda 表达式应用在 filter、map、reduce 高阶函数中

这个地方先挖下一个小坑,你可以自行扩展学习。

5. 将 lambda 表达式应用在函数的返回值里面

这种技巧导致的结论就是函数的返回值也是一个函数,具体测试代码如下:

def fun(n): return lambda x:x+n new_fun = fun(2) print(new_fun) # 输出内容:<function fun.<locals>.<lambda> at 0x00000000028A42F0>

上述代码中,lambda 表达式实际是定义在某个函数内部的函数,称之为嵌套函数,或者内部函数。

对应的将包含嵌套函数的函数称之为外部函数。

内部函数能够访问外部函数的局部变量,这个特性是闭包(Closure)编程的基础

闭包(Closure)是指在一个函数内部定义另一个函数,并且这个内部函数可以访问外部函数的局部变量,即使外部函数执行完毕后,这些局部变量依然会被"记住"并保存下来,供内部函数使用。这种特性在编程中非常有用。

闭包的定义

闭包是一个函数对象,这个对象能够记住定义它的环境中的变量值(即外部函数的局部变量),即使在环境已经不存在的情况下,仍然能够访问这些变量。

闭包的三要素

要形成闭包,需要以下三要素:

  1. 外部函数:外层函数中定义了一个变量或参数。
  2. 内部函数:在外层函数中定义的函数(称为嵌套函数)。
  3. 返回内部函数:外部函数返回内部函数,使内部函数可以在外部调用时继续访问外部函数的变量。

闭包的作用

闭包主要用于在一个函数的内部定义并返回一个内部函数,使这个内部函数"记住"并可以访问外部函数的变量。这样可以用于创建带有持久状态的函数,常用于工厂函数、定制化函数、数据封装等场景。

闭包的示例

以下代码演示了闭包的概念:

def make_multiplier(n): def multiplier(x): return x * n return multiplier

在这里,make_multiplier 是外部函数,multiplier 是内部函数。即使 make_multiplier 执行完并退出,它的参数 n 仍然会被 multiplier 函数"记住"。

times_3 = make_multiplier(3) # 创建一个闭包,n = 3 times_5 = make_multiplier(5) # 创建另一个闭包,n = 5 print(times_3(10)) # 输出 30,因为 10 * 3 = 30 print(times_5(10)) # 输出 50,因为 10 * 5 = 50

在这段代码中:

  • times_3 是一个闭包,记住了 n = 3 的状态。
  • times_5 是另一个闭包,记住了 n = 5 的状态。

闭包的关键点

  • 持久化状态:闭包会"记住"外部函数的变量,因此在多次调用时可以保持一致的行为。
  • 数据封装:闭包将数据(外部变量)封装在函数内部,使得在调用时无需外部提供这些变量值。

闭包的实际应用

闭包在许多场景中非常有用,例如创建特定的数学运算函数、定制化回调函数、创建工厂函数等。

扩展知识

lambda 表达式虽然有优点,但不应过度使用 lambda,最新的官方 Python 风格指南 PEP8 建议永远不要编写下述代码:

normalize_case = lambda s: s.casefold()

因此你想创建一个函数并存储到变量中, 请使用 def 来定义。

不必要的封装

我们实现一个列表排序,按照绝对值大小进行。

my_list = [-1,2,0,-3,1,1,2,5]
sorted_list = sorted(my_list, key=lambda n: abs(n))
print(sorted_list)

上述貌似用到了 lambda 表达式,但是确忘记了,在 Python 中所有的函数都可以当做参数传递。

my_list = [-1,2,0,-3,1,1,2,5]
sorted_list = sorted(my_list, key=abs)
print(sorted_list)

也就是当我们有一个满足要求的函数的时候,没有必要在额外的去使用 lambda 表达式了。

扩展知识

lambda 表达式虽然有优点,但不应过度使用 lambda,最新的官方 Python 风格指南 PEP8 建议永远不要编写下述代码:

normalize_case = lambda s: s.casefold()

因此你想创建一个函数并存储到变量中, 请使用 def 来定义。

不必要的封装

我们实现一个列表排序,按照绝对值大小进行。

my_list = [-1,2,0,-3,1,1,2,5]
sorted_list = sorted(my_list, key=lambda n: abs(n))
print(sorted_list)

上述貌似用到了 lambda 表达式,但是确忘记了,在 Python 中所有的函数都可以当做参数传递。

my_list = [-1,2,0,-3,1,1,2,5]
sorted_list = sorted(my_list, key=abs)
print(sorted_list)

也就是当我们有一个满足要求的函数的时候,没有必要在额外的去使用 lambda 表达式了。

参考教程:

列表推导式-进阶语法-CSDNPython入门技能树

相关推荐
摇光9311 分钟前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
沐泽Mu15 分钟前
嵌入式学习-QT-Day09
开发语言·qt·学习
测试杂货铺18 分钟前
UI自动化测试实战实例
自动化测试·软件测试·python·selenium·测试工具·测试用例·pytest
小猿_0020 分钟前
C语言实现顺序表详解
c语言·开发语言
余~~1853816280041 分钟前
NFC 碰一碰发视频源码搭建技术详解,支持OEM
开发语言·人工智能·python·音视频
苏三有春1 小时前
PyQt实战——使用python提取JSON数据(十)
python·json·pyqt
GOATLong1 小时前
c++智能指针
开发语言·c++
Dola_Pan1 小时前
C语言:随机读写文件、实现文件复制功能
c语言·开发语言
佳心饼干-1 小时前
C语言-08复合类型-结构体
c语言·开发语言