【Python进阶】拷贝、闭包、装饰器,函数分类

目录

一、对象属性和类属性

1、对象属性

2、类属性

二、类方法和静态方法

1、类方法

2、静态方法

3、扩展综合案例

三、深拷贝和浅拷贝

1、浅拷贝

2、深拷贝

3、浅拷贝和深拷贝的区别

四、函数知识

1、函数的定义与调用

2、函数名记录的是引用

3、函数名当作参数传递

五、闭包

1、闭包的作用

2、使用闭包

3、nonlocal关键字

六、装饰器

1、装饰器入门

1)语法糖

2)传统方式

七、函数分类

1、装饰无参无返回值的函数

2、装饰有参无返回值的函数

3、装饰无参有返回值的函数

4、装饰有参有返回值的函数


一、对象属性和类属性

1、对象属性

对象属性,有时也称为实例属性、普通属性、公有属性,或者直接叫做属性。

在类内部,访问对象属性语法:

self.对象属性名

在类外部,访问对象属性语法:

对象名.对象属性名

例如,一起来完成:

(1)定义一个手机类,属性有品牌、颜色;

(2)分别试着在类内部和类外部访问属性。

# 1.定义手机类
# 2.内部访问
class Phone(object):def __init__(self,color,brand):   #  构造器# 对象名.属性名self.color = color   # 对象属性self.brand = brand   # 对象属性
​def show(self):print(f"访问车的颜色:{self.color}")
​
# 3.外部访问
phone = Phone("黑色","Audi")
print(f"颜色:{phone.color}")
print(f"品牌:{phone.brand}")

总结:

(1)在类外部要访问对象属性,语法:对象名.属性名;

(2)在类内部要访问对象属性,语法:self.属性名。

2、类属性

类属性指的是:类所拥有的属性,在整个类中都可以直接使用。

定义类属性语法:

class 类名(object):

         类属性名 = 值

调用类属性语法:

类名.类属性名

例如,一起来完成:

(1)在Student类中,定义一个名为school_name的类属性;

(2)调用使用类属性,观察效果。

class Student:          # 公共属性就定义成类属性school_name = '家里蹲'   #类属性,所有对象共享,不输入任何一个对象,属于整个类,用类名访问,用对象访问可以可以# 属性def __init__(self, id,name, age,sex):self.id = id    # 对象属性,属于某个对象的,使用对象访问self.name = nameself.age = ageself.sex = sex
​# 学习行为def study(self):print(f'{self.name}学生要好好学习!')# 睡觉行为def sleep(self):print(f'{self.name}学生要好好睡觉!')
​
​
print('-----------------------')
stu = Student(1001,'刘备',18,'M')
​
# 访问类属性
print('-----------访问类属性-----------------')
print(Student.school_name)  # 使用类名来访问类属性
print(stu.school_name)      # 类属性也可以使用对象访问,但是不建议
​
# 访问对象属性
print('-----------访问对象属性-----------------')
print(stu.id)   # 使用对象来访问对象属性
print(stu.name) # 使用对象来访问对象属性
print(stu.age)  # 使用对象来访问对象属性
print(stu.sex)  # 使用对象来访问对象属性# 1.定义类 -类属性  [方法]class People(object):# 类属性count = 100
​def show(self):print("森林防火,人人有责.")
​
# 2.调用使用
# print(People.count)
# 扩展   了解
# p = People()
# print(p.count)
# 思考: 类属性名可以私有化吗?如何访问?

总结:

实际上,可以通过对象名和类名来调用类属性,但优先考虑使用【类名.类属性名】形式。

二、类方法和静态方法

1、类方法

类方法指的是:类所拥有的方法。要形成类方法,需满足:

(1)使用装饰器@classmethod来修饰方法;

(2)把方法的第1个参数设置为cls。

定义类方法,语法:

class 类名(object):@classmethoddef 类方法名(cls):...# 类方法中不能出现self

调用类方法,语法:

类名.类方法名()

说明:类方法一般会和类属性配合使用,尤其是私有类属性。

例如,一起来完成:

定义一个小狗类,且小狗很喜欢吃骨头;[类方法]

# 1、定义类方法
class Dog(object):total_dogs = 10 # 类属性,类变量@classmethod  # 类方法def eat(cls):print(f'{cls.total_dogs}条狗吃骨头')  # cls就代表类本身 ,使用类方法来访问类属性# 调用类方法
Dog.eat()  # 直接使用类名来访问类方法# 静态方法中不能出现self

总结:

(1)定义类方法时,需要:先使用@classmethod修饰方法,且第1个参数名为cls;

