第 10 节 函数的基础3

函数

1. 生成式

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

#需求:生成一个1~10的整数列表
list1 = list(range(1,11))
print(list1)  #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

#需求:生成列表:[1*1, 2*2, 3*3, 4*4, 5*5, 6*6, 7*7, 8*8, 9*9, 10*10]
#列表生成式:[]
#写下面的列表生成式的时候,需要生成的元素x*x放到最前面,后面跟的就是for-in循环
list3 = [x * x for x in range(1,11)]
print(list3)

#生成式公式:[exp for iter_var in iterable]  其中exp是个表达式,会用到循环变量iter_var,每循环一次就会执行一次exp,生成一个元素,添加到列表.等价:
'''
l = []
for iter_var in iterable:
     l.append(exp)
'''

#升级需求:生成偶数的平方的列表
list4 = [x * x for x in range(1,11) if x % 2 == 0]
print(list4)

#可以在列表生成式中使用两层循环
suit = ['♥','♦','♣','♠']
face = ['A','2','3','4','5','6','7','8','9','10','J','Q','K']
poke = [(x,y) for x in suit for y in face]

#字典生成式
#列表生成式可以使用两个变量,实现字典的键值交换
d = {"X":"A","Y":"B","Z":"C"}
list5 = {v:k for k,v in d.items()}
print(list5)

#集合生成式
print({x for x in range(10)})

#练习:
1.将一个列表中所有的字符串变成小写
  l = ["Hello","World","IBM","Apple"]
如果是这样的列表呢
  l =  ["Hello","World",10,"IBM","Apple"]

2.生成器

如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

  • 延迟计算、惰性求值
  • 节省内存,高效

生成器(Generator) 生成器会产生一个对象,而不是一个列表

2.1 yield表达式

#通过函数和yield关键字生成
#使用了 yield 的函数被称为生成器(generator)
#yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行
 def test(n):
  for i in range(1,n + 1):
      yield i
      #print(i)
#得到生成器
 result = test(10)
 print(result)
 
 #生成器只能遍历一次, 所以下面不会有任何输出
 for x in result:
      print(x)
      
#可以这样遍历
for x in test(10):
     print(x)
#一般不通过这种方式遍历 
print(next(result))  

2.2生成器表达式

生成器【Generator】生成器会产生一个可迭代对象,而不是一个列表。生成器表达式很类似列表生成式:

(表达式 for var in 可迭代对象)

#将列表生成式中的[]替换成()
ge = (x for x in range(1,6))
print(ge,type(ge))

#生成器需要通过next()方法获取数据,调用一次则返回一个数据
print(next(ge))
print(next(ge))
print(next(ge))
print(next(ge))
print(next(ge))

#注意:如果通过next函数获取生成器中的数据,当数据取完之后,
#将不能再调用next函数,否则出现StopIteration
#print(next(ge))  #StopIteration

#生成器主要通过for-in的方式进行遍历
for x in ge:
    print(x,end=' ')

3.迭代器

在这里插入图片描述

3.1 迭代对象

可以直接作用于for-in循环的数据类型都被称为可迭代对象(Iterable),可以使用isinstance()判断一个对象是否是可迭代对象,可以直接作用于for-in循环的数据类型:

  • 数据结构:list、set、tuple、dict、string
  • generator【生成器】【(),函数结合yield】
#引入 from collection  import Iterable
from collections import Iterable
print(isinstance("",Iterable))#True
print(isinstance({},Iterable))#True
print(isinstance((),Iterable))#True
print(isinstance(1,Iterable))#False

3.2 迭代器

迭代器不但可以作用于for-in循环,还可以使用next()函数将其中的元素获取出来,当获取完最后一个元素之后,当再次调用next方法,则会出现StopIteration错误,表示无法继续返回一个值。可以使用isinstance()判断一个对象是否是迭代器。迭代器的类型是Iterator

from collections import  Iterator,Iterable
print(isinstance([],Iterator))  #False
print(isinstance((),Iterator))  #False
print(isinstance({},Iterator))  #False
print(isinstance("",Iterator))  #False
print(isinstance((x for x in range(0,6)),Iterator))  #True 生成器是迭代器
print(isinstance((x for x in range(0,6)),Iterable)) #True 生成器也是迭代对象

结论:list、set、tuple、dict、string是可迭代对象,但是,不是迭代器,只有生成器才是迭代器

3.3 将迭代对象转换为迭代器

迭代器一定是可迭代对象,但是,可迭代对象不一定是迭代器

iter():将可迭代对象转化为迭代器【主要针对list、set、tuple、dict、string】

print(isinstance(iter([]),Iterator)) #True
print(isinstance(iter(()),Iterator)) #True
print(isinstance(iter({}),Iterator)) #True
print(isinstance(iter(""),Iterator)) #True

l2 = iter(l1)  #将列表转换为迭代器
print(next(l2))  #使用next获取迭代器中的元素

while True:
    try:
        print(next(l2))  #可能出问题的代码放到try块中
    except StopIteration: #捕获异常
        break  #终止循环

4 装饰器(重点,难点)

软件开发中有一条非常重要的规则就是:对修改封闭,对扩展开放。
对于一个现有的函数,如果想要增强此函数的功能,但是不允许修改此函数源代码的时候,使用装饰器来解决这个问题

  • 本质:就是一个闭包,还是一个返回函数的高阶函数

  • 好处:就是在不用修改原函数代码的前提下给函数增加新的功能

