列表生成式+迭代器+闭包+变量的作用域+装饰器

一、列表生成式和生成器

列表生成式和生成器都属于可迭代对象

列表生成式:生成一个列表,区别列表生成器range,需要进行转换list(range(start,end,step))

生成器:generator

1.列表生成式

List Comprehensitons,是Python内置的用来创建列表的工具

语法:[元素 for循环 条件判断]

代码演示:

#语法:[新列表的元素规律   for循环   条件判断],条件判断根据具体的需求可以省略

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

#2.需求:生成一个列表list2 = [1,4,9,16,25,36,49...81]
#方式一:通过追加自己实现
newList1 = []
for x in range(1,10):
    newList1.append(x ** 2)
print(newList1)
#方式二:列表生成式
newList2 = [i ** 2  for i in range(1,10)]
print(newList2)
#[1, 4, 9, 16, 25, 36, 49, 64, 81]

#3.加上条件判断
newList3 = [i ** 2  for i in range(1,10) if i % 2 == 0]
print(newList3)


#4.需求:生成一个列表,其中的元素是1~20之间的偶数
newList4 = [i for i in range(1,21) if i % 2 == 0]
print(newList4)

#5.可以使用嵌套循环,生成一个全排列
"""
1,2,3,4   从中取出3个进行排列
123
321
213
231
234
342
432
。。。
"""
list2 = [m + n for m in "ABC" for n in "XYZ"]
print(list2)  #['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
"""
for m in "ABC"
    for n in "XYZ"
        print(m + n)
AX  AY AZ   BX BY BZ   CX CY CZ
"""

#6.for循环可以同时遍历两个数据
d = {"A":"x","B":"y","C":"z"}
for k,v in d.items():
    print(k,"=",v)

list3 = [k + "=" + v for k,v in d.items()]
print(list3)#['A=x', 'B=y', 'C=z']


#练习:使用列表生成式将下面列表中的所有单词改为小写
l = ["hello","IBM","abc","Good"]
#方式一
newList1 = []
for word in l:
    newList1.append(word.lower())

print(newList1)
#方式二
newList2 = [word.lower() for word in l]
print(newList2)

l = ["hello","IBM",18,"abc","Good"]
#存在的问题:int没有lower,没有isalpha,所以如果列表中存在整型,则无法进行转换
#newList3 = [word.lower() for word in l if word.isalpha()]
#print(newList3)

#isinstance():判断一个变量是否是某种指定的数据类型
num = 10
print(isinstance(num,int))
s = "hello"
print(isinstance(s,str))

#解决方案:在转换之前,先进行判断,判断元素是否是字符串
newList3 = [word.lower() for word in l if isinstance(word,str)]
print(newList3)

"""
总结:
[元素的规律   for循环  if判断]
执行顺序:第一步:for循环    第二步:if判断   第三步:元素的规律
注意:if'判断只能判断for循环遍历出来的元素
"""
2.生成器

生成器:生成具有一定内容的容器【generator】

作用:为了解决快速的生成一批数据,会占用大量的内存的问题,引入了生成器的机制,用来生成指定一批数据的算法,当需要使用数据的时候,生成器直接生成

定义生成器的方式

方式一:将列表生成式中的[]改成()

方式二:通过函数和关键字yield生成

代码演示:

#1.
ge1 = [x for x in range(1,10)]   #列表生成式,list
print(type(ge1))

ge2 = (x for x in range(1,10))   #生成器,generator
print(type(ge2))


#2.生成器本质上还是一个容器,其中可以存储多个数据
#特殊:除了可以使用for遍历之外,还可以使用next()遍历
print(ge2)
"""
print(next(ge2))
print(next(ge2))
print(next(ge2))
"""

#补充:如果一个for循环只是为了控制循环的次数,则其中的变量可以用下划线代替
for _ in range(0,9):
    print(next(ge2))

#注意:如果一个生成器中的元素通过next全部遍历完成之后,再次调用next,则会报错StopIteration
#print(next(ge2))  #StopIteration  停止迭代

"""

1

2

3
4
5
6
7
8
9

"""

#注意:区别于list等的遍历【list等的遍历每次都是从头开始遍历,但是,生成器只要遍历一次,下一次遍历则没有结果】
for num in ge2:
    print(num)

print("****************")

#2.通过函数和yield
def test(n):
    for i in range(1,n + 1):
        print("111",i)
        yield  i    #暂停
        print("222",i)

r = test(10)
print(r)  #<generator object test at 0x000001870CA59200>

"""
for x in r:
    print("~~~~",x)
"""
print(next(r))

print(next(r))
print(next(r))

"""
111 1
1

222 1
111 2
2

222 2
111 3
3
"""