(2)调用类方法的语法:类名.类方法名()。

2、静态方法

静态方法需要通过装饰器@staticmethod来修饰方法,且静态方法一般不需要定义任何参数。

定义静态方法,语法:

class 类名(object):@staticmethoddef 静态方法名():...

调用静态方法,语法:

类名.静态方法名()

说明:可以使用静态方法显示一些文本信息。

在Python中,静态方法(static method)是类中的一个方法,但它既不属于类本身(如类方法),也不属于类的实例。静态方法不需要特定的类实例来调用,也不需要类本身作为第一个参数(如类方法中的cls)。它们基本上就是定义在类命名空间中的普通函数,只不过这些函数可以通过类名或类的实例名来调用。

例如,一起来完成:

(1)开发一款要显示操作界面的小游戏,分别有开始、暂停、退出等按键;

(2)使用静态方法完成编写。

# 1.定义类
# 2.静态方法
class Game(object):@staticmethoddef show_menu():print("==================================")print("\t1.开始游戏;")print("\t2.暂停游戏;")print("\t3.结束游戏.")print("==================================")# 静态方法
Game.show_menu()  # 通过类名来调用静态方法game = Game() 
game.show_menu() # 通过实例对象调用静态方法

总结:

(1)静态方法要使用@staticmethod修饰,且可以没有参数。

(2)调用静态方法的语法:类名.静态方法名()。

3、扩展综合案例

1. 设计一个 Game 类 (类名)

2. 属性:

                • 定义一个 top_score 类属性 -> 记录游戏的历史最高分

                • 定义一个 player_name 实例属性 -> 记录当前游戏的玩家姓名

3. 方法:

                • 静态方法 show_help() -> 直接打印 这是游戏帮助信息

                • 类方法 show_top_score() -> 显示历史最高分

                • 实例方法 start_game() -> 开始当前玩家的游戏

                -         3.1 输出 玩家 xxx 开始游戏

                -         3.2 使用随机数,生成 10 - 100 之间的随机数字作为本次游戏的得分

                -         3.3 打印 玩家 xxx 本次游戏得分 xxx

                -         3.4 判断本次游戏得分和最高分之间的关系

4. 主程序步骤:

                __main__ 1 查看帮助信息 2 查看历史最高分 3 创建游戏对象,开始游戏

import randomclass Game(object):top_score = 0  # 类属性:记录游戏的历史最高分def __init__(self,name):self.name = name  #记录当前游戏的玩家姓名#这是游戏帮助信息@staticmethoddef show_help():print("==================================")print("\t1.开始游戏;")print("\t2.暂停游戏;")print("\t3.结束游戏.")print("==================================")#显示历史最高分@classmethoddef show_top_score(cls):print(f'当前历史最高分{cls.top_score}')  # 类方法访问类属性# 开始当前玩家的游戏def start_game(self):# 3.1 输出 玩家 xxx 开始游戏print(f'玩家{self.name} 开始游戏')#3.2 使用随机数,生成 10 - 100 之间的随机数字作为本次游戏的得分score = random.randint(10, 100)#3.3 打印 玩家 xxx 本次游戏得分 xxxprint(f'玩家 {self.name} 本次游戏得分 {score}')#3.4 判断本次游戏得分和最高分之间的关系if score > Game.top_score:print(f'恭喜{self.name}打破了最高纪录!')Game.top_score = score  # 修改最高分else:print(f'很遗憾,{self.name}没有打破了最高纪录,继续努力!')if __name__ == '__main__':print('-----------------------------------------')#1 查看帮助信息Game.show_help()#2 查看历史最高分Game.show_top_score()#3 创建游戏对象,开始游戏game = Game('刘备')game.start_game()print('-----------------------------------------')#1 查看帮助信息Game.show_help()#2 查看历史最高分Game.show_top_score()#3 创建游戏对象,开始游戏game = Game('关羽')game.start_game()

三、深拷贝和浅拷贝

1、浅拷贝

浅拷贝需要使用copy模块下的copy()函数。

函数名含义
copy(t)使用浅拷贝来拷贝信息。

浅拷贝只对可变类型的第一层对象进行拷贝,对拷贝的对象开辟新的内存空间进行存储,且不会拷贝对象内部的子对象。

例如,一起来完成:

(1)使用浅拷贝来拷贝不可变数据类型:数字19和元组(12, 13, 14, );

(2)使用浅拷贝来拷贝可变数据类型:列表[10, 20, 30]和列表[a, b];

(3)观察拷贝不可变类型、可变类型数据的效果。

总结:

(1)当要了解浅拷贝时,需要使用copy模块的copy()函数;

