Python基础——1.4结构语句(if、for、while)-语句关键词-迭代器-生成器(表达式)-三元表达式-列表生成式

一、if分支结构

分支结构就是根据条件判断的真假去执行不同分支对应的子代码

# if 语句
	if 表达式:
		代码块
        
# if else 语句
	if 表达式:
		代码块1
	else:
    	代码块2
        
# if elif else 语句
	if 表达式1:
		代码块1
	elif 表达式2:
		代码块2
	elif 表达式3:
    	代码块3
	else:
   		代码块n

1.注意事项

  • if、elif、else 语句的最后都有冒号:

  • elif 和 else 都不能单独使用必须和 if 一起出现,且要正确配对

  • 表达式可以是单一的值或者变量,也可以是由运算符组成的复杂语句,但执行结果必须为布尔类型

  • 一旦某个表达式成立就会执行它后面对应的代码块;如果所有表达式都不成立,就执行 else 后面的代码块;如果没有 else 部分,那就什么也不执行

  • 在if判断中所有数据类型都会自动转换成布尔类型,用作布尔表达式(如用作if语句中的条件)时,下面的值都将被解释器视为假,但它们并不相等:

    ​ False None 0 “” () [] {}

  • 换而言之,标准值False和None、各种类型(包括浮点数、复数等)的数值0、空序列(如空

    字符串、空元组和空列表)以及空映射(如空字典)都被视为假,而其他各种值都被视为真,

    包括特殊值True

2.缩进要求

  • 不要忘记缩进

if、elif 和 else 后面的代码块一定要缩进,而且缩进量要大于 if、elif 和 else 本身

  • 缩进1 个 Tab 键

Python 要求代码块必须缩进,缩进量不限,建议缩进 1 个 Tab 键的位置或缩进 4 个空格;两者等价

  • 所有语句都要缩进,且同一代码块缩进量要相同

一个代码块的所有语句都要缩进,而且缩进量必须相同。

  • 不要随便缩进

不需要使用代码块的地方千万不要缩进,一旦缩进就会产生一个代码块

3.语句嵌套

if、if else 和 if elif else,这 3 种条件语句间可相互嵌套

# 在最简单的 if 语句中嵌套 if else 语句
if 表达式1if 表示式2:
        代码块1
    else:
        代码块2        
# 在 if else 语句中嵌套 if else 语句
if 表示式 1if 表达式2:
        代码块1
    else:
        代码块2
elseif 表达式3:
        代码块3
    else:
        代码块4

if、if else 和 if elif else 之间可相互嵌套。开发程序时根据场景需要选择合适的嵌套方案。在相互嵌套时,一定要严格遵守不同级别代码块的缩进规范

number = int(input('Enter a number between 1 and 10: '))
if number <= 10:
    if number >= 1:
        print('Great!')
    else:
        print('Wrong!')
else:
    print('Wrong!')
    
# 这有点笨拙,因为输入了print('Wrong!')两次。
number = int(input('Enter a number between 1 and 10: '))
if number <= 10 and number >= 1:
    print('Great!')
else:
    print('Wrong!')

# 通过使用链式比较1 <= number <= 10可进一步简化示例。
number = int(input('Enter a number between 1 and 10: '))
if 1 <= number <= 10:
    print('Great!')
else:
    print('Wrong!')

4.三目运算符

# 语法:条件为真时的结果  if  判断的条件  else  条件为假时的结果
a if a>b else c if c>d else d
# 应该理解为
a if a>b else ( c if c>d else d )

二、循环结构

python中有while与for两种循环机制,其中while循环称之为条件循环

1.while

while 条件表达式:
    代码块
# 此代码块指缩进格式相同的多行代码,在循环结构中,代码块又称为循环体
  • while 语句执行流程:

    首先判断条件表达式的值,其值为真(True)时执行代码块中的语句,执行完毕后,再回来重新判断条件表达式的值是否为真,若仍为真,则继续重新执行代码块…如此循环,直到条件表达式的值为假(False)才终止循环

