生成器、装饰器和异常处理

生成器

可迭代对象

在此之前我们先来了解一个概念,什么是可迭代对象,可迭代对象是非常重要的,它意味着你可以正常使用for循环来实现循环遍历。在Python中,可迭代对象(iterable)是一个可以一次返回其所有元素的对象。这意味着你可以使用for循环遍历这个对象,或者使用内置的iter()函数获取它的迭代器。

Python中的许多内建类型都是可迭代的,例如:

  • 序列类型:如列表(list)、元组(tuple)、字符串(str)等。
  • 集合类型:如集合(set)、冻结集合(frozenset)等。
  • 字典类型(dict)。

可迭代对象相对于普通的对象多了一个__iter__的特殊方法

此外,用户自定义的对象也可以是可迭代的,只要它们实现了迭代协议。这个协议通常包括一个__iter__方法,该方法返回一个迭代器对象。迭代器对象需要实现两个方法:next__和__iter

我们可以通过一个dir()函数来查看自己定义的对象是不是可迭代的

a = 1
li = [1, 2, 3, 4, 5]
print(dir(a))
print(dir(li))

结果太长,我就不展示了,不过我们要知道dir函数就是查看定义对象里面的方法的,一般来说可迭代对象里面有一个__iter__的特殊方法

Python中的几种遍历

在Python中,遍历(Iteration)是一种处理集合元素的方式。

遍历我们可以理解为一遍遍的拿取,也就是说可迭代对象里面的内容,我们是一次一次的拿取的,而不是一次性的拿完,一次只拿取一个也就是单条内容。

for循环遍历对象

a = 1
li = [1, 2, 3, 4, 5]
for i in a:
    print(i)

for i in li:
    print(i)

不是可迭代对象的我们在打印的时候会报错,这里很明显a不是可迭代对象,因为a=1是一个整形,整形是不可迭代,li显然就是一个列表了,列表是可迭代的,它会遍历列表里面的每一个内容。

使用enumerate()函数遍历

如果你想同时获取元素的索引和值,可以使用enumerate()函数:

my_list = ['a', 'b', 'c', 'd']
for index, element in enumerate(my_list):
    print(index, element)  # 输出:0 a 1 b 2 c 3 d

使用zip()函数遍历多个序列

如果你有多个序列,并希望同时遍历它们,可以使用zip()函数:

list1 = [1, 2, 3]  
list2 = ['a', 'b', 'c']  
for element1, element2 in zip(list1, list2):  
    print(element1, element2)  # 输出:1 a 2 b 3 c

这是三个相对来说比较常见的遍历了,这其中for循环遍历是最常见的,zip遍历爬虫可能会用到

迭代器

迭代器(Iterator)是Python中的一个非常有用的概念,它允许我们遍历一个集合的所有元素而不需要知道集合的底层表示方法。迭代器从集合的第一个元素开始访问,直到所有的元素被访问完结束。

迭代器只能往前不会后退,它从集合的第一个元素开始访问,直到所有的元素被访问完结束。

迭代器只能往前不会后退,当你试图往回遍历时,只能重新开始或者抛出异常。

在Python中,你可以通过内置的iter()函数来获取一个对象的迭代器。例如,对于一个列表,你可以使用iter()函数来获取一个迭代器:

li = [1, 2, 3, 4, 5]
it_li = iter(li)

然后,你可以使用next()函数来逐个访问迭代器中的元素:

li = [1, 2, 3, 4, 5]
it_li = iter(li)
print(next(it_li))  #输出1
print(next(it_li))  #输出2

你也可以使用for循环来遍历迭代器中的元素:

for i in it_li:
    print(i)  # 输出:1 2 3 4 5

注意,当迭代器中没有更多元素时,next()函数会引发StopIteration异常。因此,在实际应用中,我们通常会在try/except语句块中调用next()函数来处理这个异常。

生成器

生成器(Generator)是一种特殊的迭代器,它允许你遍历一个序列,而不需要一次性加载所有元素。生成器在每次迭代时只生成一个元素,而不是一次性生成所有元素。这使得生成器非常适合处理大数据集,因为它可以节省内存空间。

在Python中,你可以使用yield关键字来定义一个生成器函数。下面是一个简单的例子:

def my_generator():
    for i in range(5):
        yield i

for i in my_generator():
    print(i)

输出

0
1
2
3
4

在这个例子中,my_generator是一个生成器函数,它使用yield关键字来返回每个数字。当我们调用my_generator()时,它返回一个生成器对象。然后,我们可以使用for循环来遍历这个生成器对象,每次迭代都会从生成器中获取下一个元素。

在这里我帮大家区分一下return和yield的作用,其实它们两个的作用是相似的,都是返回值,区别在于函数碰到return会停止运行然后返回值,最后终止运行。但函数如果碰到yield函数则会暂时的暂停一下,直到下一个next方法调用出现继续返回值

斐波那契数列

生成器有一个著名的小游戏,叫斐波那契数列,不知道大家知道不知道,我们可以用生成器把斐波那契数列写出来

其数值为:1、1、2、3、5、8、13、21、34……在数学上,这一数列以如下递推的方法定义:F(0)=1,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。

下面我用生成器给大家写出来供大家参考:

def fbnq(end):
    a, b, c = 0, 0, 1
    while a < end:
        b, c = c, b+c
        yield b
        a = a+1
x= fbnq(8)
print(next(x))
print(next(x))
print(next(x))
print(next(x))
print(next(x))
print(next(x))
print(next(x))
print(next(x))