(2)注意:对于浅拷贝的理解,尽量分为拷贝不可变类型和可变类型的数据来查看。

(3)浅拷贝适用于对象内部主要是基本类型(如int, float, str等)或不需要深拷贝的情况。

2、深拷贝

深拷贝需要使用copy模块下的deepcopy()函数:

函数名含义
deepcopy(t)使用深拷贝来拷贝信息。

深拷贝指的是拷贝一个对象时,只要发现对象有可变类型就会对该对象到最后一个可变类型的每一层对象就行拷贝,对每一层拷贝的对象都会开辟新的内存空间进行存储。

通俗地说,深拷贝就是对一个对象中所有层次的拷贝,即既拷贝了引用,也拷贝了内容。

例如,一起来完成:

(1)使用深拷贝来拷贝不可变数据类型:字符串"hello"和元组(100, 200, 300, );

(2)使用深拷贝来拷贝可变数据类型:列表[11, 22, 33]和列表[a, b];

(3)观察拷贝不可变类型、可变类型数据的效果。

#(1)使用浅拷贝来拷贝不可变数据类型:数字19和元组(12, 13, 14, );
import copyprint('-------------不可变类型:数字---------------')
a = 19
b = copy.deepcopy(a)print(a,b)          # 值相同
print(id(a),id(b))  # 地址相同print('-------------不可变类型:元组---------------')tuple1 = (12, 13, 14)
tuple2 = copy.deepcopy(tuple1)print(tuple1,tuple2)          # 值相同
print(id(tuple1),id(tuple2))  # 地址相同#(2)使用浅拷贝来拷贝可变数据类型:列表[12, 13, 14]print('-------------可变类型:列表---------------')
list1 = [12, 13, 14]
list2 = copy.deepcopy(list1)print(list1,list2)          # 值相同
print(id(list1),id(list2))  # 地址不同print('-------------可变类型:列表嵌套---------------')
list1 = [12, 13, 14,[77,88,99]]
list2 = copy.deepcopy(list1)print(list1,list2)          # 值相同
print(id(list1),id(list2))  # 外层地址不同
print(id(list1[3]),id(list2[3]))  # 内层地址竟然相同list1[3][0] = 777   # list1把内层列表的值修改之后,list2的内层列表也跟着改,这样不合理print(list1,list2)print('-------------可变类型:列表嵌套,直接赋值---------------')list1 = [12, 13, 14,[77,88,99]]
list2 = list1print(list1,list2)          # 如果直接赋值,值相同
print(id(list1),id(list2))  # 外层地址相同
print(id(list1[3]),id(list2[3]))  # 内层地址也相同list1[3][0] = 777   # list1把内层列表的值修改之后,list2的内层列表也跟着改,这样不合理print(list1,list2)

结论:
浅拷贝本质是只拷贝了内存地址值
对不可变类型的数据进行浅拷贝时, 内存地址值相同, 值也相同, 通过指向原有数据内容的内存地址值.
浅拷贝拷贝的是【内存地址值】
浅拷贝了可变数据类型的数据后, 外层内存地址会变化,值也会变化, 内层地址不会变化,值也不会变化

深拷贝既拷贝了内存地址值,又拷贝了内容

对不可变类型的数据进行深拷贝时, 内存地址值相同, 值也相同。

深拷贝拷贝了引用和内容

深拷贝了可变数据类型的数据后, 内存地址值会变化, 值是相同的. [从表面上看: 深浅拷贝效果一致]

3、浅拷贝和深拷贝的区别

对于浅拷贝和深拷贝,区别如下:

函数名含义
deepcopy(t)完全拷贝了父对象及其子对象。
copy(t)拷贝父对象,不会拷贝对象的内部的子对象。

例如,一起来完成:

(1)分别使用浅拷贝和深拷贝来拷贝可变类型:列表[m, n];

(2)观察父对象和子对象引用和数值的变化效果。

#(1)使用浅拷贝来拷贝不可变数据类型:数字19和元组(12, 13, 14, );
import copyprint('-------------不可变类型:数字---------------')
a = 19
b = copy.deepcopy(a)print(a,b)          # 值相同
print(id(a),id(b))  # 地址相同print('-------------不可变类型:元组---------------')tuple1 = (12, 13, 14)
tuple2 = copy.deepcopy(tuple1)print(tuple1,tuple2)          # 值相同
print(id(tuple1),id(tuple2))  # 地址相同#(2)使用浅拷贝来拷贝可变数据类型:列表[12, 13, 14]print('-------------可变类型:列表---------------')
list1 = [12, 13, 14]
list2 = copy.deepcopy(list1)print(list1,list2)          # 值相同
print(id(list1),id(list2))  # 地址不同print('-------------可变类型:列表嵌套---------------')
list1 = [12, 13, 14,[77,88,99]]
list2 = copy.deepcopy(list1)print(list1,list2)          # 值相同
print(id(list1),id(list2))  # 外层地址不同
print(id(list1[3]),id(list2[3]))  # 内层地址竟然相同list1[3][0] = 777   # list1把内层列表的值修改之后,list2的内层列表也跟着改,这样不合理print(list1,list2)