注意:使用 while 循环时要保证循环条件有变假时(循环结构中至少有一个位置能让循环条件为 False 或让 break 语句得以执行),否则将成为死循环(无法结束循环)。纯计算无IO的死循环会导致致命的效率问题

2.for

循环结构的第二种方式for循环可做的while循环都可实现,但在循环取值(即遍历值)时for循环比while循环更为简洁。它常用于遍历字符串、列表、元组、字典、集合等序列类型,逐个获取序列中的各个元素。只要能够使用for循环,就不要使用while循环。

# for 循环的语法格式
for 变量名 in 可迭代对象: 
    代码一
    代码二
    ...
for item in ['a','b','c']:
    print(item)   # a b c
    
# 步骤1:从列表['a','b','c']中读出第一个值赋值给item(item=‘a’),然后执行循环体代码
# 步骤2:从列表['a','b','c']中读出第二个值赋值给item(item=‘b’),然后执行循环体代码
# 步骤3: 重复以上过程直到列表中的值读尽

列表推导式:

# 列表推导式语法: 
[ 表达式 for 变量 in range(起始位置, 结束位置, 步长) ]

# 根据需求快速生成一个列表
a = [i for i in range(4)]
print(a)  #输出结果:[0, 1, 2, 3]
a = [x for x in range(3, 4)] #结果:a = 3

# 在循环的过程中使用if
a = [x for x in range(3, 10) if x % 2 == 0]  #结果:a = [4,6,8]

# 普通方式创建列表
a = []
for i in range(100):
    a.append(i)
print(a)

# 推导式创建列表
a = [value for value in range(100)]
print(a)

# 创建⼀个包含10个随机数的列表
import random

my_list = [random.randint(1, 10) for _ in range(10)]
print(my_list)

# 将上⾯列表中的元素, 加 10

new_list = [value + 10 for value in my_list]
print(new_list)

# 序列中所有的偶数组合成列表

my_list = [value for value in range(10) if value % 2 == 0]
print(my_list)

# 输出:

# [1, 2, 9, 5, 10, 3, 9, 7, 2, 6]

# [11, 12, 19, 15, 20, 13, 19, 17, 12, 16]

# [0, 2, 4, 6, 8]
1)迭代字典
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
    print(key, 'corresponds to', d[key])
    # x corresponds to 1
	# y corresponds to 2
	# z corresponds to 3
    
# 也可使用keys等字典方法来获取所有的键。如果只对值感兴趣,可使用d.values。你可能还记得,d.items以元组的方式返回键值对。for循环的优点之一是,可在其中使用序列解包。
for key, value in d.items():
    print(key, 'corresponds to', value)
    # x corresponds to 1
	# y corresponds to 2
	# z corresponds to 3
    
# 字典元素的排列顺序是不确定的。换而言之,迭代字典的键或值时,一定会处理所有的键或值,但不知道处理的顺序。
2)并行迭代
# 同时迭代两个序列:
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]

# 打印名字和对应的年龄,i是用作循环索引的变量的标准名称。
for i in range(len(names)):
    print(names[i], 'is', ages[i], 'years old')
    # anne is 12 years old
    # beth is 45 years old
    # george is 32 years old
    # damon is 102 years old
zip()

并行迭代工具是内置函数zip,它将两个序列“缝合”起来,并返回一个由元组组成的序列。返回值是一个适合迭代的对象,要查看其内容,可使用list将其转换为列表。

print(list(zip(names, ages)))
# [('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]

# “缝合”后,可在循环中将元组解包。
for name, age in zip(names, ages):
    print(name, 'is', age, 'years old')
    # anne is 12 years old
    # beth is 45 years old
    # george is 32 years old
    # damon is 102 years old
record_sum.sort(reverse=True) 
# 函数zip可用于“缝合”任意数量的序列。需要指出的是,当序列的长度不同时,函数zip将在最短的序列用完后停止“缝合”。
print(list(zip(range(5), range(100000000))))
# [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
3)获取索引

在迭代对象序列的同时获取当前对象的索引

