迭代器、生成器、递归、三元表达、生成式

一、迭代器

概念

1、什么是迭代器

迭代器就是用来迭代取值的工具,那么什么是迭代呢?迭代就是一个重复的过程,但每次重复都是基于上一次结果进行的

# 单纯的重复不叫迭代
while True:
  1 + 1
  
# 下面才属于迭代过程
count = 1
while count < 5:
  print(count)
  count += 1

2、为何要用迭代器

优点:(1)找到一种通用的迭代取值方案==>for 循环

(2)惰性计算,节省内存

缺点:(1)不能直接取指定的值,只能依次next

(2)迭代器对象是一次性的:一个迭代器对象取值取干净了,就不能再继续取了

3、可迭代对象

内置有__iter__方法的对象都是可迭代对象

'abc'.__iter__()
"abc".__iter__()
[1, 2, 3].__iter__()
(1, 2, 3).__iter__()
{"x": 1, "y": 2}.__iter__()
{1, 2, 3, 4}.__iter__()
open('a.txt',mode='r').__iter__()

调用可迭代对象的iter会得到一个返回值,该返回值是迭代器对象

s = 'abc'
iter_s = s.__iter__()
# iter_s 就是s这个可迭代对象的迭代器对象

迭代器对象的特点:

(1)内置有 .next()方法

(2)内置有.iter()方法

s = "abc"
iter_s = s.__iter__()  # iter_s = iter(s)
print(iter_s.__next__())  # print(next(ites_s)) 输出a
print(iter_s.__next__())  # 输出b
print(iter_s.__next__())  # 输出c
print(iter_s.__next__())  # 再取就会报异常

dic = {'x':1,'y':2}
iter_dic = dic.__iter__()
print(iter_dic.__next__())
print(iter_dic.__next__())  # 取出的是字典的key值

虽然迭代器对象是有.__iter__方法的,但是我们发现,针对迭代器对象调用.__iter__得到的依然是之前那个可迭代对象的迭代器

items = [111, 222, 333]

print(len(items))  # items.__len__()

iter_s = iter(items)

print(iter_s.__iter__().__iter__().__iter__() is iter_s)  # 结果没有什么变化
 # names = ['egon', 'tom', 'jack', 'lili', 'ttt']
names = {"x":1,"y":2,'z':3}
# 权当我们此时并不知道for循环 我们需要将上述列表或字典 遍历
 iter_names = iter(names)
 while True:
     try:
         print(next(iter_names))
    except StopIteration:
        break
 # 用while循环写的迭代器循环

由上面我们大概可以看出for循环的工作原理:

(1)调出in后面那个对象的iter方法,得到一个迭代器对象iter_names

(2)x = next(iter_names),然后运行循环体代码

(3)重复步骤2,直到取完值,抛出异常,for循环会帮我们捕捉异常结束循环

names = ['egon', 'tom', 'jack', 'lili', 'ttt']


iter_s1 = iter(names)
print(next(iter_s1))
print(next(iter_s1))
print(next(iter_s1))
print(next(iter_s1))
print(next(iter_s1))

iter_s2=iter(names)  # 当我们想针对同一迭代器对象再次取值就需要再赋值一个迭代器对象

print(next(iter_s2))
print(next(iter_s2))
print(next(iter_s2))
print(next(iter_s2))
print(next(iter_s2))

# 但是我们使用for循环针对一个迭代器对象是可以多次取值的,因为在for循环内部,每次已经帮我们建好了迭代器

二、生成器

生成器就是迭代器,如何得到一个自定义的迭代器:在函数内一旦存在yield关键字,调用函数并不会执行函数体代码,会返回一个生成器对象,生成器即自定义的迭代器

def func():
    print('one')
    yield 1
    print('two')
    yield 2
    print('three')
    yield 3
    print('第四次')

func() # 此时python内检测到有yield该函数就算调用了也不会执行
g = func()  # 赋值给g
print(g)  # 输出结果为<generator object func at 0x1025ada50> 
# 会触发函数体代码的运行,然后遇到yield停下来,将yield后的值
# 当做本次调用的结果返回
res1=g.__next__()
print(res1)

res2=g.__next__()
print(res2)

res3=g.__next__()
print(res3)

res4=g.__next__()
def my_range(start,stop,step=1):
    # print('start...')
    while start < stop:
        yield start
        start+=step
    # print('end....')