结论通俗:

浅拷贝 -> 给文件夹制作了一个快捷方式;

深拷贝 ->复制+粘贴了一份新的, 里面的所有内容都是全新。

总结:

(1)当拷贝多层数据时,才能发现深拷贝、浅拷贝的区别在于是否能完全拷贝子对象;

(2)深拷贝适用于对象内部包含较多非基本类型对象,并且需要确保对象之间完全独立的情况。

深浅拷贝的区别:

浅拷贝只复制了原始对象的引用,而深拷贝则是递归地复制原始对象及嵌套对象,从而得到完全独立的新对象副本

四、函数知识

1、函数的定义与调用

在之前的学习中,已经学习过函数。一起来看看简单和综合函数语法格式。

最简单的语法:

# 定义
def 函数名():代码...# 调用
函数名()

综合的语法:

# 定义
def 函数名([参数1, 参数2, 参数3, ...]):代码...[return 值]# 调用
函数名([值1, 值2, 值3, ...])

接着,再来总结下函数的使用特点

(1)先定义,后调用;

(2)不调用,不执行;

(3)调用一次,执行一次;

(4)当输出有返回值的函数时,输出的是具体的返回值结果;当输出没有返回值的函数时,输出的是None。

例如,一起来完成:

(1)定义并调用一个有返回值的函数func();

(2)定义并调用一个无返回值的函数test()。

# 1.定义有返回值的func()
# def func():
#     print("Hello World..")
#     return 100
#
# # 2.调用
# # func()
# print(func())# 3.定义无返回值的test()
def test():print("人生苦短,我用Python")# 4.调用
print(test())
# 人生苦短,我用Python
# None

总结:

(1)当调用函数时,要给在调用函数名后添加()括号;

(2)注意:当输出没有返回值的函数调用时,输出的是None;

2、函数名记录的是引用

我们已经知道,当要调用一个函数时,需要:

函数名([值1, 值2, 值3, ...])

说明:要调用函数,记得添加()括号。

那么,如果直接输出函数名,会是什么效果呢?

例如,一起来完成:

(1)定义一个有返回值的函数show();

(2)接着,直接输出函数名,观察输出结果;

(3)结论:函数名记录的是函数引用,即内存地址值。

def show():print('我是一个小小的函数')print(show)  #<function show at 0x000001BF04195168> 函数名就是一个地址引用# show就是一个地址,指向函数的定义的那片内存空间,把函数的地址赋值为show2,show2也指向了那片内存空间
# show2也称为函数的引用地址
show2 = show  #使用show2来调用函数
show2()   

总结:

(1)当定义了函数后,就相当于给函数名在内存中开辟了一个新的内存空间;

(2)注意:直接输出函数名时,输出的是函数对应的内存地址值;

3、函数名当作参数传递

我们已经知道,函数名记录的是函数的引用,即内存地址值。

那么,当把函数名直接作为参数进行传递时,从本质上说,传递的是:对应函数的内存地址值。

def 函数名A():代码...def function(num):代码num()  # 调用函数...function(函数名A)   # 把函数名当作参数传递

例如,一起来完成:

(1)定义一个无参函数test();

(2)定义有一个参数的函数func();

(3)把无参函数test()的函数名传递给有参函数func(),并观察效果。

# (1)定义一个无参函数test();
# (2)定义有一个参数的函数func();
# (3)把无参函数test()的函数名传递给有参函数func(),并观察效果。def test():print('这个是test函数')def func(f_name):print('func函数开始')f_name()print('func函数结束')def add(x,y):return  x + ydef func2(f_name):  # f_name = lambda x,y:x+yprint('func2函数开始')a = 10b = 20print(f'两个数的和是:{f_name(a,b)}')print('func2函数结束')if __name__ == '__main__':func(test)func2(lambda x,y:x+y)func2(add)   # 作用同上

总结:

(1)当把函数名直接传递时,若要查看调用函数的效果,需要在函数内给参数添加()括号进行调用;

(2)把函数名当作参数进行传递,可以应用于闭包和装饰器中。