# 如替换一个字符串列表中所有包含子串'xxx'的字符串。假设:
for string in strings:
    if 'xxx' in string:
        index = strings.index(string)  # 在字符串列表中查找字符串
        strings[index] = '[censored]'
        
# 上面替换前的搜索没有必要。如果没有替换,搜索返回的索引(即返回的是该字符串首次出现处的索引)就为-1,下面的语句会报错。下面是一种更佳的解决方案:
index = 0
for string in strings:
    if 'xxx' in string:
        strings[index] = '[censored]'
    index += 1
enumerate()

能够迭代索引-值对,其中的索引是自动提供的

# 无需设置index变量,直接获取索引和索引对应的值
for index, string in enumerate(strings):
    if 'xxx' in string:
        strings[index] = '[censored]'
4)反向迭代

reversed和sorted类似于列表方法reverse和sort(sorted接受的参数也与sort类似),但可用于任何序列或可迭代的对象,且不就地修改对象,而是返回反转和排序后的版本

# sorted返回一个列表,而reversed像zip返回可迭代对象,不能对可迭代对象执行索引或切片操作,也不能直接对可迭代对象调用列表的方法。要执行这些操作,可先使用list对返回的对象进行转换。

print(list(reversed('Hello, world!')))
# ['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
print(''.join(reversed('Hello, world!')))
# !dlrow ,olleH
5)排序迭代

要按字母表排序,可先转换为小写。为此,可将sort或sorted的key参数设置为str.lower。例如,sorted(“aBc”, key=str.lower)返回[‘a’, ‘B’, ‘c’]

print(sorted([4, 3, 6, 8, 3]))
# [3, 3, 4, 6, 8] 
print(sorted('Hello, world!'))
# [' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
6)列表推导

列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。列表推导的工作原理非常简单,有点类似于for循环。

print([x * x for x in range(10)])
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 这个列表由range(10)内每个值的平方组成。只打印能被3整除的平方值,可使用求模运算符:
# 如果y能被3整除,y 3 % 将返回0(请注意,仅当x能被3整除时,x*x才能被3整除)。
# 可在列表推导中添加一条if语句。
print([x * x for x in range(10) if x % 3 == 0])
# [0, 9, 36, 81]

# 还可添加更多的for部分。
print([(x, y) for x in range(3) for y in range(3)])
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

# 作为对比,下面的两个for循环创建同样地列表:
result = []
for x in range(3):
    for y in range(3):
        result.append((x, y))
print(result)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

使用多个for部分时,也可添加if子句。

# 这些代码将名字的首字母相同的男孩和女孩配对。
girls = ['alice', 'bernice', 'clarice']
boys = ['chris', 'arnold', 'bob']
print([b + '+' + g for b in boys for g in girls if b[0] == g[0]])
# ['chris+clarice', 'arnold+alice', 'bob+bernice']

# 前述男孩/女孩配对示例的效率不太高,因为它要检查每种可能的配对。
girls = ['alice', 'bernice', 'clarice']
boys = ['chris', 'arnold', 'bob']
letterGirls = {}    # 创建一个名为letterGirls的字典
for girl in girls:   # 字典键为girls中每个名字首字母,值为该名字
    letterGirls.setdefault(girl[0], []).append(girl)
print([b + '+' + g for b in boys for g in letterGirls[b[0]]])  # 用boys中名字首字母作为键在letterGirls字典中查找,找的则返回键对应的值
# ['chris+clarice', 'arnold+alice', 'bob+bernice']

使用圆括号代替方括号并不能实现元组推导,而是将创建生成器,可使用花括号来执行字典推导。

# 在列表推导中for前面只有一个表达式,而在字典推导中,for前面有两个用冒号分隔的表达式。这两个表达式分别为键及其对应的值
squares = {i: "{} squared is {}".format(i, i ** 2) for i in range(10)}
print(squares[8])
# 8 squared is 64

3.else

while 循环和 for 循环其后都可紧跟着一个 else 代码块,当循环正常执行完且中间没有被break 中止就会执行else后面的语句,所以可用else来验证循环是否正常结束。