#工作原理:函数生成器执行到yield的时候会暂停,会将yield后面的值返回,并将yield前后的代码屏蔽
#当遍历生成器的时候,才会再去执行被屏蔽掉的代码

二、可迭代对象和迭代器

1.可迭代对象

可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以直接作用于for循环的数据类型有:

​ a.一类是集合数据类型:包括list,tuple,dict,set,string

​ b.一类是生成器generator【包括()和yield】

通过isinstance()判断一个对象是否是可迭代对象

代码演示:

#第一步:导入模块
from collections import  Iterable

print(isinstance([],Iterable))
print(isinstance((),Iterable))
print(isinstance({},Iterable))
print(isinstance("hello",Iterable))
print(isinstance((x for x in range(1,9)),Iterable))

print(isinstance(10,Iterable))
print(isinstance(True,Iterable))
2.迭代器

不但可以直接作用于for循环,还可以使用next()获取元素值,被称为迭代器:Iterator

通过isinstance()判断一个对象是否是迭代器

代码演示:


from collections import Iterator

print(isinstance([],Iterator))
print(isinstance((),Iterator))
print(isinstance({},Iterator))
print(isinstance("hello",Iterator))
print(isinstance((x for x in range(1,9)),Iterator))


print(isinstance(10,Iterator))
print(isinstance(True,Iterator))

#不能使用next遍历,但是可以使用for遍历的数据类型就是可迭代对象【注意:生成器可以使用for或者next遍历】
#迭代器一定是可迭代对象,但是,可迭代对象不一定是迭代器

print("*********")

#虽然;list,tuple,dict以及string都不是迭代器,可以通过iter()将其转换为迭代器
print(isinstance(iter([]),Iterator))
print(isinstance(iter(()),Iterator))
print(isinstance(iter({}),Iterator))
print(isinstance(iter("abc"),Iterator))

#区分可迭代对象和迭代器


#补充:迭代器的遍历
ge = (x for x in range(34,100))
"""
for num in ge:
    print(num)
"""

#工作原理:使用next遍历,当所有的元素遍历完成,则报错StopIteration,作为条件
while True:
    try:
        #监控区:查看其中的代码有没有异常,如果有异常,则代码跳到except分支中执行
        num = next(ge)
        print(num)
    except StopIteration:
        break

三、闭包

如果在一个函数的内部再定义一个新的函数,外部的函数被称为外部函数,里面函数被称为内部函数

语法:

def 外部函数函数名(参数):

​ 函数体1