五、闭包

1、闭包的作用

在之前的学习中,我们会发现:当调用完函数后,函数内定义的变量就销毁了。

如果要保存函数内的变量,就可以使用闭包。

先来看看闭包的作用:闭包可以保存函数内的变量,而不会随着调用完函数而被销毁。

例如,一起来完成:

(1)此处来了解闭包的作用:保存函数内的变量;

(2)定义一个有返回值的函数;

(3)然后,调用函数并使用变量存储返回值结果;

(4)在变量基础上,进行重复累加数值,观察效果。

# 1.定义有返回值的函数
def func():a = 10print("今天天气真好")return a# 2.使用变量来接收函数调用
# func()
number = func()  # a的值存储到了number  -类似闭包的语法
# 3.观察: 函数虽然调用结束了,但是变量被保存起来  = 闭包
print(number+23)
print(number+44)

2、使用闭包

闭包指的是:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数。

此时,把这个使用外部函数变量的内部函数,就称为闭包。

定义闭包语法:

# 外部函数
def 外部函数名(外部参数):# 内部函数def 内部函数名(内部参数):...[使用外部函数的变量]代码return 内部函数名      # 闭包

调用闭包语法:

变量名 = 外部函数名([外部参数列表])
变量名([内部参数列表])

要构成闭包,需要满足3个条件:

(1)有嵌套:外部函数中嵌套了一个内部函数

(2)有引用:内部函数中使用了外部函数的变量或参数

(3)有返回:外部函数返回内部函数的函数名

说明:

(1)为了更好的理解闭包,建议:外部函数命名为outer、内部函数命名为inner;

(2)当熟练使用闭包后,再任意命名即可。

例如,一起来完成:

(1)定义一个用于求和的闭包;

(2)其中,外部函数有参数x,内部函数有参数y;

(3)然后调用并求解两数之和及输出,观察效果。

# 定义外部函数
def outer(x):def inner(y):  # 函数定义嵌套result = x + y   # 内部函数使用外部函数变量print(f'两个数的和是:{result}')return inner   # 外部函数返回内部函数的名字if __name__ == '__main__':inner_func = outer(100)  # 调用外部函数,返回的值就是内部函数的名字,,就是返回一个函数inner_func(10)   # 调用内部函数,外部函数的x是100inner_func(20)  # 调用内部函数,外部函数的x是100

总结:

(1)构成闭包的3个条件:有嵌套、有引用、有返回;

(2)注意:闭包可以用于处理装饰器的使用。

3、nonlocal关键字

在闭包的使用过程中,当要在内部函数中修改外部函数的变量,需要使用nonlocal提前声明。

nonlocal关键字语法:

nonlocal 变量名

说明:

当变量报错时,记得使用nonlocal声明。

例如,一起来完成:

(1)编写一个闭包,并让内部函数去修改外部函数内的变量a = 100;

(2)记得使用【nonlocal 变量名】提前声明,并观察效果。

# 当你希望在内部函数中修改外边函数的变量,就应该使用nolocal关键字来声明
# 定义外部函数
def outer():a = 10    # 外部函数的局部变量def inner():  # 函数定义嵌套nonlocal a   # 声明这里的a就是外部函数的变量a += 1       # 内部函数修改该变量print(f'a的值是:{a}')return inner   # 外部函数返回内部函数的名字if __name__ == '__main__':inner_func = outer()inner_func()

总结:

(1)若要声明能够让内部函数去修改外部函数的变量,则要使用nonlocal关键字;

(2)注意:当要在函数中修改全局变量的值时,要记得使用global给全局变量提前声明。

六、装饰器

1、装饰器入门

1)语法糖

装饰器本质上就是闭包,但装饰器有特殊作用,那就是:在不改变原有函数的基础上,给原有函数增加额外功能。

定义装饰器:

def outer([外面参数列表]):def inner([内部参数列表]):新增额外功能代码.......[引用]return inner

使用装饰器的标准语法:

# 语法糖
@outer
def 函数名():代码...

例如,一起来完成:

(1)我们知道,发表评论前是需要先登录的;

(2)接着,先定义有发表评论的功能函数;

(3)使用语法糖方式,在不改变原有函数的基础上,提示用户要先登录~。

# 接下来,要对func函数进行增强,编写闭包
def outer(func):def inner():print('先要登录!')func()print('评论成功!')return inner  # inner函数本质上就是增强版的func函数# 定义你要对哪个函数进行增强
@outer
def func():print('发表评论!')if __name__ == '__main__':func()

总结:

(1)装饰器本质上就是闭包,作用是在不改变原有函数的基础上,给原有函数增加额外功能;