如果执行过程中被break,就不会执行else的语句

count = 0
while count <= 5 :
    count += 1
    print("Loop",count)
else:
    print("循环正常执行完啦")
print("-----out of while loop ------")
# 输出
# Loop 1
# Loop 2
# Loop 3
# Loop 4
# Loop 5
# Loop 6
# 循环正常执行完啦   	#没有被break打断,所以执行了该行代码
# -----out of while loop ------

# 如果执行过程中被break,就不会执行else的语句
count = 0
while count <= 5 :
    count += 1
    if count == 3:
        break
    print("Loop",count)
else:
    print("循环正常执行完啦")
print("-----out of while loop ------")
# 输出
# Loop 1
# Loop 2
# -----out of while loop ------    #由于循环被break打断了,所以不执行else后的输出语句

4.循环嵌套

while 和 for 循环结构也支持嵌套。当 2 个(甚至多个)循环结构相互嵌套时,位于外层的循环结构常简称为外层循环或外循环,位于内层的循环结构常简称为内层循环或内循环。

循环嵌套结构的代码,Python 解释器执行的流程为:

  1. 当外层循环条件为 True 时,则执行外层循环结构中的循环体;
  2. 外层循环体中包含了普通程序和内循环,当内循环的循环条件为 True 时会执行此循环中的循环体,直到内循环条件为 False,跳出内循环;
  3. 若外层循环的条件仍为 True,则返回第 2 步继续执行外层循环体,直到外层循环的循环条件为 False;
  4. 当内层循环的循环条件为 False,且外层循环的循环条件也为 False,则整个嵌套循环才算执行完毕

嵌套循环执行的总次数 = 外循环执行次数 * 内循环执行次数

  • if 语句和循环(while、for)结构之间,也可以相互嵌套
i = 0
if i<10:
    for j in range(5):
        print("i=",i," j=",j) 
  • if、while、for 之间支持多层( ≥3 )嵌套
if ...:
    while ...:
        for ...:
            if ...:
                ...

三、语句关键字

1.pass

在实际开发中,有时会先搭建起程序的整体逻辑结构,但暂时不去实现某些细节。程序有时需要占一个位置或放一条语句,但又不希望这条语句做任何事情,此时可以通过 pass 语句来实现。pass 是 Python 中的关键字,用来让解释器跳过此处,什么都不做。

if name == 'Ralph Auldus Melish':
    print('Welcome!')
elif name == 'Enid':
    # 还未完成……
elif name == 'Bill Gates':
    print('Access Denied')
    
# 这些代码不能运行,因为在Python中代码块不能为空。要修复这个问题,只需在中间的代码块中添加一条pass语句即可。
if name == 'Ralph Auldus Melish':
    print('Welcome!')
elif name == 'Enid':
    # 还未完成……
    pass
elif name == 'Bill Gates':
    print('Access Denied')

也可不使用注释和pass语句,而是插入一个字符串。这种做法尤其适用于未完成的函数和类,因为这种字符串将充当文档字符串

2.assert

assert 语句又称断言语句,用于判断某个表达式的值,若值为真,则程序继续向下执行;反之主动报错,执行可用 if 语句表示。assert 在错误条件出现时直接让程序崩溃。常用于检查用户的输入是否符合规定,还常用作程序初期测试和调试过程中的辅助工具

if 表达式==True:
    程序继续执行
else:
    程序报 AssertionError 错误

assert 的检查可以关闭,在命令行模式下运行 Python 程序时,加入 -O 选项可以使程序中的 assert 失效。一旦 assert 失效,其包含的语句也就不会被执行

3.break

在执行 while 循环或者 for 循环时,Python提供了 2 种强制离开当前循环体的办法

  1. 使用 continue 语句,可以跳过执行本次循环体中剩余的代码,转而执行下一次的循环
  2. 只用 break 语句,可以完全终止当前循环

