当前位置: 首页 > news >正文

Python编程-二万字浅谈装饰器原理与装饰器设计模式和函数式编程案例讲解

Python编程-浅析装饰器原理与装饰器设计模式和函数式编程案例讲解

本文制作时基于Python3.11.8Python3.12.1,存在谬误,请联系修改,希望对你有所帮助

什么是函数式编程

函数式编程(Functional Programming)是一种编程范式,它将计算视为数学函数的计算,并避免了状态改变以及可变数据。在函数式编程中,函数被视为一等公民,意味着它们可以像其他数据类型一样被传递、返回和操作。

以下是函数式编程的一些主要特征:

  1. 纯函数(Pure Functions):纯函数指的是函数的输出仅由输入决定,不会对外部状态产生影响,也不依赖外部状态。相同的输入总是产生相同的输出,这种特性使得纯函数易于理解、测试和并行化。

  2. 不可变性(Immutability):在函数式编程中,数据是不可变的,即一旦创建就不可更改。这意味着一旦数据被创建,就不能被修改,而是通过创建新的数据来代替。

  3. 无副作用(Side-effect free):函数式编程尽量避免副作用,即对系统外部环境造成的影响。这意味着函数不会修改外部状态,包括修改全局变量、执行 I/O 操作等。

  4. 高阶函数(Higher-order Functions):函数式编程支持高阶函数,即函数可以作为参数传递给其他函数,或者从其他函数返回。

  5. 递归(Recursion):递归是函数式编程中常见的一种迭代方式,用于替代循环。

  6. 惰性计算(Lazy Evaluation):函数式编程支持惰性计算,即只有在需要时才会计算表达式的值,这种特性在处理无限数据结构时特别有用。

函数式编程的优势包括代码简洁、可读性强、易于测试和并行化。它在处理并发编程、大数据处理、分布式系统等方面具有很好的适用性。常见的函数式编程语言包括Haskell、Clojure、Scala、Erlang等。此外,现代编程语言如Python、JavaScript和Java等也提供了一些函数式编程的特性和支持。

什么是高阶函数

在Python中函数名可以作为参数进行传递,例如多线程中的方法包装:

def function_name():passthread = Thread(target=function_name)

由于函数名可以作为一个参数进行传递,于是python中存在将一个函数传递给另一个函数的函数被称为高阶函数:

def print_hello(hint_string) -> None:print('Hello '+ hint_string)def start_func(other_func) -> None:other_func('World')start_func(print_hello)

上述的start_func即为高阶函数,这个和PHP是较为类似的,也可以理解为C语言中的函数指针

高阶函数匿名函数使用案例

Lambda 表达式是 Python 中的一种匿名函数,它允许快速定义简单的函数,而不需要使用 def 定义函数的形式。Lambda 表达式的语法如下:

lambda arguments: expression

其中:

  • lambda:关键字,表示定义 lambda 表达式。
  • arguments:函数的参数,可以是零个或多个参数,与普通函数一样,但不允许使用默认参数值或可变参数。
  • expression:函数体,表示函数的返回值。

Lambda 表达式通常用于需要一个函数作为参数的情况,比如在高阶函数中,例如 map()filter()sorted() 等函数中,或者在需要临时定义一个简单函数的地方。

例如使用 Lambda 表达式定义一个简单的函数,计算两个数的和:

add = lambda x, y: x + y
print(add(3, 4))  # 输出:7

高阶函数map使用案例

map函数接收一个函数名和一个或多个可迭代对象,返回的是一个map对象,并且map对象实现了可迭代协议:

def calculate_func(num: int) -> int:return abs(num) ** 2num_list: list[int] = [1, 2, 4, -5, -9]res_list: list[int] = list(map(calculate_func, num_list))print(res_list)
for i in map(calculate_func, num_list): # 借助可迭代协议进行迭代的方式print(i)

在上述操作中,map函数会将可迭代对象的每个元素逐个递交由第一个参数所指定的函数进行处理,然后返回一个map对象供我们操作

并且需要注意的是,除了第一个参数指定为函数名,后面的可迭代对象的参数将逐个以位置形参的形式传递给函数名:

def calculate_func(list1_var: int, list2_var: int) -> int:return list1_var + list2_varnum_list1: list[int] = [1, 2, 4, -5, -9]
num_list2: list[int] = [1, 7, 4, -6, -9]res_list: list[int] = list(map(calculate_func, num_list1, num_list2))print(res_list)

高阶函数reduce使用案例

位于functools中的reduce接收三个参数,第一个参数必须为两个参数的函数名;第二个参数必须是一个可迭代的对象;第三个参数用于指定初始值,它是一个可选值,未指定值时时使用可迭代对象的第一个参数为基准,指定后则以指定的值为基准值。reduce函数用来将函数运算的结果进行累计,即将函数运算的结果累计作为下一次运算的第一个参数,可迭代对象的下一个值将自动作为第二参数继续运算,直到可迭代对象迭代结束。

from functools import reducedef calculate_func(num1: int, num2: int) -> int:return num1 + num2num_list: list[int] = [1, 8, 4, -5, -9]res_list: int = reduce(calculate_func, num_list)print(res_list)

在上述代码中,未指定初始值,基准为传入列表的第一个值作为基准,进入函数作为第一参数,运算时列表的第二个元素作为函数的第二参数,下面我们看指定初始值的情况,(我这里使用了lambda表达式):

from functools import reducenum_list: list[int] = [1, 8, 4, -5, -9]res: int = reduce(lambda x, y: x+y, num_list, 25)print(res)

高阶函数filter的使用案例

filter() 是 Python 中的一个内置函数,用于过滤序列(列表、元组、集合等)中的元素。filter() 函数接受一个函数和一个可迭代的序列作为参数,并返回一个由符合条件的元素组成的迭代器。该函数在每次迭代时,都会将序列中的元素传递给指定的函数,如果函数返回值为 True,则该元素将被保留,否则将被过滤掉。

from functools import reducedef is_pos_neg_num(num: int) -> bool:if num > 0 :return Trueelse :return Falsenum_list: list[int] = [1, 8, 4, -5, -9, 5, -8]res = list(filter(is_pos_neg_num, num_list))print(res)

还可以用来过滤字符串中的值,这里以去除空格为例:

from functools import reduceoriginal_string = 'Hello World Python Java CPP'res: str = ''.join(list(filter(lambda x: False if x == ' ' else True, original_string)))print(res)

高阶函数sorted使用案例