(2)要构成装饰器,要满足4个条件:有嵌套、有引用、有返回、有额外功能;

2)传统方式

定义装饰器:

def outer([外面参数列表]):def inner([内部参数列表]):新增额外功能代码.......[引用]return inner

使用装饰器的传统方式语法:

# 传统方式
变量名 = outer([外面参数列表])
变量名([内部参数列表])

例如,一起来完成:

(1)我们知道,发表评论前是需要先登录的;

(2)接着,先定义有发表评论的功能函数;

(3)使用传统方式,在不改变原有函数的基础上,提示用户要先登录~;

(4)了解装饰器的执行流程。

# 接下来,要对func函数进行增强,编写闭包
def outer(func):def inner():print('先要登录!')func()print('评论成功!')return inner  # inner函数本质上就是增强版的func函数# 定义你要对哪个函数进行增强
def func():print('发表评论!')if __name__ == '__main__':inner_func = outer(func)inner_func()

总结:

(1)使用装饰器时,应该优先考虑使用:语法糖;

(2)为了更好的了解装饰器的执行流程,可以通过装饰器的传统方式来了解。

七、函数分类

对于函数的使用,可以根据有无参数、有无返回值来进行分类。分为:

(1)无参无返回值的函数

(2)有参无返回值的函数

(3)无参有返回值的函数

(4)有参有返回值的函数

无参无返回值的函数的语法:

# 定义
def 函数名():代码...# 调用
函数名()

有参无返回值的函数的语法:

# 定义
def 函数名(参数1, 参数2, ...):代码...# 调用
函数名(值1, 值2, ...)

无参有返回值的函数的语法:

# 定义
def 函数名():代码...return 值# 调用
变量名 = 函数名()

有参有返回值的函数的语法:

# 定义
def 函数名(参数1, 参数2, ...):代码...return 值# 调用
变量名 = 函数名(值1, 值2, ...)

总结:

(1)我们会发现,函数的分类有4种,那么对应于装饰器也有4种;

(2)注意:对函数来分类,主要是根据有无参数和返回值来划分的。

1、装饰无参无返回值的函数

当使用装饰器装饰无参无返回值的函数时,语法:

def outer(func):def inner():新增额外功能代码.......[引用]return inner

例如,一起来完成:

(1)在给无参无返回值的原有函数求和计算结果之前;

(2)添加一个友好提示(注意:不能改变源码):正在努力计算中...。

# 1.定义装饰器
def outer(func):def inner():   # 有嵌套print("=======正在努力计算中...========")   # 有额外功能func()  # 有引用return inner  # 有返回# 2.使用装饰器
# 3.定义函数
@outer
def get_sum():a = 10b = 23sum = a + bprint(f"两数之和为:{sum}")# 4.调用函数
get_sum()

总结:

(1)当被装饰的函数没有参数时,对应定义的装饰器的内部函数也没有参数;

(2)注意:当被装饰的函数没有返回值时,对应定义的装饰器的内部函数也没有返回值.。

2、装饰有参无返回值的函数

当使用装饰器装饰有参无返回值的函数时,语法:

def outer(func):def inner(参数1, 参数2, ...):新增额外功能代码.......[引用]return inner

例如,一起来完成:

(1)在给有参无返回值的原有函数求和计算结果之前;

(2)添加一个友好提示(注意:不能改变源码):正在努力计算中...。

def outer(func):def inner(x,y):   # 有嵌套

总结:

当被装饰的原有函数有参数时,装饰器的内部函数也有对应个数的参数

3、装饰无参有返回值的函数

当使用装饰器装饰无参有返回值的函数时,语法:

def outer(func):def inner():新增额外功能代码.......[引用]return 值  # 要返回值return inner

例如,一起来完成:

(1)在给无参有返回值的原有函数求和计算结果之前;

(2)添加一个友好提示(注意:不能改变源码):正在努力计算中...。
 

# 1.定义装饰器
def outer(func):def inner():print("=====正在努力计算中...")result = func()return resultreturn inner# 2.使用装饰器
# 3.定义函数
@outer
def get_sum():a = 19b = 23sum = a + breturn sum# 4.调用函数
print(get_sum())

总结:

当原有函数有返回值时,记住:装饰器的内部函数也需要返回结果,否则没有输出效果。

4、装饰有参有返回值的函数

当使用装饰器装饰有参有返回值的函数时,语法:

def outer(func):def inner(参数1, 参数2, ...):新增额外功能代码.......[引用]return 值  # 要返回值return inner

例如,一起来完成:

(1)在给有参有返回值的原有函数求和计算结果之前;