break用法

  • break 语句可立即终止当前循环的执行,跳出当前所在的循环结构。无论是 while 循环还是 for 循环,只要执行 break 语句,就会直接结束当前正在执行的循环体。
  • break 语句的语法只需要在相应 while 或 for 语句中直接加入即可
  • break 语句一般结合 if 语句进行搭配使用,表示在某种条件下跳出循环体
username = "jason"
password = "123"
# 记录错误验证的次数
count = 0
while count < 3:
    inp_name = input("请输入用户名:")
    inp_pwd = input("请输入密码:")
    if inp_name == username and inp_pwd == password:
        print("登陆成功")
        break # 用于结束本层循环
    else:
        print("输入的用户名或密码错误!")
        count += 1

循环嵌套+break

如果循环嵌套了很多层,要想退出每一层循环则需要在每一层循环都有一个break

username = "jason"
password = "123"
count = 0
while count < 3:  # 第一层循环
    inp_name = input("请输入用户名:")
    inp_pwd = input("请输入密码:")
    if inp_name == username and inp_pwd == password:
        print("登陆成功")
        while True:  # 第二层循环
            cmd = input('>>: ')
            if cmd == 'quit':
                break  # 用于结束本层循环,即第二层循环
            print('run <%s>' % cmd)
        break  # 用于结束本层循环,即第一层循环
    else:
        print("输入的用户名或密码错误!")
        count += 1

针对嵌套多层的while循环,若很明确要在某一层直接退出所有层的循环,其实就让所有while循环的条件都用同一变量,该变量的初始值为True,一旦在某一层将该变量的值改成False,则所有层的循环都结束

username = "jason"
password = "123"
count = 0
tag = True
while tag: 
    inp_name = input("请输入用户名:")
    inp_pwd = input("请输入密码:")
    if inp_name == username and inp_pwd == password:
        print("登陆成功")
        while tag:  
            cmd = input('>>: ')
            if cmd == 'quit':
                tag = False  # tag变为False, 所有while循环的条件都变为False 
                break
            print('run <%s>' % cmd)
        break  # 用于结束本层循环,即第一层循环
    else:
        print("输入的用户名或密码错误!")
        count += 1

4.continue

和 break 语句相比,continue 语句只会终止执行本次循环中剩下的代码,直接从下一次循环继续执行。continue 语句的用法和 break 语句一样,只要 while 或 for 语句中的相应位置加入即可

# 打印1到10之间,除7以外的所有数字
number=11
while number>1:
    number -= 1
    if number==7:
        continue 
        # 结束掉本次循环,即本次循环continue之后的代码都不会运行了,而是直接进入下一次循环
    print(number)

四、迭代器(Iterator)

迭代器是迭代取值的工具,迭代器基于索引迭代取值的局限性,能够不依赖于索引的取值方式

迭代是一个重复的过程,每次重复都基于上一次的结果而继续。单纯的重复不是迭代。

可多个值循环列举的类型有:列表,字符串,元祖,字典,集合,文件

l = [1,2,3]
i = 0
while i<len(l):
	print(l[i])
	i+=1
#上述索引迭代取值的方式只适用于有索引的数据类型:列表,字符串,元祖

1.对象

  • 可迭代对象(可以转换成迭代器的对象):内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象。
  • 可迭代对象.iter():得到迭代器对象
  • 迭代器对象:迭代器对象(Iterator)是调用obj.iter()方法返回的结果,是内置有iter和next方法的对象,打开的文件是迭代器对象。
  • 迭代器对象.next():得到迭代器的下一个值
  • 迭代器对象.iter():得到迭代器的本身
d = {'a': 1, 'b': 2}
d_iter = iter(d)
count = 0
while count < len(d):
    print(next(d_iter))
    count += 1
print('%' * 20)
# a
# b
# %%%%%%%%%%%%%%%%%%%%
d = {'a':1,'b':2}
d_iter = iter(d)
print(d_iter is iter(d_iter))
# True

2.优缺点