sorted() 是 Python 中的一个内置函数,用于对可迭代对象进行排序操作。它接受一个可迭代对象作为参数,并返回一个新的已排序的列表,sorted还有两个关键字参数:

  • key(可选):用于指定排序的比较函数。默认为 None,表示直接对元素进行比较排序。如果指定了 key,则 sorted() 函数将会以 key 函数的返回值作为排序的依据。
  • reverse(可选):指定排序的顺序,如果设置为 True,则降序排序;如果设置为 False(默认值),则升序排序。
words = ["banana", "apple", "orange", "grape", "kiwi"]res = sorted(words, key=len, reverse=True)print(res)

如上示例,我们以指定以字符串长度为比较依据,并且置为逆序

高阶函数偏函数使用案例

Python 中的偏函数(Partial Function)是指使用 functools.partial 函数对现有函数创建一个新的函数,固定该函数的部分参数。在需要多次调用同一个函数但又希望保持某些参数不变的情况下非常有用(使用函数默认值也可以实现)。

from functools import partialdef get_greeting(name, sentence):return 'Hello!!! ' + str(name) + ',' + str(sentence)get_greeting_default = partial(get_greeting, sentence='You are the real IKUN')print(get_greeting_default('kun'))
print(get_greeting_default('kunkun'))

使用此方法,更多时候是需要重写自己不方便修改的部分,例如在使用bytes对象转换时需要使用指定编码时,或使用int时指定转换进制:

gbk_bytes = partial(bytes, encoding='gbk')
binary_int = partial(int, base=2)

高阶函数闭包函数与使用案例

闭包(Closure)是函数式编程中的一个重要概念(闭包实质上也是一种高阶函数),也在 Python 中得到了支持。闭包指的是一个函数对象,该函数可以访问并操作其创建时所在的作用域中的变量,即使这些变量在函数被调用之后已经不存在了。在 Python 中,闭包通常由内部函数和外部函数组成。内部函数可以访问外部函数中定义的变量(一般定义闭包就是需要访问外部函数的变量或参数),即使外部函数已经执行完毕并且不再存在。

def outer_function(x):def inner_function(y):return x + yreturn inner_functionclosure = outer_function(5)
print(closure(3))

在这个示例中,outer_function 是外部函数,它接受一个参数 x。内部函数 inner_function 可以访问外部函数 outer_function 中的变量 x。当调用 outer_function(5) 后,它返回了一个闭包 closure,此时 x 被赋值为 5。当调用 closure(3) 时,内部函数 inner_function 访问了外部函数中的变量 x,并且将 3 加上了 x,得到了 8

闭包的优点之一是它可以保持外部函数的状态,这使得它允许函数在每次调用时记住它所处的上下文,并且可以在之后的调用中使用这个上下文。

需要注意的是,闭包可能会导致内存泄漏,因为闭包中引用的外部变量会被保留,即使它们不再被使用。因此,应该小心使用闭包,并确保在不需要时适时释放资源。

利用闭包求解任意点到固定点之间的距离:

from typing import Callable
import mathdef set_fixed_point(x1, y1) -> Callable[[int, int], float]:def get_distance(x2, y2) -> float:return math.sqrt((x1 - x2)**2 + (y1 - y2)**2)return get_distancedistance = set_fixed_point(0, 0)
print(distance(2, 2))

多个内部函数闭包使用案例

Python允许在一个函数中创建多个内部函数。在 Python 中,函数是一级对象,因此可以像任何其他对象一样在函数内部进行定义、传递和返回。需要注意的是:每个内部函数都会占用内存空间,如果定义了大量的内部函数,可能会导致内存占用过多

当在一个函数中定义了多个内部函数时,可以通过调用外部函数来获取对应的内部函数。每个内部函数在外部函数被调用时都会重新创建,因此每次调用外部函数都会得到新的内部函数实例,并且它们之间是相互独立的,互不影响。

def outer_function():def inner_function1():return "This is inner function 1"def inner_function2():return "This is inner function 2"return inner_function1, inner_function2# 调用外部函数获取内部函数
func1, func2 = outer_function()# 分别调用内部函数
print(func1())  
print(func2()) 

在这个示例中,outer_function 中定义了两个内部函数 inner_function1inner_function2。通过调用 outer_function,我们得到了对应的内部函数实例 func1func2。然后,我们可以像普通函数一样调用这些内部函数。

多重闭包函数使用案例

既然闭包允许函数并列成为内部函数,自然套娃也是可以的:

def outer_function():def inner_function1():def inner_function2():print("This is inner function 2")print("This is inner function 1")return inner_function2return inner_function1func1 = outer_function()
func2 = func1()
func2()

这一点在多重装饰器上将会体现出来

使用闭包添加新的功能

在项目维护与功能添加中,如果要获取一些关键节点的信息,直接修改已有的项目代码显然是不够方便的,此时我们可以使用闭包来更新功能:

from typing import Callable
from time import asctimedef running_function() -> str:print("This is running function")def create_logs(func: Callable) -> None:with open('log.txt', 'a', encoding='utf-8') as file:file.write(str(func.__name__) + '  ' + asctime() + '\n')def outer_function(func) -> Callable[[None], str]:def inner_function() -> None:create_logs(func)func()return inner_functionfunc_start = outer_function(running_function)()

在 Python 中,__name__ 是一个特殊的内置变量,它用于获取当前模块的名称。当 Python 文件作为主程序直接执行时,__name__ 的值为 '__main__';而当 Python 文件被导入为模块时,__name__ 的值为该模块的名称。这个特性常用于将一些代码块标记为主程序或模块中的一部分,以便在需要时能够灵活地执行或导入模块,而不会对整个脚本产生副作用。

需要注意的是,__name__可以用于获取当前模块的名称,但不仅限于获取模块名称,还可以用于其他一些情况,如获取函数名等。t下面是用于模板渗透时的常见方式:

获取内容使用方法
模块名__name__
函数名function.__name__
类名self.__class__.__name__
方法名method.__name__
类的模块名self.__module__

闭包函数的作用域特性

闭包函数的作用域问题是指内部函数(闭包函数)可以访问外部函数的变量,而外部函数无法直接访问内部函数的变量。这种作用域链的特性使得闭包函数可以在其定义时捕获外部作用域的变量,并在稍后的调用中保持对这些变量的引用。