斐波那契数列就是前两个数字之和等于第三个,然后依次递推,这里面我只打印了八个数字,想打印更多的话把参数改一下就好。

装饰器

在Python中,装饰器(Decorator)是一个特殊类型的函数,用于修改其他函数的行为或增强功能。它是一种高级Python语法,用于在不修改函数源代码的情况下向函数添加额外的功能。

装饰器通常以被装饰的函数作为参数,并返回一个新的函数。它可以用来实现各种功能,例如日志记录、缓存、权限验证等。

在这呢我给大家说一个要注意的事项,装饰器必须是一个闭包函数,闭包函数我在写函数那一篇文章的时候已经说过了,在这里呢我就在说一次,闭包函数有两点要注意:

1、它必须是一个嵌套函数

2、内部函数作为外部函数的返回值

大家只要记住这两点就好了

装饰器的底层逻辑

我呢先给大家讲一下闭包函数的底层逻辑:

def cut():
    print("杜甫也是一位伟大的诗人")

def deserve(off):#定义处的参数称为形参,off为形参
    print("回头看,轻舟已过万重山")
    def poet():
        print("李白是一位伟大的诗人")
        off()
    return poet
xl=deserve(cut)
xl()

从代码中我们可以看到deserve函数是一个闭包函数,可以把这个闭包函数当做装饰器,而cut函数就是这个装饰器的参数并返回了cut函数里面的内容,打印的结果为

回头看,轻舟已过万重山
李白是一位伟大的诗人
杜甫也是一位伟大的诗人

自定义装饰器

装饰器的底层逻辑理解了那么这个自定义装饰器就更好理解了

def deserve(off):
    print("回头看,轻舟已过万重山")
    # off()
    def poet():
        print("李白是一位伟大的诗人")
        off()
    return poet
@deserve
def cut():
    print("杜甫也是一位伟大的诗人")
cut()

这个就是自定义装饰器,和刚刚那个装饰器的底层逻辑其实差别不大,只是装饰器多了个'@'符号而已,这个符号是装饰器的标志,而cut就是被装饰的函数,被当做是装饰器的参数传进去,并返回一个新的函数,在装饰器里面就是被认为是一个新的函数,毕竟装饰器里面本来是没写cut函数的

带参数的装饰器

def deserve(off):
    print("回头看,轻舟已过万重山")
    def poet(*args,**kwargs):
        print("李白是一位伟大的诗人")
        off(*args, **kwargs)
    return poet
@deserve
def sum(a, b):
    print(a+b)
sum(3,4)

要注意,如果原函数也就是sum函数里面有参数,那么装饰器里面接受参数的函数里面也要有参数

带有返回值的装饰器

要注意,如果原函数也就是sum函数里面有参数,那么装饰器里面接受参数的函数里面也要有参数
带有返回值的装饰器

这里sum函数里面有返回值,那么装饰器里面也要有返回值,如果没有返回值,则会打印None,函数sum里面的内容就不会被返回出来。

内置装饰器

@property

这个装饰器最大的特点就是对属性的访问和修改更加方便和直观。

class Person():
    def __init__(self, name, age):
        self.name = name
        self.age = age
    @property
    def sun(self):
        print(f"{self.name}很潇洒")

可以把这个装饰器简单的理解为像调用属性一样调用方法,不需要括号

@classmethod

将一个函数标记为类方法,使其与类而不是实例关联。类方法需要访问和修改类状态,第一个参数总是表示类本身。

class Person():
    @classmethod
    def run(cls):
        print("This is a class method.")
xl=Person()
xl.run()
@staticmethod

将一个函数标记为静态方法,使其与类而不是实例关联。静态方法不需要访问或修改实例状态,可以直接通过类名调用。

class Person():
    @staticmethod
    def cun():
        print("要睡觉")
Person().cun()

正常情况下是不能直接一类名调用函数方法的,要用一个变量来接收类名

异常和异常处理

我们都知道在程序运行中报错是很致命的,也避免不了出现报错,一旦出现报错那么程序就会瘫痪,为了解决程序报错还能让程序继续巡行才有了异常处理,使其在程序报错时还能正常运行

其基本语法:

try:
    a = 1
    for i in a:
        print(i)
except:
    print('这是一个报错')

这是异常处理的基本固定的格式,except后面还能跟报错的具体语法:

try:
    a = 1
    for i in a:
        print(i)
except TypeError:
    print('这是一个报错')

我们还可以根据此语法去查看错误:

try:
    a = int(input("请输入一个数字:"))
except Exception as e:
    print("输入有误", e)
else:
    print("正常")

如果出现报错,则会打印具体报错的语法,不报错就正常运行

finally

finally不管报不报错都会执行的语句:

try:
    a = int(input("请输入一个数字:"))
except Exception as e:
    print("输入有误", e)
else:
    print("正常")
finally:
    print("继续执行")

raise主动抛出异常

还可以主动抛出异常:

try:
    a = 1
    for i in a:
        print(i)
except TypeError:
    raise TypeError('主动抛出异常')
else:
    pass
finally:
    pass

这里有几点语法规则大家要注意:

1、try后面必须跟上except

2、except只有在函数中才能使用return

3、finally不管是否发生异常都会执行

4、raise可以主动抛出异常

看了这么久了,点个赞吧,内容较多,要慢慢消化,制作不易,点个关注再走吧!

  • 35
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值