优点

  • 为序列和非序列类型提供了一种统一的迭代取值方式
  • 惰性计算:节省内存。迭代器对象表示的是一个数据流,可以只在需要时去调用next来计算出一个值
  • 就迭代器本身,同一时刻在内存中仅有一个值,因而可存放无限大的数据流
  • 其他容器类型如列表,需把所有元素都存放于内存中,受内存大小的限制,可存放值的个数有限

缺点

  • 除非取尽,否则无法获取迭代器的长度(只有在next完毕才知道到底有几个值)。
  • 只能取下一个值,不能回到开始,一次性的只能往后走而不能往前退。
  • 迭代器产生后唯一目标就是重复执行next方法直到值取尽,否则会停留在某位置等待下一次调用next
  • 再次迭代同个对象,只能重新调用iter方法创建新迭代器对象,若有两个或者多个循环使用同一迭代器,只有一个循环能取到值

3.再谈for循环

for循环原理是迭代器使用while循环的简化

  • 迭代器使用while循环的实现方式如下
goods=['mac','lenovo','acer','dell','sony']
i=iter(goods)  #每次都需要重新获取一个迭代器对象
while True:
    try:
        print(next(i))
    except StopIteration: #捕捉异常终止循环
        break
# mac
# lenovo
# acer
# dell
# sony
  • for循环又称为迭代循环,in后可以跟任意可迭代对象,上述while循环可以简写为
goods=['mac','lenovo','acer','dell','sony']
for item in goods:   
    print(item)
  • for 循环首先会调用可迭代对象goods内置的iter方法拿到一个迭代器对象,然后再调用该迭代器对象的next方法将取到的值赋给item,执行循环体完成一次循环,周而复始,直到捕捉StopIteration异常,结束迭代
# for循环可以称之为迭代循环
d = {'a':1,'b':2}
for k in d:
	print(k)
# 1. d.__iter__()得到一个迭代器对象
# 2. 迭代器对象.__next__()拿到一个返回值,然后将该返回值赋值给k
# 3. 循环往复步骤2,直到抛出异常,for循环户捕捉异常然后结束循环
  • for循环的本质就是调用next()

4.常用函数

函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象

# 设可迭代对象array为例来介绍它们三个的用法
array=[1,2,3,4,5]
1)map()

map函数平方可迭代对象的每个元素

# map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下
array=[1,2,3,4,5]
res=map(lambda x:x**2,array)
print(res)
print(list(res))
# <map object at 0x00000262D0FD5D80>
# [1, 4, 9, 16, 25]
解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器
2)reduce()

reduce函数合并可迭代对象

注意:reduce在python3中被集成到模块functools中,需要导入才能使用

# reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值
from functools import reduce
array=[1,2,3,4,5]
res=reduce(lambda x,y:x+y,array)
print(res)
# 15

# 解析:没有初始值时reduce函数会先迭代一次array得到值1作为初始值传给第一个值x,然后继续迭代一次array得到值2传给第二个值y,运算的结果为3,将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果3作为第二个值传给y,依次类推,迭代完array的所有元素得到最终结果15

# 也可以为reduce指定初始值
from functools import reduce
array=[1,2,3,4,5]
res = reduce(lambda x,y:x+y,array,100)
print(res)
# 115
3)filter()

filter函数过滤可迭代对象

array=[1,2,3,4,5]
res = filter(lambda x: x > 3, array)
print(list(res))
# [4, 5]
# 解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器

提示:实际开发中,可以用列表生成式或生成器表达式来实现三者的功能

五、生成器(generator)

生成器就是自定义的迭代器

__next__  不建议使用
next()  使用这种
def func():
	print('第一次')
	yield 1
	print('第二次')
	yield 2
g = func()
print(g)
# <generator object func at 0x00000233F90F4580>

# g 就是生成器,就是自定义的迭代器,会触发函数体代码的运行,然后遇到yield停下来,将yield后的值当做本次调用的结果返回
res = next(g)
print(res)
# 第一次
# 1

函数体内若存在yield关键字,调用函数不会执行函数体代码,而是返回生成器对象,即自定义的迭代器