###4.1 装饰器写法

#被修饰的函数
def say_hello(name):
	print('我就是人见人爱,花见花开的%s'%name)
	
# 参数是被修饰函数
def wrapper(func):     #1.定义装饰器
    def inner(name):   #2.定义闭包 在闭包中增加功能
        print('-' * 50)
        func(name)     #3.调用原函数实现原来的功能
        print('*' * 50)
    return inner       #4.返回增强功能的函数

say_hello = wrapper(say_hello) #5.获取增强功能的函数
say_hello('风流小王子')         #6. 调用增强函数,实现功能

###4.2使用@语法糖将装饰器应用到指定函数上,简化使用

#用法:在需要被装饰的函数前面加上:  @装饰器的名字  【外层函数的名字】
def wrapper(func):
  def inner(age1):
      #增加的功能
      if age1 < 0:
          age1 = 0
      #调用原函数
      func(age1)
  return inner
  
@wrapper     #相当于 getAge = wrapper(getage)
def getAge(age):
	print(age)
getAge(18)  #调用增强的函数
注意:使用@的时候,如果装饰器和需要被装饰的函数在同一个.py文件中的时候,装饰器一定要出现在被装饰函数的前面【Python中的代码是从上往下依次执行的】

4.3 带有不定长参数的装饰器

同一个装饰器可以应用于多个函数

def wrapper(func):       
  def inner(*tup,**kw):  #变长参数
      func(*tup,**kw)  
      print('-'*50)    
  return inner    
  
@wrapper                 
def test1(a,b):    
	print(a,b)  
test1(1,2)       

@wrapper                 
def test1(a):        
      print(a)   

4.4 多个装饰器作用在一个函数上(不重要)

#多个装饰器同时作用于一个函数的时候,要注意一下装饰器执行顺序
	def wrapper1(func):
	  print("wrapper1~~~~外部函数")
	  def inner(a,b):
	      print('wrapper1-----内部函数')
	      func(a,b)
	  return inner
	
	def wrapper2(func):
	 	print("wrapper2~~~~外部函数")
	    def inner(a, b):
	        print("wrapper2~~~~内部函数")
	        func(a, b)
	    return inner
	    
	@wrapper1
	@wrapper2
	def text(num1,num2):
		print(num1 + num2)	
		
	text(10,20)

5.递归函数

###5.1 嵌套调用

在函数A中可以调用函数B,在函数B中可以调用函数C,这种调用方式称为函数的嵌套调用。

5.2 递归调用

一个函数直接或间接的调用自己则称为递归调用。

def fac(n):
      if n ==0:  #递归终止条件,如果n为0,则结束递归调用,返回
          return 1
      else:
          tmp = fac(n-1)  #调用自己计算n-1的阶乘
          return n * tmp #返回n * (n-1)!
    print(factorial(5))  #120

5.3 递归调用过程

递归调用可分解为两个过程,正向递归调用和逆向递归返回。

在这里插入图片描述

5.4 递归适用条件

如果一个问题规模缩减后,求解方式和原来一样,小规模问题解决后导致问题的最终解决,则可适用递归

  • 形式是递归的 阶乘和斐波那契数列
  • 结构是递归的 列表遍历
  • 解法是递归的 汉诺塔

递归的写法:

  • 一个递归程序必须包含两部分:
    • 1) 递归终止条件
    • 2) 递归调用自己
def  recurve(*args,**kw):	
      if 递归终止条件:   #递归终止条件必须在递归调用前
          # to do 
       else:
          #to do
          recurve(参数)
          #to do

6 栈和队列

6.1栈

抽象成一个开口向上的容器【羽毛球球筒】

  • 特点:先进后出

stack

#创建一个栈【列表】
my_stack = []

#入栈【向栈中存数据】:append
my_stack.append(23)
print(my_stack)
my_stack.append(30)
print(my_stack)
my_stack.append(4)
print(my_stack)
my_stack.append(11)
print(my_stack)
my_stack.append(20)
print(my_stack)

#出栈【从栈中取数据】:pop
#pop每调用一次,则取出一个数据,先添加进去的最后被取出来【先进后出】
my_stack.pop()
print(my_stack)
my_stack.pop()
print(my_stack)
my_stack.pop()
print(my_stack)
my_stack.pop()
print(my_stack)
my_stack.pop()
print(my_stack)

6.2 队列

queue

抽象成一个水平放置的水管

特点:先进先出

import  collections

#创建队列
queue = collections.deque([12,43,8,10])
print(queue)


#入队【存数据】,append
queue.append(66)
print(queue)
queue.append(77)
print(queue)
#deque([12, 43, 8, 10, 66, 77])

#出队【取数据】,popleft
queue.popleft()
print(queue)
queue.popleft()
print(queue)
queue.popleft()
print(queue)

课后练习:

#队列:先进先出

import collections

queue = collections.deque([10,20,30])

#出队

print(queue.popleft())
print(queue.popleft())
print(queue.popleft())

#入队

queue.append(40)
queue.append(50)
queue.append(60)

#约瑟夫环

def josephus(m,n):
    queue = collections.deque([x for x in range(1,42)])
    while len(queue) != 2:
        for x in range(1,n):
            queue.append(queue.popleft()) #左边出队,右边入队
        queue.popleft()  #直接出队
    return queue

que = josephus(41,3)
print(que.popleft(),que.popleft())
  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值