(2)添加一个友好提示(注意:不能改变源码):正在努力计算中...。

# 接下来,要对func函数进行增强,编写闭包
def outer(func):def inner(a,b):  #被增强的函数func,有两个参数,则这里的inner也必须有两个参数,因为inner是增强版的funcprint('求和前!')result = func(a,b)return result     # 被增强函数有返回值,这里也必须有返回值 这里的return,一般返回被增强函数的返回值return inner  # inner函数本质上就是增强版的func函数# 定义你要对哪个函数进行增强
@outer
def func(a,b):   # 有参无返回值return a+bif __name__ == '__main__':result = func(10,20)print(result)

总结:

(1)当被装饰的原有函数有参有返回值时,定义的装饰器类型应该在内部函数中要有参数,也要有返回值;

(2)当要构成装饰器的条件时,需要满足:有嵌套、有引用、有返回、有额外功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3225658.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

记录|C#安装+HslCommunication安装

记录线索 前言一、C#安装1.社区版下载2.VS2022界面设置 二、HslCommunication安装1.前提2.安装3.相关文件【重点】 更新记录 前言 初心是为了下次到新的电脑上安装VS2022做C#上机位项目时能快速安装成功。 一、C#安装 1.社区版下载 Step1. 直接点击VS2022&#xff0c;跳转下…

apksigner安装

apksigner安装 下载cmdline-tools获取SDK 组件如果发生报错&#xff1a;Error: Could not determine SDK root.Error: Either specify it explicitly with --sdk_root or move this package into its expected location: <sdk>\cmdline-tools\latest\&#xff0c;并把 安…

首月免月租,手机卡首月免月租什么意思?

手机卡首月免月租是真的吗&#xff1f;只有首月免吗&#xff1f;最近有不少小伙伴来咨询首月免月租这件事了&#xff0c;今天这篇文章就给大家解开这个疑惑。 话不多说&#xff0c;下面让我们直接进入正题&#xff1a; 首先&#xff0c;三大运营商的卡一般只有移动和电信的套餐…

14.爬虫---Selenium 经典动态渲染工具的使用

14.Selenium 经典动态渲染工具的使用 1.查看chrome浏览器版本2.ChromeDriver 安装3.Selenium 安装4.验证安装5.基本用法5.1启动浏览器5.2导航到页面5.3查找元素5.3.1单个元素 find_element5.3.2多个元素 find_elements 5.4 执行操作5.5 动作链ActionChains5.6 执行 JavaScript …

帕金森病患者应该如何确定自己每天适宜的饮水量?

帕金森病患者确定每天适宜的饮水量时&#xff0c;应该考虑到药物副作用、运动障碍和便秘等问题。建议的饮水量通常是每天6至8杯水&#xff0c;相当于约2000毫升左右。这个量可以根据个人的体重、气候条件、活动水平以及是否有其他健康问题进行适当调整。 为了科学合理地安排饮水…

半导体光伏废水深度除氟树脂

摘要&#xff1a;海普开发的HP3600纳米除氟吸附剂&#xff0c;这种树脂对水体中的氟均具有高效的选择性&#xff0c;已应用于多个领域含氟废水的处理&#xff0c;为客户提供了优质、高效的除氟解决方案。 #半导体光伏废水深度除氟树脂 半导体作为各种高新技术飞速发展的基础&a…

IF不降反增!审稿速度,比我家网速还快!3本接受率高的医学期刊,赶紧码住!

&#x1f50d; 为什么选择这3本期刊&#xff1f; 今天老毕给大家分享3本医学 SCI&#xff0c;分别为Tumori Journal、Adipocyte以及Annals of Medicine。 这3本医学杂志&#xff0c;不仅审稿速度快&#xff0c;录用率还高&#xff0c;其中不乏接受率为48%的“毕业神刊”。2024年…

图解HTTP(5、与 HTTP 协作的 Web 服务器 6、HTTP 首部)

5、与 HTTP 协作的 Web 服务器 一台 Web 服务器可搭建多个独立域名的 Web 网站&#xff0c;也可作为通信路径上的中转服务器提升传输效率。 用单台虚拟主机实现多个域名 在相同的 IP 地址下&#xff0c;由于虚拟主机可以寄存多个不同主机名和域名的 Web 网站&#xff0c;因此…

万字学习——DCU编程实战补充

参考资料 2.1 详解DCU架构 DCU 开发与使用文档 (hpccube.com) DCU架构是什么样的 计算单元阵列&#xff0c;如图CU0、CU1等缓存系统&#xff08;L1一级缓存&#xff0c;L2二级缓存&#xff09;全局内存(global memory)CPU和DCU数据通路&#xff08;DMA&#xff09; 我的理解…