# 应用案例
def my_range(start, stop, step=1):
    while start < stop:
        yield start
        start += step
a = my_range(1, 7, 2)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
# 1
# 3
# 5
# Traceback (most recent call last):
#   File "C:\Users\14978\PycharmProjects\pythonProject\练习.py", line 9, in <module>
#     print(next(a))
# StopIteration
for x in my_range(1, 7, 2):
    print(x)
# 1
# 3
# 5

yield关键字是自定义迭代器的实现方式。不同于return,yield可用于返回值,但函数一旦遇到return就结束,而yield可以保存函数的运行状态挂起函数,用来返回多次值

def dog(name):
    print('狗准备吃东西')
    while True:
        x = yield # x 拿到的是yield接收的值,yield可以接收到外部send传过来的数据并赋值给x
		print('狗哥%s吃了%s' % (name, x))
        yield   # 针对表达式形式的yield,生成器对象必须事先被初始化一次,让函数挂起在food=yield的位置,等待调用g.send()方法为函数体传值,g.send(None)等同于next(g)
g = dog('旺旺')
g.send(None)  # 等同于next(g)
g.send('一根骨头')

# 狗准备吃东西
# 狗哥旺旺吃了一根骨头
  • 普通函数顺序执行,遇到return语句或者最后一行函数语句就返回
  • generator函数在每次调用next()的时候执行,遇到yield语句暂停并返回数据到函数外,再次被next()调用时从上次返回的yield语句处继续执行

六、表达式之快速操作

1.三元表达式

三元表达式是一种简化代码的解决方案,语法如下

res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值
def max2(x,y):
    if x > y:
        return x
    else:
        return y
res = max2(1,2)

# 用三元表达式可以一行解决
x=1
y=2
res = x if x > y else y # 三元表达式

2.列表生成式

列表生成式是一种简化代码的解决方案,用来快速生成列表

[expression for item1 in iterable1 if condition1]
或者:
[expression for item1 in iterable1]
# expression为新变量对旧变量的手段,item1为新变量,iterable1为旧变量,condition1为对新变量要求
l = ['muyi_nb', 'yimu_nb', 'lao_nb']

1.将所有小写字母转为大写
new_l = [x.upper() for x in l]  
print(new_l)
# ['MUYI_NB', 'YIMU_NB', 'LAO_NB']

2.取出所有的_nb
new_l = [x.split('_')[0] for x in l]
print(new_l)
new_l = [x.replace('_nb', '') for x in l if x=='yimu_nb']
print(new_l)
# ['muyi', 'yimu', 'lao']
# ['yimu']

3.字典生成式
items = [('name','muyi'),('age',18),('sex','man')]
res = {k:v for k,v in items if k!='sex'}
print(res)
# {'name': 'muyi', 'age': 18}

4.集合生成式
keys = ['name','age','sex']
set1 = {key for key in keys}
print(set1,type(set1))
# {'age', 'sex', 'name'} <class 'set'>

3.生成器表达式

创建生成器对象有两种方式:

  • 调用带yield关键字的函数
  • 生成器表达式,与列表生成式的语法格式相同,只需要将[]换成()
(expression for item in iterable if condition)
# expression为新变量对旧变量的手段,item1为新变量,iterable1为旧变量,condition1为对新变量要求

对比列表生成式返回的是一个列表,生成器表达式返回的是一个生成器对象

# 对比列表生成式,生成器表达式的优点是节省内存(一次只产生一个值在内存中)
a=[x*x for x in range(3)]
print(a)
# a=[0, 1, 4]
g=(x*x for x in range(3))
print(g)
# <generator object <genexpr> at 0x101be0ba0>
next(g)
# 0
next(g)
# 1
next(g)
# 4
next(g) #抛出异常StopIteration

# 如果我们要读取一个大文件的字节数,应该基于生成器表达式的方式完成
with open('db.txt','rb') as f:
    nums=(len(line) for line in f)
    total_size=sum(nums) # 依次执行next(nums),然后累加到一起得到结果
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木颤简叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值