g=my_range(1,5,2) # 1 3
print(next(g))
print(next(g))
print(next(g))



def func():
    res = 0
    while True:
        yield res
        res += 1

g=func()
# print(next(g))
# print(next(g))
# print(next(g))
for i in g:
    print(i)

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

三、函数递归调用

1、定义:是函数嵌套调用的一种特殊形式

具体是指:在调用一个函数的过程中又直接或者间接的调用到本身

# 直接调用本身
def f1():
  print('is me')
  f1()
f1()


# 间接调用本身
def f1()
	print('from f1')
  f2()
  
def f2():
  print('fromf2')
  f1()
  
f1()

# 这种函数造成的循环是有上限的 一般上线为1000次

递归应该分为两个阶段

1、回溯:一层一层往下调用

2、递推:一层一层向上推出结果

一段代码循环运行的方式,可以用while for循环,另一种方式就是递归,递归的本质就是循环

 while True:
     print(1111)
     print(2222)
     print(3333)
#  方式二:递归的本质就是循环:
def f1():
	print(1111)
  print(2222)
	print(3333)
     f1()
f1()

2、需要强调的一点是:

递归调用不应该无限的调用下去,必须在满足某种条件下结束递归调用

n = 0
while n < 0:
  print(n)
  n+=1
  
def f1(n):
  if n == 0
  	return  # 相当于满足条件结束代码运行
  print(n)
  n+1=1
  f1(n)
  
f1(0)

3、递归的两个阶段

回溯:一层一层调用下去

递推:满足某种结束条件,结束递归调用,然后一层一层返回

age(5) = age(4) + 10
age(4) = age(3) + 10
age(3) = age(2) + 10
age(2) = age(1) + 10
age(1) = 18

def age(n):
    if n == 1:
        return 18
    return age(n-1) + 10


res=age(5)
print(res)

递归应用

# 将下列列表每个值取出来
l = [11, [22, [33, [44, [55, [66, [77, [88, [99]]]]]]]]]
# 如果没有递归函数,我们就需要for遍历然后判断它是不是列表,不是列表打印出来,是列表就继续遍历

def func(l):
  for item in l:
    if type(item) is list:
      func(item)
    else:
      print(item)
# 当我们需要不停的使用一个逻辑循环时,我们就应该反应过来使用递归函数

递归实现二分法

nums = [3, 7, 9, 13, 21, 33, 57, 63, 78, 99]



def search(nums,find_num):
    print(nums)
    if len(nums) == 0:
        print('not exists')
        return
    mid = len(nums) // 2
    if find_num > nums[mid]:
        # 找右半部分
        search(nums[mid+1:],find_num)

    elif find_num < nums[mid]:
        # 找左半部分
        search(nums[:mid],find_num)
    else:
        print('find it')


search(nums,63)

三元表达式

三元表达式是一种符合逻辑且更简洁的语法格式

# 针对以下需求
def func(x,y)
	if x > y:
    return x
  else:
    return y
  
res = func(1,2)
print(res)

三元表达式

语法格式:条件成立时要返回的值 if 条件 else 条件不成立时要返回的值

x = 111
y = 222
res = x if x > y else y
print(res)

当然只有两个条件情况时可以用三元表达式,多于两种情况就不合适了

生成式

1、列表生成式

# 没有列表生成式之前我们需要造一个列表
l = []
for i in range:
  if i > 3:
    l.append(i)
    
# 我们可以这么做
l = [i for i in range(10) if i > 3]
print(l)

# 将下面列表中名字带_wx的名字组成一个新列表
names = ['jesse','shiki_wx','yuki_wx','kafka_wx']
wx_names = [name for name in names if name.endswith('_wx')]
print(wx_names)

2、字典生成式

dir = 'k%s' %i:i for i in range(3)
print(dir)

3、集合生成式

print({i for i in range(3)})

4、生成器表达式

res = (i for i in range(5))
print(res)  # 此时res是一个生成器
print(next(res))
print(next(res))
with open('a.txt', mode='rt', encoding='utf-8') as f:
    # res = f.read()
    # print(len(res))  # 23个字符

    # res = 0
    # for line in f:
    #     res += len(line)

    # res = sum((len(line) for line in f))
    res = sum(len(line) for line in f)
    print(res)
上一篇:Python系列 36 迭代器


下一篇:pytorch从零搭建神经网络实现多分类(Fashion-Mnist)