2024-12.python高级语法
异常处理
-
首先我们要理解什么叫做**"异常”**?
- 在程序运行过程中,总会遇到各种各样的问题和错误。
- 有些错误是我们编写代码时自己造成的:
- 比如语法错误、调用错误,甚至逻辑错误。
- 还有一些错误,则是不可预料的错误,但是完全有可能发生的:
- 比如文件不存在、磁盘空间不足、网络堵塞、系统错误等等。
- 这些导致程序在运行过程中出现异常中断和退出的错误,我们统称为异常。大多数的异常都不会被程序处理,而是以错误信息的形式展现出来。
#0不能被作为除数 1/0 异常信息为:ZeroDivisionError: division by zero -
异常的分类:
- 异常有很多种类型,Python内置了几十种常见的异常,无需特别导入,直接就可使用。
- 需要注意的是,所有的异常都是异常类,首字母是大写的!
-
异常的危害:
- 如果程序中一旦出现了异常的语句代码,则该异常就会立即中断程序的运行!
-
因此:
- 为了保证程序的正常运行,提高程序健壮性和可用性。我们应当尽量考虑全面,将可能出现的异常进行处理,而不是留在那里,任由其发生。
-
python处理异常的机制:
-
Python内置了一套try…except…finally(else)…的异常处理机制,来帮助我们进行异常处理。其基本语法是:
-
try:pass except Exception as ex:pass -
机制说明:
-
首先,执行try子句(在关键字try和关键字except之间的语句)
-
如果没有异常发生,忽略except子句,try子句执行后结束。
-
如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的except子句将被执行。
-
try:print("发生异常之前的语句正常执行")print(1/0)print("发生异常之后的语句不会被执行") except ZeroDivisionError as e:print(e)
-
-
如果程序发生的异常不在你的捕获列表中,那么依然会抛出别的异常:
-
# 未捕获到异常,程序直接报错 s1 = 'hello' try:int(s1) except IndexError as ex: # 本例为非法值异常,而你只捕获索引异常print(ex)
-
-
Exception是什么?
- 在Python的异常中,有一个通用异常:
Exception,它可以捕获任意异常。 - 思考:那么既然有这个什么都能管的异常,其他诸如OSError、ZeroDivisionError的异常是不是就可以不需要了?
- 当然不是!很多时候程序只会弹出那么几个异常,没有必要针对所有的异常进行捕获,那样的效率会很低。另外,根据不同的异常种类,制定不同的处理措施,用于准确判断错误类型,存储错误日志,都是非常有必要甚至强制的。
- 常见的异常类型:
异常名 解释 AttributeError 试图访问一个对象没有的属性 IOError 输入/输出异常 ImportError 无法引入模块或包;多是路径问题或名称错误 IndentationError 缩进错误 IndexError 下标索引错误 KeyError 试图访问不存在的键 KeyboardInterrupt Ctrl+C被按下,键盘终止输入 NameError 使用未定义的变量 SyntaxError 语法错误 TypeError 传入对象的类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量 ValueError 传入一个调用者不期望的值,即使值的类型是正确的 OSError 操作系统执行错误 -
异常的基本使用:
-
try:1/0 except Exception as e:print(e) print('我是异常代码后序的操作代码!')
- 在Python的异常中,有一个通用异常:
-
Python的异常机制具有嵌套处理的能力:
-
比如在函数f3()调用f2(),f2()调用f1(),虽然是在f1()出错了,但只需要在f3()进行异常捕获,不需要每一层都捕获异常
-
#函数嵌套出现异常 def f1():return 10/0def f2():f1()def f3():f2()f3() -
函数嵌套处理异常:
-
def f1():return 10/0def f2():f1()def f3():f2()try:f3() except Exception as e:print(e)
-
-
try…excetion的嵌套
-
之前我们说过,不是只使用通用的异常类Exception就万事大吉了,为了效率问题,我们需要对常见的异常信息进行精准的捕获,那么如果异常出现在用户层的话,则就需要对用户操作可能会出现的异常进行判断然后精准捕获了,如何操作呢?
-
如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中。也就是前面说的嵌套处理能力。直到程序最顶端如果还没有被捕获,那么将弹出异常。
-
try:try:print("发生异常之前的语句正常执行")print(1/0)print("发生异常之后的语句不会被执行")except ValueError as e:print(e)except ZeroDivisionError as e:print("里层没有抓好,只能辛苦我外层了") -
或者使用一个try和多个except的形式:
-
try:print("发生异常之前的语句正常执行")print(1/0)print("发生异常之后的语句不会被执行") except NameError as e:print(e) except ZeroDivisionError as e:print("我是第一个抓取到除零异常的") except (ValueError,ZeroDivisionError) as e:print("我是备胎") -
或者在except后面跟一个元组,元组中包含多个异常类
-
-
except (RuntimeError, TypeError, NameError):pass
-
-
finally和else子句
-
try except语法还有一个可选的else子句,如果使用这个子句,那么必须放在所有的except子句之后。这个子句将在try子句没有发生任何异常的时候执行: -
同样的,还有一个可选的finally子句。无论try执行情况和except异常触发情况如何,finally子句都会被执行!
-
当然,else和finally同时存在时:
-
try:pass except:pass else:print("else") finally:print("finally")
-
-
主动抛出异常:raise
-
很多时候,我们需要主动抛出一个异常。Python内置了一个关键字
raise,可以主动触发异常。 -
疑问:
-
为什么要自己主动抛出异常?不嫌多事么?因为有的时候,你需要记录错误信息,然后将异常继续往上层传递,让上层去处理异常,如下:
-
try:divNum = input('enter a divNum:')divNum = int(divNum)try:1/divNumexcept ZeroDivisionError as ex:print("记录异常日志: ", ex)print("但是我自己无法处理,只能继续抛出,看看上层能否处理(甩锅)")raise ValueError('非法录入') except Exception as e:print(e)print('用户录入非法数据,请重新输入!') -
有时候,你需要主动弹出异常,作为警告或特殊处理:
-
#用户录入自己的性别:1表示男,2表示女 sex = int(input("Please input a number: "))try:if sex == 1:print("这是个男人!")elif sex == 0:print("这是个女人!")else:print("好像有什么不符合常理的事情发生了!!")raise ValueError("非法的输入") except ValueError:print("这是个人妖!")
-
-
迭代器
在介绍迭代器之前,先说明下迭代的概念:
-
迭代:
- 通过for循环遍历"对象”的每一个元素的过程。
- 这里的对象指的就是可迭代对象。因此记住:for循环遍历的只能是可迭代的对象。
-
可迭代类型的对象:
- 在Python中,list/tuple/string/dict/set/bytes都是可以迭代的数据类型/可迭代对象!
-
如何判定一个对象是否为可迭代对象呢?
-
可以通过collections模块的Iterable类型作用在isinstance中来判断一个对象是否可迭代
-
from collections import Iterable print(isinstance('abc',Iterable))
-
-
迭代器
-
迭代器是一种可以被遍历的对象,并且能作用于next()函数。
-
性质:
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往后遍历不能回溯,不像列表,你随时可以取后面的数据,也可以返回头取前面的数据。
-
迭代器通常要实现两个基本的方法:
iter()和next()。 -
注意:
- 可迭代对象并不一定是迭代器!
- 常见的数据结构,字符串、列表、元组都属于可迭代对象,并不是迭代器!
-
如何创建一个迭代器呢?
-
字符串,列表或元组对象,甚至自定义对象都可用于创建迭代器:
-
#使用Python内置的iter()方法创建迭代器对象 lis=[1,2,3,4] it = iter(lis) -
可以使用type查看列表和迭代器类型的不同:
-
lis=[1,2,3,4] it = iter(lis) print(type(lis),type(it)) -
使用next()方法获取迭代器的下一个元素:
-
lis=[1,2,3,4] it = iter(lis) print(next(it)) print(next(it)) -
使用for循环遍历迭代器:
-
lis = [1,2,3,4] it = iter(lis) # 创建迭代器对象 for x in it: # 使用for循环遍历迭代对象print (x, end=" ")
-
-
-
思考:迭代器的作用是什么?
- 可迭代对象的优缺点:
- 可迭代对象的优点:可以直观查看里面的对象,如直接查看列表的内容
- 可迭代对象缺点:全部内容要加载至内存中,故占用内存
- 迭代器的优缺点:
- 优点:
- 提供了一种通用不依赖索引的迭代取值方式;
- 节省内存,迭代器在内存中相当于只占一个数据的空间:因为每次取值都上一条数据会在内存释放,加载当前的此条数据。
- 缺点:
- 因为有next方法,即只能往后取值,不能往前,取值不如按照索引的方式灵活,不能取指定的某一个值
- 无法预测迭代器的长度
- 优点:
- 可迭代对象的优缺点:
-
总结:迭代器和可迭代的区别?
-
1.凡是可作用于for循环的对象都是可迭代类型;2.凡是可作用于next()函数的对象都是迭代器类型;3.list、dict、str等是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转换成迭代器。 -
自定义迭代器
-
很多时候,为了让我们自己写的类成为一个迭代器,需要在类里实现
__iter__()和__next__()方法- 实际上,在使用next()函数的时候,调用的就是迭代器对象的
__next__方法 - python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现
__iter__方法,而__iter__方法要返回一个迭代器。- 迭代器自身正是一个迭代器,所以迭代器的
__iter__方法返回自身即可
- 迭代器自身正是一个迭代器,所以迭代器的
- 实际上,在使用next()函数的时候,调用的就是迭代器对象的
-
#迭代生成指定范围数列的平方值 class Squares:def __init__(self, start, stop): # 迭代起始、终止位self.start = startself.stop = stopdef __iter__(self): # 返回自身的迭代器return selfdef __next__(self): # 返回下一个元素if self.start > self.stop: # 结尾时抛出异常raise (StopIteration)item = self.start**2self.start += 1return itemif __name__ == "__main__":for i in Squares(1, 5):print(i, end=" ") -
菲波那切数列实现
-
#菲波那切数列实现 class FbnList():def __init__(self,num):self.num = numself.index = 0 #当前生成了第几位数#初始化前三位值self.num1 = 0self.num2 = 1self.num3 = 1def __iter__(self):return selfdef __next__(self):if self.index >= self.num:raise StopIterationvalue = self.num1self.num1,self.num2,self.num3 = self.num2,self.num3,self.num2+self.num3self.index += 1return value#参数为要生成多少位菲波那切数列的值 fbn = FbnList(100) for i in fbn:print(i,end=' ') -
实现类似iter功能的类:可以使得将列表转换成迭代器
-
class List_A():def __init__(self,alist):self.alist = alistself.index = 0def __iter__(self):return selfdef __next__(self):if self.index < len(self.alist):value = self.alist[self.index]self.index += 1return valueelse:raise StopIterationa = List_A([1,2,3]) print(next(a))
-
推导式
-
Python语言有一种独特的语法,相当于语法糖的存在,可以帮你在某些场合写出比较精简酷炫的代码。但没有它,也不会有太多的影响。Python语言有几种不同类型的推导式
- 列表推导式
- 字典推导式
- 集合推导式
- 元组推导式?
-
列表推导式
-
列表推导式是一种快速生成列表的方式。其形式是用方括号括起来的一段语句,如下例子所示:
-
alist = [x*2 for x in range(1,10)] print(alist) ############上下两组代码是等效 alist = [] for x in range(1,10):alist.append(x*2) print(alist)
-
-
列表推导式要这么理解,首先执行for循环,对于遍历的每一个x,代入x*x表达式中进行运算,将运算结果逐一添加到一个新列表内,循环结束,得到最终列表。它相当于下面的代码:
-
alist = []for x in range(1,10):alist.append(x*2) print(alist)-
作用:
- 列表推导式为我们提供了一种在一行内实现较为复杂逻辑的生成列表的方法。其核心语法是用中括号[]将生成逻辑封装起来。当然列表推导式也有多样用法
-
-
增加条件语句
-
alist = [x * x for x in range(1,11) if x % 2 == 0] print(alist)##############相当于如下代码 alist_1 = [] for x in range(1,11):if x % 2 == 0:alist_1.append(x*x) print(alist_1) -
多重循环
-
re = [a+b for a in '123' for b in 'abc'] print(re)############# alist = [] for a in '123':for b in 'abc':alist.append(a+b) print(alist)
-
-
字典推导式
-
既然使用中括号[]可以编写列表推导式,那么使用大括号呢?你猜对了!使用大括号{}可以制造字典推导式!
-
dic = {x:x**2 for x in [2,4,6]} print(dic)''' dic = {} for x in [2,4,6]:dic[x] = x**2 ''' -
注意x: x**2的写法,中间的冒号,表示左边的是key右边的是value。
-
-
集合推导式
-
大括号除了能用作字典推导式,还可以用作集合推导式,两者仅仅在细微处有差别。
-
a = {x for x in 'aabbccddeeff'} print(a)
-
-
元组推导式
-
使用了中括号和大括号,那么使用圆括号,是不是元组推导式?想法不错,但事实却没有。圆括号在Python中被用作生成器的语法了,很快我们就会讲到,没有元组推导式。
-
a = (x for x in 'aabbccddeeff') print(a) #<generator object <genexpr> at 0x102f45970> #返回的是一个生成器对象
-
生成器
-
在Python这门语言中,生成器毫无疑问是最有用的特性之一。
-
与此同时,也是使用的最不广泛的Python特性之一
-
究其原因,主要是因为,在其他主流语言里面没有生成器的概念。正是由于生成器是一个“新”的东西,所以,它一方面没有引起广大工程师的重视,另一方面,也增加了工程师的学习成本,最终导致大家错过了Python中如此有用的一个特性。那到底什么是生成器呢?
-
有时候,序列或集合内的元素的个数非常巨大,如果全制造出来并放入内存,对计算机的压力是非常大的。
- 比如,假设需要获取一个10**20次方如此巨大的数据序列,把每一个数都生成出来,并放在一个内存的列表内,如果使用这种粗暴的方式,你能确保你的计算机会有如此大的内存么?
- 那么如果元素可以按照某种算法推算出来,需要该元素的话那就计算到哪个元素,那么就可以在循环的过程中不断推算出后续的元素,而不必创建完整的元素集合,从而节省大量的空间。在Python中,这种一边循环一边计算出元素的机制,称为生成器:generator。
- 因此:生成器是一种特殊的迭代器,生成器自动实现了“迭代器协议”(即__iter__和next方法),不需要再手动实现两方法。
-
下面,我们一起来看看如何创建一个生成器!2种方式
- 生成器推导式(忽略)
- for循环,yield关键字
-
生成器推导式:
-
a = (x for x in 'aabbccddeeff') print(a)#生成器对象-
可以通过next()函数获得generator的下一个返回值:
-
a = (x for x in 'aabbccddeeff') print(next(a)) print(next(a)) print(next(a))
-
-
但更多情况下,我们使用for循环创建生成器:
-
g = (x for x in range(5)) for i in g:print(i) -
yield关键字创建生成器(重点)
-
在 Python中,使用yield返回的函数会变成一个生成器(generator)。 在调用生成器的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。下面重点理解yield关键字的使用:
- yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器
- 当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象
- 当你使用for进行遍历的时候或者调用next函数后,函数中的代码才会执行
-
简单示例代码:函数体通过for循环结合yield返回一个生成器
-
def createGenerator():for i in range(5):print('我是循环体!')yield i*i #使用了yield返回的结果而不是用return g = createGenerator() print(g) #<generator object createGenerator at 0x104bc5970> v1 = next(g) print(v1) #我是循环体! #0 v2 = next(g) print(v2) #我是循环体! #1 -
思考:下述函数的执行结果是什么?
-
def yieldTest():i = 0while i < 3:temp = yield i #赋值语句一定是先执行等号右侧的,在执行等号左侧print(temp)i += 1#在生成器函数实现内部是可以向yield后面写代码obj = yieldTest()#创建一个生成器对象 v1 = next(obj) print(v1) #执行结果:0v2 = next(obj) print(v2) #执行结果:None 1 -
思考None是如何产生的第一次取值:yield 返回了 i 值 0,停在yield i,temp没赋到值。第二次取值,开始在print,temp没被赋值,故打印None,i加1,继续while判断,yield 返回了 i 值 1,停在yield i)
-
-
装饰器
-
装饰器(Decorator):
-
从字面上理解,就是装饰对象的器件。
-
就是可以在不修改原有代码的情况下,为被装饰的对象增加新的功能或者附加限制条件。
-
装饰器有很多种,有函数的装饰器,也有类的装饰器。装饰器在很多语言中的名字也不尽相同,它体现的是设计模式中的装饰模式。
-
装饰器的语法是将@装饰器名,放在被装饰对象上面。
-
@dec def func():pass
-
-
在进行装饰器的介绍之前,我们必须先明确几个概念和原则:
- 首先,Python程序是从上往下顺序执行的,而且碰到函数的定义代码块是不会立即执行的,只有等到该函数被调用时,才会执行其内部的代码块
- 其次,由于顺序执行的原因,如果你真的对同一个函数定义了两次,那么,后面的定义会覆盖前面的定义。因此,在Python中代码的放置位置是有区别的,不能随意摆放,通常函数体要放在调用的语句之前。
-
虚拟场景
-
有一个大公司,下属的基础平台部负责内部应用程序及API的开发。另外还有上百个业务部门负责不同的业务,这些业务部门各自调用基础平台部提供的不同函数,也就是API处理自己的业务,情况如下:
-
#基础平台部门开发了上百个函数的API def f1():print('业务部门1的数据接口......') def f2():print('业务部门2的数据接口......') def f3():print('业务部门3的数据接口......') def f100():print('业务部门100的数据接口......')#各部分分别调用自己部分的API f1() f2() f3() f100() -
公司还在创业初期时,基础平台部就开发了这些函数。由于各种原因,比如时间紧,比如人手不足,比如架构缺陷,比如考虑不周等等,没有为函数的调用进行安全认证。现在,公司发展壮大了,不能再像初创时期的“草台班子”一样将就下去了,基础平台部主管决定弥补这个缺陷,于是:
-
第一天:主管叫来了一个运维工程师,工程师跑上跑下逐个部门进行通知,让他们在代码里加上认证功能,然后,当天他被开除了。
-
第二天:主管叫来了一个python自动化开发工程师。哥们是这么干的,只对基础平台的代码进行重构,让N个业务部门无需做任何修改。这哥们很快也被开了,连运维也没得做。
-
#基础平台部门开发了上百个函数的API def f1():#加入认证程序代码xxxprint('业务部门1的数据接口......') def f2():#加入认证程序代码xxxprint('业务部门2的数据接口......') def f3():#加入认证程序代码xxxprint('业务部门3的数据接口......') def f100():#加入认证程序代码xxxprint('业务部门100的数据接口......')#各部分分别调用自己部分的API f1() f2() f3() f100() -
第三天:主管又换了个开发工程师。他是这么干的:定义个认证函数,在原来其他的函数中调用它,代码如下:
-
#基础平台部门开发了上百个函数的API def cheak():pass def f1():cheak()print('业务部门1的数据接口......') def f2():cheak()print('业务部门2的数据接口......') def f3():cheak()print('业务部门3的数据接口......') def f100():cheak()print('业务部门100的数据接口......')#各部分分别调用自己部分的API f1() f2() f3() f100() -
但是主管依然不满意,不过这一次他解释了为什么。
- 主管说:写代码要遵循开放封闭原则,简单来说,已经实现的功能代码内部不允许被修改,但外部可以被扩展。如果将开放封闭原则应用在上面的需求中,那么就是不允许在函数f1 、f2、f3…f100的内部进行代码修改,但是可以在外部对它们进行扩展。
-
第四天:已经没有时间让主管找别人来干这活了,他决定亲自上阵,使用装饰器完成这一任务,并且打算在函数执行后再增加个日志功能。主管的代码如下:
-
def outer(func):def inner():print('认证功能操作')result = func()return resultreturn inner#基础平台部门开发了上百个函数的API @outer def f1():print('业务部门1的数据接口......') @outer def f2():print('业务部门2的数据接口......') @outer def f3():print('业务部门3的数据接口......') @outer def f100():print('业务部门100的数据接口......')#各部分分别调用自己部分的API f1() f2() f3() f100() -
使用装饰器@outer,也是仅需对基础平台的代码进行拓展,就可以实现在其他部门调用函数API之前都进行认证操作,并且其他业务部门无需对他们自己的代码做任何修改,调用方式也不用变。
-
-
-
装饰器机制分析
-
下面以f1函数为例,对装饰器的运行机制进行分析:
-
#1.定义一个装饰器 #装饰器outer是有特殊要求的: #要求1:装饰器函数必须要有一个参数(表示的是被装饰函数的函数名) def outer(func): #step2.func == f1def inner():print('给f1函数增添的安全认证功能')func() #step3:等同于在调用f1()print('给f1函数增加了数据检测的功能')return inner#step4:inner表示的是内部函数的名字,该函数名就会替换被装饰的函数名 #2.使用定义好的装饰器,去装饰某一个函数(在不修改函数原有代码的基础上给其增添新的功能) #如果装饰器装饰了一个函数,则装饰器函数就会被自动调用 @outer # step1.调用装饰器函数,且将被装饰的函数名传递给装饰器函数的参数 #使用outer装饰器装饰f1函数 def f1(): #step5:f1 == inner; inner()函数调用就是在调用f1()print('业务部门1的数据接口......') def f2(): #f2是没有被outer装饰的print('f2函数的原有实现')f1() #实际上就是在调用inner()- 1.程序开始运行,从上往下解释,读到def outer(func):的时候,发现这是个函数定义,于是把函数体加载到内存里。- 2.读到@outer的时候,程序被@这个语法吸引住了,解释器知道这是个装饰器,按规矩要立即执行的,于是程序开始运行@后面那个名字outer所定义的函数。- 3.程序返回到outer函数,开始执行装饰器的语法规则。规则是:- 被装饰的函数的名字会被当作参数传递给装饰函数。装饰函数执行它自己内部的代码后,会将它的返回值赋值给被装饰的函数。原来的f1函数被当做参数传递给了func,而f1这个函数名之后会指向inner函数。- 注意:- @outer和@outer()有区别,没有括号时,outer函数依然会被执行,这和传统的用括号才能调用函数不同,需要特别注意!- f1这个函数名当做参数传递给装饰函数outer,也就是:func = f1,@outer等于outer(f1),实际上传递了f1的函数体,而不是执行f1后的返回值。- outer函数return的是inner这个函数名,而不是inner()这样被调用后的返回值- 4.程序开始执行outer函数内部的内容,一开始它又碰到了一个函数inner,inner函数定义块被程序观察到后不会立刻执行,而是读入内存中(这是默认规则)。- 5.再往下,碰到return inner,返回值是个函数名,并且这个函数名会被赋值给f1这个被装饰的函数,也就是f1 = inner。根据前面的知识,我们知道,此时f1函数被新的函数inner覆盖了(实际上是f1这个函数名更改成指向inner这个函数名指向的函数体内存地址,f1不再指向它原来的函数体的内存地址),再往后调用f1的时候将执行inner函数内的代码,而不是先前的函数体。那么先前的函数体去哪了?还记得我们将f1当做参数传递给func这个形参么?func这个变量保存了老的函数在内存中的地址,通过它就可以执行老的函数体,你能在inner函数里看到result = func()这句代码,它就是这么干的!- 6.接下来,还没有结束。当业务部门,依然通过f1()的方式调用f1函数时,执行的就不再是旧的f1函数的代码,而是inner函数的代码。- 7.以上流程走完后,你应该看出来了,在没有对业务部门的代码和接口调用方式做任何修改的同时,也没有对基础平台部原有的代码做内部修改,仅仅是添加了一个装饰函数,就实现了我们的需求,在函数调用前进行认证,调用后写入日志。这就是装饰器的最大作用。 -
思考:为什么我们要搞一个outer函数一个inner函数这么复杂呢?一层函数不行吗?
- 请注意,@outer这句代码在程序执行到这里的时候就会自动执行outer函数内部的代码,如果不封装一下,在业务部门还未进行调用的时候,就执行了,这和初衷不符。当然,如果你对这个有需求也不是不行。
-
-
带参装饰器
-
上面的例子中,f1函数没有参数,在实际情况中肯定会需要参数的,函数的参数怎么传递的呢?
-
在inner函数的定义部分也加上一个参数,调用func函数的时候传递这个参数:
-
def outer(func):#2.func == f1def inner(n): #3.n == name,n就是被装饰函数的参数print('新功能!')func(n) #4.func(n) == f1(n)return inner #5.inner就会覆盖原先的被装饰函数名f1@outer #1.调用装饰器函数,将被装饰的函数名f1作为实参,传递给outer的形参 def f1(name): #6.f1 == innerprint('f1的原有功能,f1的参数值为:',name)f1('bobo') #7.inner('bobo')
-
相关文章:
2024-12.python高级语法
异常处理 首先我们要理解什么叫做**"异常”**? 在程序运行过程中,总会遇到各种各样的问题和错误。有些错误是我们编写代码时自己造成的: 比如语法错误、调用错误,甚至逻辑错误。 还有一些错误,则是不可预料的错误…...
【C语言】贪吃蛇项目(1) - 部分Win32 API详解 及 贪吃蛇项目思路
文章目录 一、贪吃蛇项目需要实现的基本功能二、Win32 API介绍2.1 控制台2.2 部分控制台命令及调用函数mode 和 title 命令COORD 命令GetStdHandle(获取数据)GetConsoleCursorInfo(获取光标数据)SetConsoleCursorInfo (…...
秋叶Stable diffusion的创世工具安装-带安装包链接
来自B站up秋葉aaaki,近期发布了Stable Diffusion整合包v4.7版本,一键在本地部署Stable Diffusion!! 适用于零基础想要使用AI绘画的小伙伴~本整合包支持SDXL,预装多种必须模型。无需安装git、python、cuda等任何内容&am…...
华为ensp中aaa(3a)实现telnet远程连接认证配置命令
作者主页:点击! ENSP专栏:点击! 创作时间:2024年4月14日18点49分 AAA认证的全称是Authentication、Authorization、Accounting,中文意思是认证、授权、计费。 以下是详细解释 认证(Authentic…...
前端网络---http协议和https协议的区别
http协议和https的区别 1、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。 2、http和https使用的端口不一样,http是80,https是443。 3、http的连接很简单,是无状态的(可以…...
FactoryMethod工厂方法模式详解
目录 模式定义实现方式简单工厂工厂方法主要优点 应用场景源码中的应用 模式定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method 使得一个类的实例化延迟到子类。 实现方式 简单工厂 以下示例非设计模式,仅为编码的一种规…...
Java基础-知识点1(面试|学习)
Java基础-知识点1 Java与C、PythonJava :C:Python: java 与 C的异同相似之处:区别: Java8的新特性Lambda 表达式:Stream API:接口的默认方法和静态方法: 基本数据类型包装类自动装箱与自动拆箱自…...
【InternLM 实战营第二期-笔记1】书生浦语大模型开源体系详细介绍InternLM2技术报告解读(附相关论文)
书生浦语是上海人工智能实验室和商汤科技联合研发的一款大模型,很高兴能参与本次第二期训练营,我也将会通过笔记博客的方式记录学习的过程与遇到的问题,并为代码添加注释,希望可以帮助到你们。 记得点赞哟(๑ゝω╹๑) 书生浦语大模型开源体系…...
【免费】基于SOE算法的多时段随机配电网重构方法
1 主要内容 该程序是完全复现《Switch Opening and Exchange Method for Stochastic Distribution Network Reconfiguration》,也是一个开源代码,网上有些人卖的还挺贵,本次免费分享给大家,代码主要做的是一个通过配电网重构获取…...
Swift面向对象编程
类的定义与实例化: Swift中定义一个类使用class关键字,类的属性和方法都写在大括号内。示例代码如下: class MyClass {var property1: Intvar property2: Stringinit(property1: Int, property2: String) {self.property1 property1self.pr…...
IEDA 的各种常用插件汇总
目录 IEDA 的各种常用插件汇总1、 Alibaba Java Coding Guidelines2、Translation3、Rainbow Brackets4、MyBatisX5、MyBatis Log Free6、Lombok7、Gitee IEDA 的各种常用插件汇总 1、 Alibaba Java Coding Guidelines 作用:阿里巴巴代码规范检查插件,…...
浅谈C语言中异或运算符的10种妙用
目录 1、前言 2、基本准则定律 3、妙用归纳 4、总结 1、前言 C语言中异或运算符^作为一个基本的逻辑运算符,相信大家都知道其概念:通过对两个相同长度的二进制数进行逐位比较,若对应位的值不同,结果为 1, 否则结果为 0。 但是…...
Canal--->准备MySql主数据库---->安装canal
一、安装主数据库 1.在服务器新建文件夹 mysql/data,新建文件 mysql/conf.d/my.cnf 其中my.cnf 内容如下 [mysqld] log_timestampsSYSTEM default-time-zone8:00 server-id1 log-binmysql-bin binlog-do-db mall # 要监听的库 binlog_formatROW2.启动数据库 do…...
vs配置opencv运行时“发生生成错误,是否继续并运行上次的成功生成”BUG解决办法
vs“发生生成错误,是否继续并运行上次的成功生成” 新手在用vs配置opencv时遇到这个错误时,容易无从下手解决。博主亲身经历很有可能是release/debug模式和配置文件不符的问题。 在配置【链接器】→【输入】→【附加依赖项】环节,编辑查看选择…...
Dryad Girl Fawnia
一个可爱的Dryad Girl Fawnia的三维模型。她有ARKit混合形状,人形装备,多种颜色可供选择。她将是一个完美的角色,幻想或装扮游戏。 🔥 Dryad Girl | Fawnia 一个可爱的Dryad Girl Fawnia的三维模型。她有ARKit混合形状,人形装备,多种颜色可供选择。她将是一个完美的角色…...
内存相关知识(新)
基本概念 内存层次结构:内存层次结构是一种层次化的存储设备结构,它包括寄存器、缓存、主存和辅助存储器。每一层次的存储设备都有不同的速度、容量和成本。 内存单元:内存被划分为一系列连续的内存单元,每个单元都有一个唯一的地…...
C++从入门到精通——static成员
static成员 前言一、static成员概念例题 二、 static成员的特性特性例题静态成员函数可以调用非静态成员函数吗非静态成员函数可以调用类的静态成员函数吗 前言 一、static成员 概念 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之…...
【K8S:初始化】:执行kubeadm显示:connection refused.
文章目录 [root10 kubernetes]# kubeadm init --kubernetes-versionv1.23.0 --image-repositoryregistry.aliyuncs.com/google_containers --apiserver-advertise-address192.168.56.104 [init] Using Kubernetes version: v1.23.0 [preflight] Running pre-flight checks [pre…...
msvcp140_1.dll是什么?找不到msvcp140_1.dll丢失解决方法
msvcp140_1.dll 文件是一个与 Microsoft Visual C 2015 Redistributable 相关的动态链接库(DLL),它在 Windows 系统中扮演着重要角色,尤其对于那些依赖于 Visual C 运行时环境的应用程序和游戏来说。以下是关于 msvcp140_1.dll 文…...
【Java探索之旅】掌握数组操作,轻松应对编程挑战
🎥 屿小夏 : 个人主页 🔥个人专栏 : Java编程秘籍 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一、数组巩固练习1.1 数组转字符串1.2 数组拷贝1.3 求数组中的平均值1.4 查找数组中指…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