如何在 Windows 10 上恢复未保存的 Word 文档

您是否整晚都在处理一个重要的 word 文件&#xff0c;但忘记保存它了&#xff1f;本文适合您。在这里&#xff0c;我们将解释如何恢复未保存的 word 文档。除此之外&#xff0c;您还将学习如何恢复已删除的 word 文档。 从专业人士到高中生&#xff0c;每个人都了解丢失重要 W…

Linux初始化新的git仓库

1.在git服务器上找到项目常部署的git地址可以根据其他项目的git地址确认 例如ssh://git192.168.10.100/opt/git/repository.git 用户名&#xff1a;git&#xff08;前面的是用户&#xff09; 服务器地址&#xff1a;192.168.10.100 git仓库路径&#xff1a;/opt/git/ 2.在服务器…

C++笔试真题

可变分区管理方案 最佳适应&#xff1a;空闲区按容量递增最坏适应&#xff1a;空闲区按容量递减首先适应&#xff1a;空闲区按地址递增 C的结构体中有构造函数。 Linux新建用户或组 useradd&#xff1a;命令用于建立用户账号usermod&#xff1a;修改用户账号groupadd&#…

中职网络安全B模块Cenots6.8数据库

任务环境说明&#xff1a; ✓ 服务器场景&#xff1a;CentOS6.8&#xff08;开放链接&#xff09; ✓ 用户名&#xff1a;root&#xff1b;密码&#xff1a;123456 进入虚拟机操作系统&#xff1a;CentOS 6.8&#xff0c;登陆数据库&#xff08;用户名&#xff1a;root&#x…

第一次坐火车/高铁,如何坐?全流程讲解

第一次坐动车注意事项 第一次乘动车流程&#xff1a;进站→安检→候车厅→找检票口→过闸机→站台候车→找车厢→上车找座→下车→出站 乘车流程 一、进火车站/高铁站&#xff1a;刷购票证件原件进站 1、自助闸机刷证&#xff1a;身份证 2、人工通道&#xff1a;护照、临时…

从两眼放光到心碎一地《长相思》第二季搞笑爱情转折

这《长相思》第二季的剧情&#xff0c; 简直是心脏按摩器升级版啊&#xff01; 爷爷一开口&#xff0c;要给玱玹安排馨悦当王后 我这小心脏差点就跟着‘嘭’一声 "哎呀&#xff0c;以为要上演宫廷版《速度与激情》 结果小夭女神一出手&#xff0c; 不是醋坛子翻&#…

[C++]——同步异步日志系统(3)

同步异步日志系统 一、日志系统框架设计1.1模块划分1.1.1 日志等级模块1.1.2 日志消息模块1.1.3 日志消息格式化模块1.1.4 日志落地模块&#xff08;日志落地的方向是工厂模式&#xff09;1.1.5 日志器模块&#xff08;日志器的生成是建造者模式&#xff09;1.1.6 异步线程模块…

速度太慢,跑个分试试:AI语言模型和API性能对比;开源的高质量PDF,DOC提取工具;斯坦福TTT代码实现

✨ 1: Artificial Analysis AI语言模型和API提供商的比较分析&#xff0c;帮助用户选择最佳方案。 Artificial Analysis 是一个专门独立分析AI语言模型和API提供商的平台&#xff0c;旨在帮助用户了解AI领域并选择最适合其需求的模型和API提供商。以下是该平台的主要内容和功…

无法加载文件 xxxx 因为在此系统上禁止运行脚本。有关详细信息,请参阅,Windows执行策略有关问题

无法加载文件 xxxx 因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅&#xff0c;Windows执行策略有关问题 1.1 出现问题 在Windows11中的Windows PowerShell执行一些前端的命令时经常会出现如下问题&#xff1a; PS C:\Users\Admin\Desktop> vue init webpa…

QListWidget、QTreeWidget、QTableWidget的拖放

QListWidget、QTreeWidget、QTableWidget的拖放实验 QAbstractItemView::DragDropMode 的枚举值 QAbstractItemView::NoDragDrop0组件不支持拖放操作QAbstractItemView::DragOnly1组件只支持拖动操作QAbstractItemView::DropOnly 2组件只支持放置操作QAbstractItemView::DragDr…

UI Toolkit generateVisualContent的使用

方法描述: Called when the VisualElement visual contents need to be (re)generated. When this delegate is handled, you can generate custom geometry in the content region of the VisualElement. For an example, see the MeshGenerationContext documentation. This…