具体来说,当内部函数引用外部函数的变量时,Python 解释器会在内部函数的作用域中查找这些变量。如果在内部函数的作用域中找不到对应的变量,则会继续向上一级作用域查找,直到找到或者到达全局作用域。这样就形成了闭包函数可以访问外部函数作用域中的变量的效果。闭包函数的作用域具有以下几个特点:

  1. **捕获外部变量:**闭包函数可以在其定义时捕获外部作用域的变量,并在稍后的调用中保持对这些变量的引用,即使外部函数已经执行完毕,这些变量依然存在于闭包函数的作用域中。

  2. **保持状态:**由于闭包函数可以访问外部函数作用域中的变量,并且这些变量在闭包函数调用之间保持不变,因此闭包函数可以用来实现状态的保持,例如计数器、缓存等。

  3. **避免全局污染:**使用闭包函数可以避免将变量声明为全局变量,从而减少了全局作用域的变量污染和命名冲突的可能性。

即闭包中的内部函数中的字段对于外部是不可见的,内部函数却可以捕获外面的字段,这保证了内部数据的完整性,不过需要注意的是,内部函数一般不用于修改外部内容

编程语言中的的对象级别

在 Python 中,常见的对象级别大致上可以分为两个(实质上并无明确规定)

一级对象的特征

一级对象(First-class object)是指在编程语言中,能够作为普通对象使用的实体。具有一级对象特性的对象可以被传递给函数、存储在变量中、作为函数的返回值、放在数据结构中等。在 Python 中,函数、类、模块、数字、字符串、列表、字典等都是一级对象。

  1. 可赋值性(Assignability):一级对象可以被赋值给变量,并且可以存储在数据结构中。
  2. 作为函数参数(Passability as arguments):一级对象可以作为函数的参数传递给其他函数。
  3. 作为函数返回值(Returnability from functions):一级对象可以作为函数的返回值返回给调用者。
  4. 可以存储在数据结构中(Storability in data structures):一级对象可以被存储在列表、字典、集合等数据结构中。

二级对象的特征

二级对象通常指的是某些限制了一定程度使用和支持的对象在一些编程语言中,二级对象可能不能作为函数的参数、返回值或存储在数据结构中,或者有其他限制。在 Python 中,常见的二级对象可能是一些特殊的内置类型或对象,例如文件对象、生成器对象等,它具有以下特点:

  1. 部分支持作为函数参数和返回值:某些对象可能不支持作为函数的参数或返回值,或者只能作为参数而不能作为返回值。
  2. 部分支持存储在数据结构中:某些对象可能不能被直接存储在数据结构(例如列表、字典)中,或者只能在特定的上下文中存储。
  3. 有限的操作和功能:某些对象可能只支持有限的操作和功能,而不能像一级对象那样支持全部的操作。
  4. 具有特定的使用限制或约束:某些对象可能有特定的使用限制或约束,可能需要满足特定的条件才能使用或进行操作。

装饰器的概念与自定义方式

装饰器(Decorator)是一种Python语法特性,它允许在不修改原始函数或类定义的情况下,动态地添加功能或修改其行为。装饰器本质上是一个函数,它期望接受一个函数作为输入,并返回一个新的函数作为输出。需要注意的是,装饰器函数必须定义在被装饰的函数被之前

装饰器通常用于以下几个方面:

  1. **代码重用:**可以使用装饰器将一些通用的功能分离出来,并将其应用于多个函数或方法,从而实现代码重用。

  2. **日志记录:**通过装饰器可以在函数执行前后添加日志记录功能,记录函数的调用时间、参数、返回值等信息。

  3. **权限检查:**装饰器可以用于检查用户权限,例如验证用户是否具有执行特定函数的权限。

  4. **性能测试:**可以使用装饰器来测量函数的执行时间,以便进行性能分析和优化。

  5. **异常处理:**装饰器可以用于捕获函数中的异常,并进行适当的处理或记录。

装饰器的语法使用 @ 符号,将装饰器函数放在被装饰函数之前。例如:

def my_decorator(function):def wrapper():print("Something is happening before the function is called.")function()print("Something is happening after the function is called.")return wrapper@my_decorator
def say_hello():print("Hello! World")say_hello()

在上面的例子中,say_hello 函数被 my_decorator 装饰器修饰,当调用 say_hello 函数时,实际上是调用了装饰器中的 wrapper 函数,从而实现了在函数执行前后添加额外的功能。

装饰器与闭包的关系

装饰器和闭包在 Python 中常常一起使用,它们之间有一定的联系,但也有一些区别。下面是它们之间的关系:

  1. **装饰器使用闭包:**装饰器本质上是一个接受函数作为参数并返回一个新函数的函数。通常情况下,装饰器内部会定义一个嵌套函数,也就是闭包,在这个闭包中可以访问外部函数的变量和参数。这个闭包函数通常用来包装原始函数,以便添加额外的功能。

  2. **闭包不一定是装饰器:**闭包是指内部函数可以访问外部函数的作用域,形成了一个封闭的作用域。闭包并不一定与装饰器结合使用,它可以用于各种目的,如延迟执行、保存状态等。

  3. **装饰器提供了一种更方便的语法来使用闭包:**使用装饰器可以更方便地将闭包应用于函数上,而不需要显式地调用闭包函数。装饰器的语法简洁明了,更符合 Pythonic 风格。

  4. **装饰器可以串联使用多个闭包:**由于装饰器可以叠加使用,一个函数可以被多个装饰器修饰,这样就形成了多个闭包嵌套的情况,这为函数添加多个不同的功能提供了便利。

装饰器的执行逻辑

从装饰器的概念来讲,本质上是闭包函数多了一个自动执行的过程。即使我们不执行传递进入的函数,不过被返回的内部函数将会在返回后被执行,正如下面的代码:

def decorator(func):print('This function is started: ', decorator.__name__)def inner_func1():print('This function is started: ', inner_func1.__name__)return inner_func1@decorator
def func():print('This function is started: ', func.__name__)func()

我们将的到如下运行结果:

This function is started:  decorator
This function is started:  inner_func1

即装饰器的实质调用链在此为decorator(func)(),我们去掉print内容再来观察进行装饰时Python虚拟机的字节码:

2           2 LOAD_CONST               0 (<code object decorator at 0x0000023D0A57D7C0, file "<string>", line 2>)4 MAKE_FUNCTION            06 STORE_NAME               0 (decorator)7           8 LOAD_NAME                0 (decorator)8           10 LOAD_CONST              1 (<code object func at 0x0000023D0A355470, file "<string>", line 7>)12 MAKE_FUNCTION           07           14 PRECALL                 018 CALL                    08           28 STORE_NAME              1 (func)