​ def 内部函数函数名(参数:

​ 函数体2

​ return 内部函数的函数名

说明:如果一个外部函数中定义了一个内部函数,并且外部函数的返回值是内部函数的引用,这样就构成了闭包

代码演示:


四、变量的作用域

1.概述

变量的作用域:指的是一个变量可以被访问的范围

注意:程序中的变量并不是在任意位置可以任意访问,访问权限取决于该变量被定义的位置

2.使用
2.1作用范围划分

分类:

​ L:Local,局部作用域

​ E:Enclosing,函数作用域【外部函数和内部函数之间】

​ G:Global,全局作用域

​ B:Built-in,内置作用域或者內建作用域

2.2查找规则

前提:当代码中的变量重名的情况下,按照L---->E----->G----->B方式查找

代码演示:

#变量的作用域
#1.如果变量不重名的情况下
#在内部函数中可以任意访问,主要是通过变量名进行匹配
#全局作用域
num1 = 10

def outter1():
    #函数作用域
    num2 = 20
    def inner1():
        #局部作用域
        num3 = 30
        print(num1,num2,num3)

    return inner1

f1 = outter1()
f1()

#2.如果变量重名的情况下
#在内部函数中访问变量,优先访问内部函数中的变量,其次是函数作用域的变量,最后才是全局作用域的变量
num = 10
def outter2():
    #num = 20
    def inner2():
        #num = 30
        #就近原则
        print(num)

    return  inner2

f2 = outter2()
f2()

print("*********")

#3.
#3.1
def func():
    n1 = 10

func()
#print(n1)

#3.2
if True:
    n2 = 20

print(n2)

#3.3
for i in range(1,5):
    n3 = 40
print(n3)
#不建议直接访问变量i
print(i)


#3.4
n = 0
while n < 1:
    n4 = 25
    n += 1
print(n4)

"""
结论:
1.在Python中,只有模块【module】,类【class】,函数【function】会引入新的作用域
2.一些普通的语句,比如if,while,for,try-excpet都不会引入新的作用域【在语句其中定义的变量,在外面仍然可以访问】
"""
2.3全局变量和局部变量

全局变量:定义在函数外面的变量【拥有全局的作用域】

局部变量:定义在函数内部的变量【只能在函数内部使用】

生命周期:全局变量大于局部变量

代码演示:

#1.不重名
total = 0  #全局变量

def func():
    num = 10  #局部变量

    print("~~~",num,total)

func()

print("outter",total)


#2.重名
n = 23

def show():
    #print(n)  #unboundLocalError: local variable 'n' referenced before assignment

    n = 40

    print(n)

show()
print("outer",n)
2.4global和nonlocal关键字的用法

global:全局

#当全局变量和局部变量重名,在函数的内部,在局部变量定义之前使用全局变量,统统都需要声明
num = 1
def fun1():
    #使用global向编译器做一个声明,告诉编译器:此处需要访问的就是全局变量
    global  num
    print(num)
    num = 123
    print(num)

fun1()

#练习:
#全局变量
a = 10
def test():
    global  a
    #局部变量
    a = a + 1
    print(a)

test()

nonlocal:不是局部的

#前提:nonlocal定义在闭包中【函数作用域】
#nonlocal:将一个变量的局部作用域扩大到函数作用域,在整个外部函数中被可以被访问
x = 0   #全局作用域

def outer():
    x = 1  #函数作用域

    def inner():
        nonlocal x
        x = 2  #局部作用域
        print("inner:",x)

    #调用函数
    inner()

    print("outer:",x)


outer()
print("gloabl:",x)
"""
inner: 2
outer: 1   ---->2
gloabl: 0
"""

五、装饰器

def now():
	print("hello")
    
#思考问题:在不修改原函数的基础上,给原函数增加新的功能  
#解决方案:装饰器

装饰器【Decorator】,如果要增强某个函数的功能,但是不能修改原函数,这种在代码运行期间给函数动态添加功能的操作机制被称为装饰器

本质:就是一个闭包,将一个函数作为外部函数的参数,返回一个函数

应用场景:1.统计函数执行时间, 2.执行函数结束之后的清理行为 3.权限校验,4.缓存 5.面向对象

使用最多的是直接使用系统的装饰器

代码演示:

#1.简单的装饰器
def test():
    print("hello")

#装饰器的书写语法
#a.书写闭包
#b.给外部函数设置参数,实参需要传一个函数【需要被增加功能的函数】
def outer1(func):
    def inner1():
        #注意:先调用原函数还是先增加新功能,都行
        #c.调用需要被增强功能的函数
        func()
        #d.增加新的功能
        print("abx")

    return  inner1

f = outer1(test)  #func = test
f()

"""
outer被称为装饰器
新增加的功能可以写在原函数调用的前面或者后面
"""

#需求:增加九九乘法表
def show(n):
    for i in range(n):
        print(i)

def outer2(func):
    def inner2():
        #新增的功能
        for i in range(1,10):
            for j in range(1,i + 1):
                print("%dx%d=%d" % (j,i,i * j),end=" ")
            print("")
        #调用原函数
        func(10)

    return inner2

f2 = outer2(show)
f2()



print("******************************************")

#2.有参数的装饰器
def getAge(age):
    print(age)

"""
getAge(10)
getAge(-38)
"""

#需求:在不修改原函数的基础上,进行数据的过滤【检验】
#当输入的age为负数时,将其改为正数
def wrapper(func):
    def inner(num):
        #增加新的功能:过滤负数
        if num < 0:
            num = abs(num)

        #调用原函数
        func(num)

    return inner

f1 = wrapper(getAge)
f1(10)
f1(-20)

#注意:如果原函数有参数,需要在装饰器的内部操作参数,则需要给inner设置参数

print("******************************************")

#3.简化装饰器:使用  @  将装饰器直接应用到需要被增强功能的函数上
#语法:@装饰器的名字
def wrapper1(func):
    def inner():
        print("hfaj")
        func()

    return  inner
@wrapper1
def test():
    print("hello")

test()

#使用@之后,则直接调用原函数,就可以使用装饰器
#注意:使用@之后,装饰器必须出现在原函数出现之前

print("******************************************")

#4.带有不定长参数的装饰器
#如果要给多个函数增强同一个功能,给inner设置不定长参数
def wrapper2(func):
    def inner(*args,**kargs):
        print("hello")
        func(*args,**kargs)

    return  inner

@wrapper2
def show1(num1):
    print(num1)
show1(10)

@wrapper2
def show2(num1,num2,num3):
    print(num1,num3,num2)
show2(10,3,54)


print("******************************************")

#5.特殊情况:多个装饰器同时作用于同一个函数
def wrapper11(func):
    def inner11():
        print("第一个装饰器")
        func()

    return inner11
def wrapper22(func):
    def inner22():
        print("第二个装饰器")
        func()

    return inner22

@wrapper11
@wrapper22
def check():
    print("num")

check()
#check()

#结论:如果多个装饰器作用于同一个函数,则按照从上往下的顺序执行,但是,不管有多少个装饰器,原函数只会被调用一次
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值