Python虚拟机依次进行了以下操作:

  1. LOAD_CONST: 将常量加载到栈顶。在这里,常量 <code object decorator at 0x0000023D0A57D7C0, file "<string>", line 2> 被加载到栈顶。
  2. MAKE_FUNCTION: 使用栈顶的常量创建一个函数对象,并将其推送到栈顶。在这里,栈顶的常量是之前加载的 <code object decorator at 0x0000023D0A57D7C0, file "<string>", line 2>
  3. STORE_NAME: 将栈顶的函数对象存储到名为 “decorator” 的变量中。
  4. LOAD_NAME: 将名为 “decorator” 的变量加载到栈顶。
  5. LOAD_CONST: 再次加载一个常量到栈顶。在这里,常量 <code object func at 0x0000023D0A355470, file "<string>", line 7> 被加载到栈顶。
  6. MAKE_FUNCTION: 创建一个函数对象并将其推送到栈顶。与之前类似,栈顶的常量是 <code object func at 0x0000023D0A355470, file "<string>", line 7>
  7. PRECALL: 进行函数调用之前的预调用操作。
  8. CALL: 执行函数调用操作。
  9. STORE_NAME: 将函数调用的结果存储到名为 “func” 的变量中。

则我们可以得出结论,在上述的代码中:

@decorator实质上执行的过程为在定义函数时执行了类似于func = decorator(func)的操作

多重装饰器包装方法

使用多个装饰器进行包装时,直接在被包装函数前以多个@进行引入即可,如下示例:

def my_decorator_one(function):def wrapper_one():print("Something is happening before the function is called.", '---by decorator one')function()print(function.__name__ + ' is started')print("Something is happening after the function is called.",  '---by decorator one')return wrapper_onedef my_decorator_two(function):def wrapper_two():print("Something is happening before the function is called.", '---by decorator two')function()print(function.__name__ + ' is started')print("Something is happening after the function is called.", '---by decorator two')return wrapper_two@my_decorator_one
@my_decorator_two
def say_hello():print("Hello! World")say_hello()

需要注意的是,运行后的结果:

Something is happening before the function is called. ---by decorator one
Something is happening before the function is called. ---by decorator two
Hello! World
say_hello is started
Something is happening after the function is called. ---by decorator two
wrapper_two is started
Something is happening after the function is called. ---by decorator one

可见程序是先执行的第一个装饰器,然后将第二个装饰器作为了第一个装饰器装饰的方法,然后第二装饰器装饰了被包装方法,即出现了嵌套的装饰器,即多重闭包

包装需要参数的函数或方法

与定义闭包函数时是类似的,我们要想包装需要参数的方法或函数,只需要将装饰器内部的函数定义为接收对应参数数量即可

def decorator(function):def inner_function(*args):print('This is inner of decorator')function(*args)return inner_function@decorator
def connect_two_string(string1, string2):print(string1 + string2)connect_two_string('Hello', 'World!!!')

向装饰器传递额外的参数

不难看出,装饰器的本质上依然是闭包函数,那么既然是函数,我们就可以为其传递参数,并在其中使用参数或进行更加复杂的操作

def decorator(*call_word):print(decorator.__name__ + ' is started')def inner_function(function):print(inner_function.__name__ + ' is started')def core_function(*args):print(core_function.__name__ + ' is started')function(*args)print(inner_function.__name__ + ' ' + str(call_word))return core_functionreturn inner_function @decorator('Welcome to Python!!!')
def connect_two_string(string1, string2):print(string1 + string2)connect_two_string('Hello', 'World!!!')

运行结果如下:

decorator is started
inner_function is started
inner_function ('Welcome to Python!!!',)
core_function is started
HelloWorld!!!

即在我们需要在装饰器使用额外的数据时,我们需要使用多重闭包,在第一层闭包中返回一个装饰器,所以上述代码的调用链应该是这样的:

decorator('Welcome to Python!!!')(connect_two_string)('Hello', 'World!!!')

字节码中也是这样操作的:

0           0 RESUME                   02           2 LOAD_CONST               0 (<code object decorator at 0x000002D462405F00, file "<string>", line 2>)4 MAKE_FUNCTION            06 STORE_NAME               0 (decorator)14           8 PUSH_NULL10 LOAD_NAME                0 (decorator)12 LOAD_CONST               1 ('Welcome to Python!!!')14 PRECALL                  118 CALL                     115          28 LOAD_CONST               2 (<code object connect_two_string at 0x000002D462411C50, file "<string>", line 14>)30 MAKE_FUNCTION            014          32 PRECALL                  036 CALL                     015          46 STORE_NAME               1 (connect_two_string)18          48 PUSH_NULL50 LOAD_NAME                1 (connect_two_string)52 LOAD_CONST               3 ('Hello')54 LOAD_CONST               4 ('World!!!')56 PRECALL                  260 CALL                     270 POP_TOP72 LOAD_CONST               5 (None)74 RETURN_VALUE

在进行装饰的过程中多了一步:12 LOAD_CONST 1 ('Welcome to Python!!!'),而后在闭包的第二层,也就是装饰器所在处执行了以下内容,返回了一个装饰器:

15          28 LOAD_CONST               2 (<code object connect_two_string at 0x000002D462411C50, file "<string>", line 14>)30 MAKE_FUNCTION            014          32 PRECALL                  036 CALL                     015          46 STORE_NAME               1 (connect_two_string)

装饰器的嵌套行为

既然闭包都能嵌套,那么装饰器不能进行嵌套,可太不合理了,不过这样可能会引起代码逻辑过于混乱,不建议尝试,有时显得低效且冗余:

def decorator_one(func):def inner_func(x, y):func(abs(x), abs(y))return inner_funcdef decorator_two(func):@decorator_onedef inner_func(x, y):func(x-1, y-1)return inner_func@decorator_two
def sum(x, y):print(x+y)sum(-6, 6)

实现智能装饰器案例讲解

经过上述的内容,我们会注意到一个问题,装饰器大致分为三种调用情况:

@decorator	# 直接装饰函数
@decorator()	# 装饰器本身使用了参数默认值
@decorator(..., ...)	# 装饰器传递了所有或合法参数

怎样实现在三种情况下都可以使用同一个装饰器来进行装饰呢?其实智能装饰器就是实现了情况判断的闭包函数

def decorator(*args, **kwargs):# 处理装饰器参数if len(args) == 1 and callable(args[0]): func = args[0]def wrapper(*func_args, **func_kwargs):print('#' * 20)result = func(*func_args, **func_kwargs)print('#' * 20)return resultreturn wrapperelse:# 如果装饰器本身使用了参数默认值,或传递了参数,则在这里处理def actual_decorator(func):def wrapper(*func_args, **func_kwargs):print('-' * 20)print("Decorator args:", args)print("Decorator kwargs:", kwargs)result = func(*func_args, **func_kwargs)print('-' * 20)return resultreturn wrapperreturn actual_decorator# 使用装饰器来装饰函数
@decorator
def function():print("Inside function")@decorator()  # 装饰器本身使用了参数默认值
def function_with_default():print("Inside function_with_default")@decorator("arg1", key="value")  # 装饰器传递了所有或部分合法参数
def function_with_args():print("Inside function_with_args")# 调用
function()
print()
function_with_default()
print()
function_with_args()

wraps装饰器使用案例

在Python中,wraps装饰器是一个用于创建装饰器的辅助函数,通常与装饰器一起使用以保留原始函数的元数据(例如函数名称、文档字符串、参数签名等)。这对于调试和日志记录非常有用,因为它能够保留原始函数的信息,而不是让被装饰的函数看起来像是另一个函数。

wraps装饰器位于functools模块中。通常,编写一个装饰器会在内部定义一个包装函数,并在这个包装函数内部对被装饰的函数进行一些操作。使用@wraps装饰器来装饰这个包装函数,这样可以确保原始函数的元数据被正确传递到包装函数。需要注意的是,使用它时必须传入指定的函数名作为参数,这也表明了其使用位置必须是装饰器中使用外部函数的内部函数,而不是装饰器函数本身:

from functools import wrapsdef decorator(*call_word):print(decorator.__name__ + ' is started')def inner_function(function):print(inner_function.__name__ + ' is started')@wraps(function)def core_function(*args):print(core_function.__name__ + ' is started')function(*args)print(inner_function.__name__ + ' ' + str(call_word))return core_functionreturn inner_function @decorator('Welcome to Python!!!')
def connect_two_string(string1, string2):print(string1 + string2)connect_two_string('Hello', 'World!!!')

此时得到运行结果中,获取的core_function已经变成了外部函数名:

decorator is started
inner_function is started
inner_function ('Welcome to Python!!!',)
connect_two_string is started
HelloWorld!!!

什么是Python元数据

在Python中,元数据是指与对象相关的描述性信息,它包括但不限于以下内容:

  1. 函数名称(__name__:函数的名称。
  2. 模块名称(__name__:模块的名称。
  3. 文档字符串(__doc__:函数、类、模块或方法的文档字符串,提供了有关对象的描述和说明。
  4. 参数签名(__annotations__:函数或方法的参数和返回值的注释。
  5. 函数参数列表(__code__.co_varnames:函数的参数列表。
  6. 函数字节码(__code__.co_code:函数的字节码指令序列。
  7. 类名称(__name__:类的名称。
  8. 类文档字符串(__doc__:类的文档字符串,提供了有关类的描述和说明。
  9. 类属性和方法(__dict__:类的属性和方法字典。
  10. 模块级别的全局变量和函数(globals():模块中定义的全局变量和函数。
  11. 类级别的方法(__dict__:类中定义的方法,存储在类的字典中。
  12. 类继承关系(__bases__:类的直接父类。
  13. 模块级别的导入信息(__path__, __file__等):模块的导入路径、文件路径等信息。

利用Callable特性实现装饰器类

在Python中,callable是一个特性,用于检查一个对象是否可以被调用(即是否可作为函数调用)。如果一个对象是可调用的,则可以像调用函数一样使用它,通过在对象名后面加上一对圆括号,并且可以传递参数给它。在Python中,函数、类(如果定义了 __call__ 方法)、类的实例(如果定义了 __call__ 方法)以及其他一些对象都是可调用的。通过使用内置函数 callable(),你可以检查对象是否是可调用的。当你调用 callable() 并将一个对象作为参数传递给它时,如果该对象是可调用的,它将返回 True,否则返回 False

from functools import wrapsclass CustomDecorator:def __init__(self, arg1, arg2):self.arg1 = arg1self.arg2 = arg2def __call__(self, func):@wraps(func)def wrapped_func(*args, **kwargs):print("Decorator arguments:", self.arg1, self.arg2)result = func(*args, **kwargs)print('This is function: ', wrapped_func.__name__)return resultreturn wrapped_func@CustomDecorator("Hello", "World")
def my_function():print("Inside the function")if callable(CustomDecorator):my_function()

设计模式之装饰器模式

所谓装饰,就是不能更改被装饰对象、类或者函数的原有的行为,在这些原有的行为上,添加一些扩展行为,来实现装饰的目的。

在设计模式中,装饰器模式是一种通用的解决方案,它的思想可以被用于设计实现中,但实际上并不一定需要使用 Python 中的装饰器语法来实现。

装饰器模式是一种结构型设计模式,它允许动态地为一个对象添加新的功能,而无需改变其原始类的结构。这种模式通过将对象放入一个包装器中来实现,该包装器包含了要添加的额外功能。在装饰器模式中,通常会有以下角色:

  1. 组件接口(Component Interface):定义了被装饰对象和装饰器共同实现的接口或抽象类。它是被装饰对象和装饰器的共同父类。

  2. 具体组件(Concrete Component):实现了组件接口,它是被装饰的原始对象。

  3. 装饰器(Decorator):也实现了组件接口,它包含了一个对组件的引用,并且可以通过该引用动态地添加额外的功能。

  4. 具体装饰器(Concrete Decorator):扩展了装饰器类,添加了具体的附加功能。

考虑一个简单的示例:假设我们有一个 Coffee 类,代表一杯咖啡,它有一个方法 cost() 来计算咖啡的价格。我们希望能够动态地为咖啡添加额外的配料,如奶油、糖浆等,而不需要修改 Coffee 类本身。

# 组件接口
class Coffee:def cost(self):pass# 具体组件
class SimpleCoffee(Coffee):def cost(self):return 5# 装饰器
class CoffeeDecorator(Coffee):def __init__(self, decorated_coffee):self.decorated_coffee = decorated_coffeedef cost(self):return self.decorated_coffee.cost()# 具体装饰器
class Milk(CoffeeDecorator):def cost(self):return self.decorated_coffee.cost() + 2class Sugar(CoffeeDecorator):def cost(self):return self.decorated_coffee.cost() + 1

在这个示例中,Coffee 是组件接口,SimpleCoffee 是具体组件,CoffeeDecorator 是装饰器,而 MilkSugar 是具体装饰器。现在,我们可以创建一个咖啡对象,并动态地添加配料:

coffee = SimpleCoffee()
print(coffee.cost())coffee_with_milk = Milk(coffee)
print(coffee_with_milk.cost()) coffee_with_milk_and_sugar = Sugar(coffee_with_milk)
print(coffee_with_milk_and_sugar.cost())

通过装饰器模式,我们可以在不修改原始 Coffee 类的情况下,动态地添加额外的功能,使得代码更加灵活和可维护。

相关文章:

Python编程-二万字浅谈装饰器原理与装饰器设计模式和函数式编程案例讲解

Python编程-浅析装饰器原理与装饰器设计模式和函数式编程案例讲解 本文制作时基于Python3.11.8与Python3.12.1&#xff0c;存在谬误&#xff0c;请联系修改&#xff0c;希望对你有所帮助 什么是函数式编程 函数式编程&#xff08;Functional Programming&#xff09;是一种编程…...

基于Zigbee的智能温室大棚系统(附详细使用教程+完整代码+原理图+完整课设报告)

🎊项目专栏:【Zigbee课程设计系列文章】(附详细使用教程+完整代码+原理图+完整课设报告) 前言 👑由于无线传感器网络(也即是Zigbee)作为🌐物联网工程的一门必修专业课,具有很强的实用性,因此很多院校都开设了zigbee的实训课程;👑同时最近很多使用了我的单片机课…...

【Web】Redis未授权访问漏洞学习笔记

目录 简介 靶机配置 Redis持久化 Redis动态修改配置 webshell 反弹shell Redis写入反弹shell任务 加固方案 简介 Redis&#xff08;Remote Dictionary Server 远程字典服务器&#xff09;是一个开源的内存数据库&#xff0c;也被称为数据结构服务器&#xff0c;它支持…...

【JAVA WEB】 css背景属性 圆角矩形的绘制

目录 背景属性设置 圆角矩形 背景属性设置 背景颜色,在style中 background-color:颜色&#xff1b; 背景图片 background-image:url(……) 背景图片的平铺方式 background-repeat: 平铺方式 repeat 平铺&#xff08;默认&#xff09;no-repeat 不平铺repeat-x 水平平铺repea…...

Docker-现代化应用部署的利器

一、容器部署的发展 今天我们来说说容器部署。我们知道容器部署的发展大致分三个阶段&#xff0c;下面来介绍一下不同阶段的部署方式的优缺点 物理机部署 优点是可以提供更高的性能、资源控制&#xff0c;也可以提供更好的数据隔离和安全性&#xff0c;因为不同的应用程序运行在…...

「优选算法」:山脉数组的峰顶索引

一、题目 符合下列属性的数组 arr 称为 山脉数组 &#xff1a; arr.length > 3存在 i&#xff08;0 < i < arr.length - 1&#xff09;使得&#xff1a; arr[0] < arr[1] < ... arr[i-1] < arr[i] arr[i] > arr[i1] > ... > arr[arr.length - 1] …...

网络安全红队基础建设与介绍

1.ATT&CK相关背景 ATT&CK在各种日常环境中都很有价值。开展任何防御活动时&#xff0c;可以应用ATT&CK防御法&#xff0c;参考攻击者及其行为。ATT&CK不仅对网络防御者提供通用技术库&#xff0c;还为渗透测试和红队提供了基础。提到对抗行为时&#xff0c;这为…...

Java语法学习反射

Java语法学习反射 大纲 基本介绍class的介绍 具体案例 1. 基本介绍 流程图&#xff08;程序在计算机的阶段&#xff09; 反射的主要的类 这个提高效率不大 2. class的介绍 对于第三点&#xff1a;首先类只会加载一次&#xff0c;得到的class的对象&#xff0c;也只有一…...

【MySQL】操作库 —— 库的操作 -- 详解

一、增删数据库 1、创建数据库 create database db_name; 本质就是在 /var/lib/mysql 创建一个目录。 说明&#xff1a; 大写的表示关键字。[ ] 是可选项。CHARACTER SET&#xff1a;指定数据库采用的字符集。COLLATE&#xff1a;指定数据库字符集的校验规则。 2、数据库删除…...

Rust安装——Win10

安装步骤 1、下载RUSTUP-INIT.EXE&#xff08;64-BIT&#xff09; 2、由于国外源下载依赖太慢&#xff0c;因此建议增加win10环境变量配置国内源&#xff0c;增加RUSTUP_DIST_SERVER、RUSTUP_UPDATE_ROOT环境变量即可 RUSTUP_DIST_SERVER随便选择其中的一个源就行&#xff0c;…...

【教学类-46-07】20240212立体春字1.0

背景需求&#xff1a; 在南浔古镇的非遗文化馆里看到一个新年活动折纸——立体春字&#xff0c; 我记得这个就是一个双三角结构折纸&#xff0c;完全可以用15*15的手工纸给孩子们做一套。 折纸教程 双三角折法 【“鼠”你有才】纸艺教学 剪纸——立体春字&#xff08;2月23日…...

Python语言例题集(003)

#!/usr/bin/python3 #猜数字 import random secretNumberrandom.randint(1,20) print(‘我想了一个1到20间的整数&#xff0c;你能猜出来吗&#xff1f;’) for guessesTaken in range(1,7): print(‘猜一下&#xff01;’) guessint(input()) if guess<secretNumber: pr…...

UE5 播放本地MP3、MP4

1.创建一个媒体播放器 2.如创建视频&#xff0c;勾选。 它会多一个媒体纹理给你 3.1 设置音频 在一个actor上添加“媒体音频组件” “音频媒体播放器”赋值给它 3.2播放音频 添加一个音频媒体播放器变量&#xff0c; 赋值 地址使用绝对地址 4.1设置视频 UI上创建一个imag…...

NLP_“预训练+微调大模型”模式和Prompt/Instruct模式的异同

文章目录 “预训练微调大模型”的模式以提示/指令模式直接使用大模型“预训练微调大模型”模式和Prompt/Instruct模式的异同小结 “预训练微调大模型”的模式 经过预训练的大模型所习得的语义信息和所蕴含的语言知识&#xff0c;很容易向下游任务迁移。NLP应用人员可以根据自己…...

普通人应该如何使用GPT

现在GPT4推出的GPTs&#xff0c;包含了各个行业方向&#xff0c;比如DALL&#xff08;绘图&#xff09;、Diagrams&#xff08;图标、流程图&#xff09;、KAYAK&#xff08;航旅助手&#xff09;、Murder Mystery Mayhem&#xff08;侦探扮演&#xff09;、Canva&#xff08;设…...

pycharm像jupyter一样在控制台查看后台变量

更新下&#xff1a;这个一劳永逸不用一个一个改 https://blog.csdn.net/Onlyone_1314/article/details/109347481 右上角运行...

Ansible command命令模块 这个模块可以直接在远程主机上执行命令,并将结果返回本主机。

目录 参数介绍练习环境配置主机清单配置无密码链接ping模块 command 命令模块也可以用来安装点东西看个路径 command 指定目录来 指定命令 参数介绍 chdir    # 在执行命令之前&#xff0c;先切换到该目录 executable # 切换shell来执行命令&#xff0c;需要使用命令的绝对…...

C语言-3

定义指针 /*指针的概念:1.为了方便访问内存中的内容&#xff0c;给每一个内存单元&#xff0c;进行编号&#xff0c;那么我们称这个编号为地址&#xff0c;也就是指针。2.指针也是一种数据类型&#xff0c;指针变量有自己的内存&#xff0c;里面存储的是地址&#xff0c;也就是…...

Quartus工程的qsf配置约束文件介绍

一、qsf文件概述 qsf&#xff1a;Quartus Setting File&#xff0c;是Quartus工程的配置文件&#xff1b; 包含一个Quartus工程的所有约束&#xff0c;包括工程的软件版本信息、FPGA器件信息、引脚约分配、引脚电平分配&#xff0c;编译约束和用于Classic TimingAnalyzer的时…...

【网工】华为设备命令学习(Telnet)

本次实验AR3为我们实际中远程的路由&#xff0c;AR4模拟我们的设备&#xff0c;最终实现Telnet的远程控制路由&#xff01; 本次笔记主要记录Telnet技术实现原理&#xff0c;后续再补充具体配置代码。 Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登录服务的…...

搜索专项---最短路模型

文章目录 迷宫问题武士风度的牛抓住那头牛 一、迷宫问题OJ链接 本题思路:只需要记录各个点是有哪个点走过来的&#xff0c;就能递推得出路径。记录前驱假设从 1,1 这个点向下走到了2, 1&#xff0c;则将2,1这个点的前驱记为1,1。这样&#xff0c;将整张地图 bfs 后&#xff0c…...

安装PostgreSQL和PostGIS

安装环境 Windows 2019 Standard Server 安装PostgreSQL 安装PostgreSQL 16 安装PostGIS 用PostgreSQL 16对应的PostGIS https://download.osgeo.org/postgis/windows/pg16/ https://download.osgeo.org/postgis/windows/pg16/postgis-bundle-pg16x64-setup-3.4.1-1.exe 创建…...

MySQL-----DCL基础操作

▶ DCL简介 DCL英文全称是Data ControlLanguage(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 DCL--管理用户 ▶ 查询用户 use mysql; select * from user; ▶ 创建用户 ▶ 语法 create user 用户名主机名 identified by 密码 设置为在任意主机上访问…...

Unity报错Currently selected scripting backend (IL2CPP) is not installed

目录 什么是il2cpp il2cpp换mono Unity打包报错Currently selected scripting backend (IL2CPP) is not installed 什么是il2cpp Unity 编辑器模式下是采用.net 虚拟机解释执行.net 代码,发布的时候有两种模式,一种是mono虚拟机模式,一种是il2cpp模式。由于iOS AppStore…...

LeetCode79. Word Search——回溯

文章目录 一、题目二、题解 一、题目 Given an m x n grid of characters board and a string word, return true if word exists in the grid. The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertic…...

Linux命令-blkid命令(查看块设备的文件系统类型、LABEL、UUID等信息)

说明 在Linux下可以使用 blkid命令 对查询设备上所采用文件系统类型进行查询。blkid主要用来对系统的块设备&#xff08;包括交换分区&#xff09;所使用的文件系统类型、LABEL、UUID等信息进行查询。要使用这个命令必须安装e2fsprogs软件包。 语法 blkid -L | -U blkid [-c…...

服务治理中间件-Eureka

目录 简介 搭建Eureka服务 注册服务到Eureka 简介 Eureka是Spring团队开发的服务治理中间件&#xff0c;可以轻松在项目中&#xff0c;实现服务的注册与发现&#xff0c;相比于阿里巴巴的Nacos、Apache基金会的Zookeeper&#xff0c;更加契合Spring项目&#xff0c;缺点就是…...

Javaweb之SpringBootWeb案例之异常处理功能的详细解析

3. 异常处理 3.1 当前问题 登录功能和登录校验功能我们都实现了&#xff0c;下面我们学习下今天最后一块技术点&#xff1a;异常处理。首先我们先来看一下系统出现异常之后会发生什么现象&#xff0c;再来介绍异常处理的方案。 我们打开浏览器&#xff0c;访问系统中的新增部…...

苹果Mac键盘如何将 F1 到 F12 取消按Fn

苹果电脑安装了Win10操作系统之后&#xff0c;F1到F12用不了怎么办的解决方法。本文将介绍一些解决方法&#xff0c;帮助您解决无法使用F1到F12功能键的问题。 使用 Mac系统的人都知道&#xff0c;Mac系统默认是没有开启 F1-F12 的使用的&#xff0c;平时我们使用的系统都可以使…...

linux下ipconfig命令报:command not found 解决方法

参考博文&#xff1a; linux下ipconfig命令报:command not found 解决方法 CentOS7更新yum报Could not resolve host:mirrorlist.centos.org; Unknown error解决办法...

Android导入其它项目慢,Gradel下载失败,另辟蹊径:使用离线gradle加载,附镜像方式

最近在开发中需要测试以前写的小项目。结果忘了换本地的gradle&#xff0c;提示下载失败。换了现在用的gradle&#xff0c;项目能跑了。虽然网上有很多很多教程了&#xff0c;但对我的情况也不是都适用。所以自己记录一下。本人水平有限&#xff0c;有不对的地方请帮我指正&…...

神经语言程式(NLP)项目的15 个开源训练数据集

一个聊天机器人需要大量的训练数据,以便在无需人工干预的情况下快速解决用户的询问。然而,聊天机器人开发的主要瓶颈是获取现实的、面向任务的对话数据来训练这些基于机器学习的系统。 我们整理了训练聊天机器人所需的对话数据集,包括问答数据、客户支持数据、对话数据和多…...

H5 红色文字抖动网址发布页/引导页源码

H5 红色文字抖动网址发布页/引导页源码 源码介绍&#xff1a;一款红色文字抖动网页源码&#xff0c;可用于引导页或网址发布页。 下载地址&#xff1a; https://www.changyouzuhao.cn/10470.html...

MacOS - 菜单栏上显示『音量』

教程步骤 点击打开系统偏好『设置』&#xff0c;并找到『控制中心』 在『控制中心模块』找到『声音』&#xff0c;选择『始终在菜单栏显示』...

深入理解常见的设计模式

目录 引言 1. 单例模式&#xff08;Singleton Pattern&#xff09; 应用场景&#xff1a; 示例代码&#xff1a; . 工厂模式&#xff08;Factory Pattern&#xff09; 应用场景&#xff1a; 示例代码&#xff1a; 3. 观察者模式&#xff08;Observer Pattern&#xff09…...

服务器解析漏洞及任意文件下载

1.服务器文件解析漏洞 文件解析漏洞,是指Web容器&#xff08;Apache、nginx、iis等&#xff09;在解析文件时出现了漏洞,以其他格式执行出脚本格式的效果。从而,黑客可以利用该漏洞实现非法文件的解析。 &#xff08;1) Apache linux系统中的apache的php配置文件在/etc/apac…...

ES6扩展运算符——三个点(...)用法详解

目录 1 含义 2 替代数组的 apply 方法 3 扩展运算符的应用 &#xff08; 1 &#xff09;合并数组 &#xff08; 2 &#xff09;与解构赋值结合 &#xff08; 3 &#xff09;函数的返回值 &#xff08; 4 &#xff09;字符串 &#xff08; 5 &#xff09;实现了 Iter…...

限制资源使用

限制资源使用 您需要显示对服务器资源的访问来保护Web应用程序和应用程序数据不受未授权用户的访问。在Java EE Web应用程序中,您可以通过在应用服务器中创建用户和用户组来保护资源免受未经授权的访问。您可以为应用程序定义角色并在部署过程中将角色分配给用户。 1. 创建授权…...

结合Next项目实际认识webpack.splitChunks

本文的目的在于简单的介绍webpack的优化功能配置&#xff1a;splitChunks。 webpack5出于“开箱即用”的目的&#xff0c;将大部分曾经要使用插件的功能集成到了config配置中&#xff0c;因此用户只需要了解如何配置&#xff0c;即可达到优化目的&#xff0c;其中最常使用接触的…...

【Tauri】(2):使用Tauri应用开发,使用开源的Chatgpt-web应用做前端,使用rust 的candle做后端,本地运行小模型桌面应用

视频演示地址 https://www.bilibili.com/video/BV17j421X7Zc/ 【Tauri】&#xff08;2&#xff09;&#xff1a;使用Tauri应用开发&#xff0c;使用开源的Chatgpt-web应用做前端&#xff0c;使用rust 的candle做后端&#xff0c;本地运行小模型桌面应用 1&#xff0c;做一个免…...

C#where T :通用的泛型约束(generic constraint)语法

在C#中&#xff0c;where T :是一种通用的泛型约束&#xff08;generic constraint&#xff09;语法&#xff0c;用于限制泛型类型参数T的特定条件。通过使用泛型约束&#xff0c;我们可以对泛型类型参数进行更具体的限制&#xff0c;以确保在使用泛型时满足特定的要求。 wher…...

vue使用Mars3d弹框嵌套video视频/实时视频(m3u8)使用hls.js

下载hls.js http://mars3d.cn/lib/video/hls/hls.js下载 1.首先绘制地图我使用的天地图 async infoMars3d() {const that this;var mapOptions {scene: {center: {lat: 30.435192,lng: 103.936535,alt: 200000,heading: 359,pitch: -79},highDynamicRange: false},// 方式1&a…...

Python爬虫之Ajax数据爬取基本原理

前言 有时候我们在用 requests 抓取页面的时候&#xff0c;得到的结果可能和在浏览器中看到的不一样&#xff1a;在浏览器中可以看到正常显示的页面数据&#xff0c;但是使用 requests 得到的结果并没有。这是因为 requests 获取的都是原始的 HTML 文档&#xff0c;而浏览器中…...

osg操控器和键盘切换操控器学习

osg提供了很多操控器,在src\osgGA目录下,cpp文件名含有Manipulator的都是操控器,每个这样的cpp表示一种类型的操控器。 名字带 Manipulator 的类都是操控器; 其中KeySwitchMatrixManipulator.cpp文件实现了键盘切换操控器; 操控器是指:操控相机运动,从而实现场景视图…...

LeetCode1143. Longest Common Subsequence——动态规划

文章目录 一、题目二、题解 一、题目 Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0. A subsequence of a string is a new string generated from the original string with so…...

利用Windows10漏洞破解密码(保姆级教学)

前言: 本篇博客只是技术分享并非非法传播知识,实验内容均是在虚拟机中进行,并非真实环境 正文: 一.windows10电脑密码破解 1)开启windows10虚拟机,停留在这个页面 2&#xff09;按5次Shift键,出现这个粘滞键,如果没有出现的,则说明漏洞已经修复 3)重新启动,在这个页面的时候…...

apk反编译修改教程系列---简单修改apk默认横竖屏显示 手机端与电脑端同步演示【十一】

往期教程&#xff1a; apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】 apk反编译修改教程系列-----任意修改apk版本号 版本名 防止自动更新【二】 apk反编译修改教程系列-----修改apk中的图片 任意更换apk桌面图片【三】 apk反编译修改教程系列---简单…...

2301: 不定方程解的个数

题目描述 输出不定方程解的个数。在数学中&#xff0c;不定方程是数论中的一个重要课题&#xff0c;在各种比赛中也常常出现. 对于不定方程&#xff0c;有时我们往往只求非负整数解&#xff0c;现有方程axbyc0&#xff0c;其中x、y为未知量且不超过10000&#xff0c;当给定a、…...

vue3学习——封装菜单栏

/Layout/Sidebar/index.vue <script setup lang"ts"> import Sidebar from ./Sidebar.vue // 在下面的代码里 import { useRoute } from vue-router import useUserStore from /store/modules/user.ts // state中存放菜单数据 import useLayoutSetting from /…...

深度学习的进展及其在各领域的应用

深度学习&#xff0c;作为人工智能的核心分支&#xff0c;近年来在全球范围内引起了广泛的关注和研究。它通过模拟人脑的学习机制&#xff0c;构建复杂的神经网络结构&#xff0c;从大量数据中学习并提取有用的特征表示&#xff0c;进而解决各种复杂的模式识别问题。 一、深度…...