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

揭秘Python的魔法:装饰器的超能力大揭秘 ‍♂️✨

文章目录

  • Python进阶之装饰器详解
    • 1. 引言
      • 装饰器的概念与意义
      • 装饰器在Python编程中的作用
    • 2. 背景介绍
      • 2.1 函数作为对象
      • 2.2 高阶函数
    • 3. 装饰器基础
      • 3.1 理解装饰器
      • 3.2 装饰器的工作原理
    • 4. 带参数的装饰器
      • 4.1 为什么需要带参数
      • 4.2 实现带参数的装饰器
        • 使用函数包裹装饰器
        • 使用类实现装饰器
    • 5. 多装饰器应用
      • 5.1 多个装饰器叠加
        • 装饰器的执行顺序
        • 避免装饰器冲突的策略
      • 5.2 装饰器的组合
    • 6. 装饰器的最佳实践
      • 6.1 保持透明性
        • 保留原函数名与文档字符串
      • 6.2 类装饰器的运用
        • 类作为装饰器的优势
        • 实例绑定与类方法装饰
    • 7. 装饰器的高级话题
      • 7.1 装饰类方法
      • 7.2 动态装饰器
      • 7.3 装饰器性能考量
    • 8. 结论
      • 装饰器的核心价值总结
        • 代码复用与解耦
        • 增强函数功能
        • 提高代码可读性
      • 在项目中合理运用装饰器的建议

Python进阶之装饰器详解

1. 引言

装饰器的概念与意义

在Python的世界里,有这样一群神秘的存在,它们被称为“装饰器”。想象一下,你走进一家咖啡馆,点了一杯普通的拿铁,然后咖啡师问你:“要不要加点香草糖浆,或者来点肉桂粉?”这就是装饰器的精髓所在——它们给原本的代码添加一些额外的功能,就像给咖啡添加香草糖浆一样,让代码更加美味。

装饰器在Python编程中的作用,就像是生活中的小工具,它们小巧而实用。比如,你有一个函数,它负责打印“Hello, World!”。但突然有一天,你想让这个函数在打印之前先检查一下用户权限,或者在打印之后记录日志。这时候,装饰器就派上用场了。你不需要修改原有的函数代码,只需要简单地“装饰”一下,就能实现这些额外的功能。

装饰器在Python编程中的作用

装饰器在Python编程中的作用,就像是给你的代码穿上一件件的外衣。它们让代码更加灵活,易于扩展和维护。想象一下,如果你的代码是一栋房子,那么装饰器就是那些可以随时更换的装饰品,比如窗帘、地毯或者壁画。它们不会改变房子的结构,但却能让房子看起来更加漂亮,或者更适合居住。

在Python中,装饰器通常用于以下场景:

  • 日志记录:在函数执行前后添加日志记录。
  • 性能测试:测量函数执行时间。
  • 事务处理:确保数据库操作的原子性。
  • 权限校验:在执行函数前检查用户权限。
  • 缓存:缓存函数的结果,避免重复计算。

装饰器就像是Python编程中的瑞士军刀,多功能且强大。它们让你的代码更加模块化,易于理解和维护。而且,装饰器的使用非常灵活,你可以为同一个函数添加多个装饰器,就像给咖啡添加多种口味一样。

现在,让我们开始探索装饰器的奥秘,看看它们是如何工作的,以及如何在你的项目中合理运用它们。但别着急,就像品尝一杯好咖啡一样,我们需要一步一步来,慢慢享受这个过程。下一篇,我们将深入了解装饰器的背景和基础,揭开它们的神秘面纱。

在这里插入图片描述

2. 背景介绍

2.1 函数作为对象

在Python的魔法世界里,一切皆对象,包括我们日常打交道的函数。这就像是在哈利波特的霍格沃茨魔法学校,即使是最普通的羽毛笔,也能变成一支会飞的羽毛笔,拥有自己的魔力。在Python中,函数不仅仅是一段执行特定任务的代码,它们也可以像其他对象一样被赋值、传递和返回。

想象一下,你有一个名为print_greeting的函数,它的作用是打印一条欢迎信息。在Python中,你可以像传递任何其他对象一样,将这个函数传递给另一个函数,或者将它赋值给一个变量。这就像是将羽毛笔交给另一个巫师,或者将它放在你的魔法背包里。

def print_greeting(name):print(f"Hello, {name}! Welcome to the world of Python decorators!")# 将函数赋值给一个变量
greet = print_greeting# 通过变量调用函数
greet("Harry")

在这个例子中,我们创建了一个函数print_greeting,然后将其赋值给变量greet。之后,我们通过变量greet来调用这个函数,就像直接调用print_greeting一样。这就是函数作为对象的魔力所在。

2.2 高阶函数

在Python中,还有一种特殊的函数,它们被称为高阶函数。高阶函数是指可以接受其他函数作为参数,或者可以返回一个函数的函数。这就像是魔法世界中的魔杖,它不仅能施展魔法,还能根据情况变化出不同的魔法。

高阶函数的概念是装饰器的基础。它们允许我们编写更加灵活和强大的代码。想象一下,你有一个魔法药水配方,这个配方需要根据不同的情境来调整。高阶函数就像是这个配方,它可以根据传入的函数来定制化地施展魔法。

def repeat(operation, times):def inner():for _ in range(times):operation()return inner# 使用高阶函数来重复执行另一个函数
def wave():print("Wave your magic wand!")repeat(waving, 3)  # 这将打印 "Wave your magic wand!" 三次

在这个例子中,repeat是一个高阶函数,它接受一个操作operation和一个次数times作为参数,并返回一个新的函数inner。这个新的函数会重复执行传入的操作指定的次数。我们使用repeat来重复执行wave函数三次。

通过理解函数作为对象的概念以及高阶函数的强大功能,我们为探索装饰器的世界打下了坚实的基础。在下一章中,我们将深入装饰器的世界,学习如何定义它们,以及它们是如何工作的。就像学习魔法一样,我们需要从基础开始,一步步提升我们的魔法技能。准备好了吗?让我们继续前进,揭开装饰器的神秘面纱。

3. 装饰器基础

3.1 理解装饰器

装饰器,听起来是不是有点像家里的装饰品?其实在Python中,装饰器也是用来“装饰”的,不过它们装饰的是函数或方法,给它们添加一些额外的“花哨”功能。

想象一下,你有一个简单的函数,它的任务就是打印出“我要去跑步了!”。但生活总是需要一点仪式感,不是吗?你可能想在跑步前发个朋友圈打卡,或者跑步后记录一下时间。这时候,装饰器就能大显身手了。

首先,我们得知道装饰器其实就是一个函数,它接受一个函数作为参数,然后返回一个新的函数。这个新的函数会在执行原函数的基础上,加上一些额外的操作。就像给你的跑步加个计时器,或者加个打卡的动作。

def make_coffee():print("泡了一杯咖啡,准备开始编码!")def with_cup(function):def wrapper():print("拿一个杯子")function()print("喝完咖啡,继续编码!")return wrappermake_coffee = with_cup(make_coffee)
make_coffee()

在这个例子中,with_cup就是一个装饰器。它接收一个函数function作为参数,然后定义了一个内部函数wrapperwrapper函数会在执行function之前和之后分别打印一些额外的信息。最后,with_cup返回了wrapper函数。

当我们将make_coffee装饰成with_cup(make_coffee)时,实际上是用with_cup这个装饰器给make_coffee函数“穿上了一件衣服”。现在,每次调用make_coffee时,都会自动执行wrapper中的代码,也就是先拿一个杯子,然后泡咖啡,最后喝完咖啡继续编码。

3.2 装饰器的工作原理

装饰器的工作原理,其实就像是俄罗斯套娃。你把一个函数包在另一个函数里面,然后再包一层,层层叠加。这就是所谓的“函数嵌套”。

让我们用一个更具体的例子来说明。假设你是一个健身教练,你需要记录每个学员的锻炼时间。你可以创建一个装饰器来自动完成这个任务。

import timedef time_tracker(func):def wrapper(start, end):start_time = time.time()func(start, end)end_time = time.time()print(f"锻炼完成!用时 {end_time - start_time:.2f} 秒")return wrapperdef workout(start, end):print(f"从 {start} 锻炼到 {end}")workout = time_tracker(workout)
workout("08:00", "09:00")

在这个例子中,time_tracker是一个装饰器,它接收一个函数func作为参数,并返回一个wrapper函数。wrapper函数记录了开始时间,执行了func,然后记录结束时间,并打印出锻炼用时。

当我们将workout装饰成time_tracker(workout)时,每次调用workout实际上调用的是wrapper函数。这样,我们就不需要手动修改workout函数来添加计时功能,装饰器帮我们自动完成了。

这就是装饰器的魔力——它们让我们的代码更加模块化,易于扩展和维护。而且,装饰器的使用非常灵活,你可以为同一个函数添加多个装饰器,就像给咖啡加不同的调料一样,让每一杯咖啡都有独特的风味。

在下一章中,我们将探索如何创建带参数的装饰器,这就像是给你的咖啡加糖,可以根据个人口味来调整。准备好了吗?让我们继续深入装饰器的世界,发现更多有趣的可能性。

4. 带参数的装饰器

4.1 为什么需要带参数

想象一下,你是一名厨师,每天为顾客准备各种美食。但是,顾客的口味千差万别,有的人喜欢辣,有的人喜欢甜,还有的人喜欢酸。如果每次顾客来,你都要问一遍他们的口味,岂不是很麻烦?这就是为什么我们需要带参数的装饰器——因为它们可以让我们根据不同的需求,定制化地“调味”我们的函数。

4.2 实现带参数的装饰器

使用函数包裹装饰器

就像我们的厨师可以根据顾客的口味来调整食谱一样,我们也可以创建一个带参数的装饰器,来根据不同的情况来调整函数的行为。

def repeater(times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeater(times=3)
def say_hello(name):print(f"Hello, {name}!")say_hello("Alice")

在这个例子中,我们创建了一个repeater装饰器工厂,它接受一个参数times,表示我们想要重复执行函数的次数。然后,repeater返回一个装饰器decorator,这个装饰器再返回一个包装函数wrapper。每次调用原始函数时,wrapper会重复执行指定的次数。

使用类实现装饰器

有时候,我们需要的不仅仅是重复执行,还可能需要更复杂的逻辑。这时候,我们可以使用类来实现装饰器,就像使用一个多功能的厨房设备,可以同时完成切菜、搅拌和烹饪的工作。

class Logger:def __init__(self, level):self.level = leveldef __call__(self, func):def wrapper(*args, **kwargs):if self.level == "INFO":print(f"INFO: Calling {func.__name__}")result = func(*args, **kwargs)return resultreturn wrapper@Logger(level="INFO")
def make_breakfast():print("煎蛋、烤面包、准备咖啡...")make_breakfast()

在这个例子中,Logger类就是一个带参数的装饰器。它接受一个level参数,用来设置日志的级别。__call__方法使得类的实例可以像函数一样被调用,这样就可以将类用作装饰器了。每次调用原始函数时,wrapper会根据日志级别打印一条信息。

通过使用带参数的装饰器,我们可以编写出更加灵活和强大的代码。就像在厨房里,有了多功能的设备,就可以根据不同的食谱来调整烹饪方式,满足各种不同的需求。

在下一章中,我们将探索如何将多个装饰器叠加在一起使用,这就像是将不同的调料混合在一起,创造出独特的风味。准备好了吗?让我们继续我们的Python烹饪之旅,发现更多有趣的装饰器组合。

在这里插入图片描述

5. 多装饰器应用

5.1 多个装饰器叠加

想象一下,你是一位厨师,正在准备一道大餐。你先给菜肴加上一层香草,然后又撒上一些辣椒粉,最后淋上一些柠檬汁。每一层调料都给菜肴增加了不同的风味,但它们共同作用,让整道菜变得美味无比。在Python中,多个装饰器的叠加也是类似的,它们可以给函数添加多层功能。

装饰器的执行顺序

装饰器的执行顺序是自内而外的,就像你穿衣服一样,先穿内衣,再穿衬衫,最后穿上外套。这意味着最内层的装饰器会最先执行,然后是第二层,依此类推。

def make_spicy(func):def wrapper(*args, **kwargs):print("加入辣椒粉")return func(*args, **kwargs)return wrapperdef add_vanilla(func):def wrapper(*args, **kwargs):print("撒上香草粉")return func(*args, **kwargs)return wrapper@add_vanilla
@make_spicy
def prepare_dish():print("准备一道美味的菜肴")prepare_dish()

输出结果:

加入辣椒粉
撒上香草粉
准备一道美味的菜肴

在这个例子中,prepare_dish函数被make_spicyadd_vanilla两个装饰器装饰。由于装饰器的执行顺序是自内而外的,所以首先执行的是make_spicy,然后才是add_vanilla

避免装饰器冲突的策略

有时候,装饰器之间可能会产生冲突,就像调料放多了可能会让菜肴变得难以下咽。为了避免这种情况,我们需要采取一些策略:

  1. 明确每个装饰器的作用:在添加装饰器之前,确保你清楚每个装饰器的作用,以及它们是否能够和谐地一起工作。
  2. 调整装饰器的顺序:有时候,改变装饰器的顺序可以解决冲突问题。
  3. 使用互斥锁:在一些并发编程的场景中,可以使用互斥锁来避免装饰器之间的冲突。

5.2 装饰器的组合

有时候,我们希望将多个装饰器组合起来,形成一个复合装饰器。这就像是将多种调料混合在一起,创造出一种新的调味品。

def combined_decorator(decorator1, decorator2):def combine(func):return decorator2(decorator1(func))return combine@combined_decorator(make_spicy, add_vanilla)
def prepare_dish():print("准备一道美味的菜肴")prepare_dish()

在这个例子中,我们定义了一个combined_decorator函数,它接受两个装饰器作为参数,并返回一个新的装饰器。这个新的装饰器将两个装饰器的功能组合在一起,使得它们可以同时应用于同一个函数。

通过合理地使用多个装饰器,我们可以编写出功能强大且高度模块化的代码。就像一位经验丰富的厨师,通过精心搭配各种调料,创造出令人难忘的美食。

在下一章中,我们将探讨装饰器的最佳实践,这就像是学习如何成为一名高级厨师,了解如何将各种技巧和调料运用得恰到好处。准备好了吗?让我们继续深入探索Python装饰器的奥秘。

6. 装饰器的最佳实践

6.1 保持透明性

装饰器虽然强大,但使用不当,它们也可能成为代码的“隐形斗篷”,让代码的本意变得模糊不清。就像在变魔术时,魔术师需要保持手法的透明性,让观众能够清楚地看到魔术的每一个细节,装饰器也应该保持代码的透明性。

保留原函数名与文档字符串

想象一下,你有一个魔术表演,观众期待看到的是“消失的硬币”。如果魔术师突然改变了节目单,观众可能会感到困惑。同样,在装饰器中,我们应该保留原函数的名字和文档字符串,这样其他开发者在阅读代码时,能够清楚地知道这个函数是做什么的。

幸运的是,Python为我们提供了一个非常方便的工具——functools.wraps,它可以帮助我们保持函数的透明度。

import functoolsdef my_decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):print("Something is happening before the function is called.")return func(*args, **kwargs)return wrapper@my_decorator
def say_hello(name):"""Greet someone by name."""print(f"Hello, {name}!")print(say_hello.__name__)  # 输出:say_hello
print(say_hello.__doc__)  # 输出:Greet someone by name.

在这个例子中,my_decorator使用了functools.wraps来装饰内部的wrapper函数。这样,即使say_hellomy_decorator装饰,它仍然保留了自己的名称和文档字符串。

6.2 类装饰器的运用

类装饰器就像是我们的多功能厨房设备,它们不仅可以完成单一的任务,还可以提供更多的可能性。类装饰器允许我们在装饰器中使用更多的Python特性,比如属性和方法。

类作为装饰器的优势

类装饰器的一个主要优势是它们可以持有状态。这意味着你可以在装饰器中存储信息,或者根据需要修改行为。

class CountCalls:def __init__(self, func):self.func = funcself.calls = 0def __call__(self, *args, **kwargs):self.calls += 1print(f"{self.func.__name__} has been called {self.calls} times")return self.func(*args, **kwargs)@CountCalls
def say_hello(name):"""Greet someone by name."""print(f"Hello, {name}!")say_hello("Alice")
say_hello("Bob")

在这个例子中,CountCalls类被用作装饰器。每次调用say_hello函数时,CountCalls都会记录调用次数,并打印出来。

实例绑定与类方法装饰

类装饰器还可以与实例绑定和类方法结合使用,这为装饰器提供了更多的灵活性。

class TimingDecorator:def __init__(self, func):self.func = funcself.execution_time = 0def __call__(self, *args, **kwargs):start_time = time.time()result = self.func(*args, **kwargs)self.execution_time = time.time() - start_timeprint(f"{self.func.__name__} executed in {self.execution_time:.4f} seconds")return result@TimingDecorator
def long_running_task():time.sleep(2)  # 模拟耗时任务long_running_task()

在这个例子中,TimingDecorator类不仅记录了函数的执行时间,还可以在之后的时间里访问这个信息,比如用于性能分析。

通过遵循这些最佳实践,我们可以确保装饰器的使用既强大又透明,让代码更加易于理解和维护。就像一位高级厨师,不仅能够创造出美味的菜肴,还能够清楚地向顾客解释每一道菜的制作过程和食材来源。

在下一章中,我们将探索装饰器的一些高级话题,这就像是学习一些高级烹饪技巧,让你的Python代码变得更加专业和高效。准备好了吗?让我们继续前进,探索装饰器的高级世界。

7. 装饰器的高级话题

7.1 装饰类方法

在Python中,类方法就像是家族中的传家宝,它们与特定的类紧密相连。装饰类方法就像是给这些传家宝加上一层保护膜,让它们在保持原有价值的同时,还能获得一些额外的保护。

想象一下,你有一个家族秘方,这个秘方被记录在一本古老的食谱中。每次使用这个秘方时,你都需要确保遵循特定的步骤,比如检查食材的新鲜度,或者记录下使用的次数。这就是装饰类方法的作用。

class FamilyRecipe:def __init__(self, name):self.name = namedef make_recipe(self, *args, **kwargs):print(f"Making the {self.name} recipe...")@classmethoddef decorate_recipe(cls, func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f"Preparing ingredients for {cls.__name__}.")return func(*args, **kwargs)return wrapper@decorate_recipedef cook(cls):print("Cooking the family recipe.")FamilyRecipe.cook()

在这个例子中,FamilyRecipe类有一个类方法decorate_recipe,它被用作装饰器来装饰另一个类方法cook。这样,每次调用cook方法时,都会先打印出准备食材的信息。

在这里插入图片描述

7.2 动态装饰器

动态装饰器就像是魔法世界中的变形术,它们可以根据条件变化形态。在Python中,动态装饰器允许我们在运行时根据条件来决定是否应用某个装饰器。

想象一下,你是一名侦探,每次调查案件时,你都需要根据现场的情况来决定使用哪些工具。有时候,你可能需要放大镜来观察细节;有时候,你可能需要手电筒来照亮黑暗的角落。动态装饰器就是你的侦探工具箱,可以根据需要随时调整。

def conditional_decorator(condition):def actual_decorator(func):def wrapper(*args, **kwargs):if condition():print("Condition met, applying decorator.")return func(*args, **kwargs)else:print("Condition not met, skipping decorator.")return func(*args, **kwargs)return wrapperreturn actual_decoratordef is_night():# 假设这是检查当前时间是否为夜晚的函数return True  # 简化示例,假设总是夜晚@conditional_decorator(is_night)
def night_shift():print("Working the night shift.")night_shift()

在这个例子中,conditional_decorator是一个装饰器工厂,它接受一个条件函数condition作为参数,并返回一个实际的装饰器actual_decorator。这个装饰器会根据条件函数的返回值来决定是否应用装饰。

7.3 装饰器性能考量

装饰器虽然强大,但它们也可能影响代码的性能。就像在赛车比赛中,额外的装饰可能会增加车辆的重量,从而影响速度。因此,在使用装饰器时,我们需要考虑它们的性能影响。

  • 避免过度装饰:不要无谓地给函数添加多个装饰器,特别是在性能敏感的代码中。
  • 测试性能:在使用装饰器后,进行性能测试,确保它们没有对代码性能产生负面影响。
  • 简化装饰器:尽量保持装饰器的简洁,避免在装饰器中执行复杂的操作。

通过这些高级话题的探讨,我们可以看到装饰器不仅仅是代码的“调味品”,它们还可以是强大的工具,帮助我们编写更加灵活、安全和高效的代码。就像一位高级厨师,不仅要掌握烹饪技巧,还要了解食材的特性和搭配原则。

8. 结论

装饰器的核心价值总结

装饰器,这个听起来就像是给代码穿上了一件时尚外套的工具,其实远不止于此。它们是Python中的瑞士军刀,多功能且强大。装饰器让我们的代码更加模块化、灵活和易于维护。就像一位时尚设计师,不仅能够让衣服看起来更漂亮,还能够根据不同场合调整设计,让穿着者既舒适又得体。

代码复用与解耦

装饰器让我们能够将一些通用的功能抽象出来,避免在多个函数中重复相同的代码。这就像是拥有一个万能的调料包,无论做什么菜,都可以撒上一点,让味道更加丰富。通过装饰器,我们可以轻松地将这些功能应用到不同的函数上,而不需要修改函数本身,实现了代码的高度复用和解耦。

增强函数功能

装饰器能够在不修改原有函数代码的前提下,给函数增加额外的功能。这就像是给一辆普通的自行车加上电动马达,让它瞬间变成电动自行车,功能得到增强,但自行车的本质并没有改变。通过装饰器,我们可以轻松地为函数添加日志记录、性能测试、事务处理等额外功能。

提高代码可读性

通过使用装饰器,我们可以将一些复杂的逻辑从函数中抽离出来,让函数的主体代码更加简洁和清晰。这就像是在阅读一本书时,作者将一些复杂的背景知识放在了附录中,而不是直接插入到故事里,让读者能够更加顺畅地阅读故事本身。装饰器帮助我们保持了代码的整洁和可读性。

在项目中合理运用装饰器的建议

  1. 明确目的:在使用装饰器之前,明确你需要装饰器解决什么问题,它是否是最佳解决方案。
  2. 保持简洁:装饰器应该尽可能简单,避免在装饰器中执行复杂的逻辑。
  3. 考虑性能:在性能敏感的应用中,考虑装饰器可能带来的性能影响。
  4. 使用functools.wraps:保留原函数的名称和文档字符串,提高代码的可读性。
  5. 避免过度装饰:不要过度使用装饰器,特别是在同一个函数上叠加多个装饰器,可能会导致代码难以理解和维护。
  6. 编写文档:为你的装饰器编写清晰的文档,说明它的用途、参数和行为。

最后,装饰器就像是我们编程工具箱中的一把利器,用得好,它能够帮助我们编写出更加优雅、高效的代码。但和所有的工具一样,我们需要合理使用,避免滥用。记住,装饰器是为了简化我们的工作,而不是让工作变得更加复杂。

随着我们对装饰器的探索告一段落,希望你能够将这些知识应用到你的Python编程实践中,让你的代码像装饰过的蛋糕一样,既美观又美味。继续前进吧,Python的魔法世界还有更多奥秘等待你去发掘!

我是阿佑,一个专注于把晦涩的知识讲得有趣的中二青年,欢迎评论区留言~

相关文章:

揭秘Python的魔法:装饰器的超能力大揭秘 ‍♂️✨

文章目录 Python进阶之装饰器详解1. 引言装饰器的概念与意义装饰器在Python编程中的作用 2. 背景介绍2.1 函数作为对象2.2 高阶函数 3. 装饰器基础3.1 理解装饰器3.2 装饰器的工作原理 4. 带参数的装饰器4.1 为什么需要带参数4.2 实现带参数的装饰器使用函数包裹装饰器使用类实…...

怎么一键消除路人?教你三个消除方法

怎么一键消除路人?在数字时代,摄影已成为我们记录生活、表达情感的重要方式。然而,完美的照片背后往往隐藏着一些不那么完美的元素——比如那些不经意间闯入镜头的路人。他们或许只是匆匆过客,但却足以破坏你精心构图的美好瞬间。…...

Android Settings系统属性读写

Settings系统属性存储均为xml,分三种: 1.global:所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限; 源码地址:frameworks/base/core/java/android/provider/Settings.java 对应xml路径&…...

2024年,企业的人才管理怎么做?这5点是关键!

当今时代,各行各业都面临着激烈的竞争。这些竞争归根结底都是人才的竞争。企业若想在竞争中掌握主动权,实现基业长青,就必须努力留住人才,并充分发挥他们的积极性、主动性和创造性。因此,做好人才管理是企业实现长期可…...

数据库DDL语句

数据库DDL语句: 查询所有数据库: show databases;查询当前数据库的名称 select database();创建数据库 create database [if not exists] 数据库名 [default charset 字符集] [collate 排序规则]注意:排序规则指定后,它会影响…...

《艺术大观》知网艺术刊:可加急, 出刊上网快

《艺术大观》 《艺术大观》征文通知 《艺术大观》期刊诚邀学者、艺术家和文化工作者积极投稿,共同探索艺术领域的前沿问题,促进学术交流和艺术创作的发展。我们欢迎各类艺术形式的研究与评论,包括但不限于绘画、雕塑、音乐、舞蹈、戏剧、电…...

如何在go语言中调用c语言代码

1.安装c语言编译器 要使用cgo,需要安装c语言编译器 gcc 2.检查CGO_ENABLED时候开启 使用以下命令查看: go env CGO_ENABLED 如果go env CGO_ENABLED被禁用(为0),需要将其设置为开启(为1) 3.编写c语言程序,并用go语言调用c语言程序 1&#xff…...

Monodle centerNet3D 瑞芯微RKNN、地平线Horizon芯片部署、TensorRT部署

一直想做一点3D目标检测,先来一篇单目3D目标检测Monodle(基于centernet的),训练代码参考官方【代码】,这里只讲讲如何部署。 模型和完整仿真测试代码,放在github上参考链接【模型和完整代码】。 1 模型训练…...

Android Studio 使用MQTT协议开发应用时怎样关闭MQTT连接

Android Studio 使用MQTT协议开发应用时怎样关闭MQTT连接 Android Studio 使用MQTT协议开发应用时关闭MQTT连接 在使用mqtt开发的时候,有时候需要通过 返回 按钮关闭界面或者Activity时,关闭当前页面使用的mqtt连接,这里有两种方式彻底销毁…...

Sping源码(八)—registerBeanPostProcessors

序言 之前我们用大量的篇幅介绍过invokeBeanFactoryPostProcessors()方法的执行流程。 而invokeBeanFactoryPostProcessors的主要逻辑就是遍历执行实现了BeanDefinitionRegistryPostProcesso类(主要是针对BeanDefinition的操作)和BeanFactoryPostProcessor(主要针对BeanFacrot…...

MaxEnt模型文章中存在的问题和处理方法(050B更新)2024.5.24

目前多数MaxEnt文章中存在的问题和处理方案。 **问题一:**变量数据使用问题,很多文章把所有变量数据直接使用,但是温度和土壤、植被类型等属于不同数据类型,在数据使用时参数配置是不一样的,产生的结果文件也是不一样的…...

Modular RPG Hero PBR

-掩码着色着色器提供了无限的颜色变化。(适用于标准/HDRP/URP 11.0.0) -为剑与盾/双剑/双剑姿态提供了简单的角色控制器。(不包括弓和魔杖控制器)(它是用旧的输入系统建造的) -HDRP/URP(11.0.0)SRP 100%支持常规着色器和遮罩着色着色器(基于着色器图形) -具有许多模块…...

机器学习之常用算法与数据处理

一、机器学习概念: 机器学习是一门多领域交叉学科,涉及概率论、统计学、计算机科学等多门学科。它的核心概念是通过算法让计算机从数据中学习,改善自身性能。机器学习专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识…...

Git管理

git作用:代码回溯 版本切换 多人协作 远程备份 git仓库:本地仓库:开发人员自己电脑上的Git仓库 原程仓库:远程服务器上的Git仓库 commit:提交,将本地文件和版本信息保存到本地仓库 push:推送&#xff0…...

osgearth 3.5 vs 2019编译

下载源码 git clone --recurse-submodules https://github.com/gwaldron/osgearth.git 修改配置文件 主要是修改bootstrap_vcpkg.bat,一处是vs的版本,第二处是-DCMAKE_BUILD_TYPERELEASE 构建 执行bootstrap_vcpkg.bat vs中生成安装 vs2019打开bu…...

2024最新 Jenkins + Docker 实战教程(六)- Jenkins配置邮箱接收构建通知

😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~ 🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Mi…...

Python学习---基于TCP协议的网络通信程序案例

TCP简介: ●TCP 面向连接、可靠的、基于字节流的传输控制协议 ●TCP的特点 ○面向连接 ○可靠传输 ■应答机制 ■超时重传 ■错误校验 ■流量管控 ●TCP通信模型 TCP严格区分客户…...

正确可用--Notepad++批量转换文件编码为UTF8

参考了:Notepad批量转换文件编码为UTF8_怎么批量把ansi转成utf8-CSDN博客​​​​​​https://blog.csdn.net/wangmy1988/article/details/118698647我参考了它的教程,但是py脚本写的不对. 只能改一个.不能实现批量更改. 他的操作步骤没问题,就是把脚本代码换成我这个. #-*-…...

每天五分钟深度学习框架PyTorch:创建具有特殊值的tensor张量

本文重点 tensor张量是一个多维数组,本节课程我们将学习一些pytorch中已经封装好的方法,使用这些方法我们可以快速创建出具有特殊意义的tensor张量。 创建一个值为空的张量 import torch import numpy as np a=torch.empty(1) print(a) print(a.dim()) print(s.shape) 如图…...

2024电工杯数学建模B题Python代码+结果表数据教学

2024电工杯B题保姆级分析完整思路代码数据教学 B题题目:大学生平衡膳食食谱的优化设计及评价 以下仅展示部分,完整版看文末的文章 import pandas as pd df1 pd.read_excel(附件1:1名男大学生的一日食谱.xlsx) df1# 获取所有工作表名称 e…...

asp.net mvc如何简化控制器逻辑

在ASP.NET MVC中,可以通过以下方法简化控制器逻辑: ASP.NET——MVC编程_aspnet mvc-CSDN博客 .NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程) https://cloud.tencent.com/developer/article/1015115 【转载…...

ngx_stream_geo_module在传输层实现高性能 IP Region 路由

一、模块定位与核心价值 层次:工作在 Stream (TCP/UDP) 层,和 ngx_http_geo_module 的 L7 语义互补。作用:基于客户端 IP 前缀 / 范围生成一个 Nginx 变量,可在后续 proxy_pass、map、limit_conn、access 等指令中使用&#xff0…...

基于Scala实现Flink的三种基本时间窗口操作

目录 代码结构 代码解析 (1) 主程序入口 (2) 窗口联结(Window Join) (3) 间隔联结(Interval Join) (4) 窗口同组联结(CoGroup) (5) 执行任务 代码优化 (1) 时间戳分配 (2) 窗口大小 (3) 输出格式…...

函数与数列的交汇融合

前情概要 现行的新高考对数列的考查难度增加,那么整理与数列交汇融合的相关题目就显得非常必要了。 典例剖析 依托函数,利用导数,求数列的最值;№ 1 、 \color{blue}{№ 1、} №1、 等差数列 { a n } \{a_{n}\} {an​} 的前 n n n 项和为 S n S_{n} Sn​, 已知 S 10…...

如何打造一款金融推理工具Financial Reasoning Workflow:WebUI+Ollama+Fin-R1+MCP/RAG

在之前的文章中,我探讨了如何使用具身人工智能,让大语言模型智能体来模仿[当今著名对冲基金经理的投资策略]。 在本文中,我将探讨另一种方法,该方法结合了经过金融推理训练的特定大语言模型(LLM)&#xff0…...

Go 语言 := 运算符详解(短变量声明)

Go 语言 : 运算符详解(短变量声明) : 是 Go 语言中特有的​​短变量声明运算符​​(short variable declaration),它提供了简洁的声明并初始化变量的方式。这是 Go 语言中常用且强大的特性之一。 基本语法和用途 va…...

提取数据区域中表格

查看本示例演示效果本示例关键代码的编写位置,请参考“开始 - 快速上手”里您所使用的开发语言框架的最简集成代码 在实际的开发过程中,有时会遇到希望提取Word文档中表格数据保存到服务器的需求,此时可以使用PageOffice提取Word文档数据区域…...

【Survival Analysis】【机器学习】【3】 SHAP可解釋 AI

前言: SHAP(SHapley Additive explanations) 是一种基于博弈论的可解释工具。 现在很多高分的 论文里面都会带这种基于SHAP 分析的图,用于评估机器学习模型中特征对预测结果的贡献度. pip install -i https://pypi.tuna.tsinghua.edu.cn/sim…...

Redis Key过期策略

概述 Redis的Key过期策略是其内存管理系统的核心组成部分,主要包括「被动过期」、「主动过期」和「内存淘汰」三个机制。其中「内存淘汰」相关内容已经在上一篇「Redis内存淘汰策略」中进行了详细的讲解,有信兴趣的同学可以在回顾上一篇文章。本文将着重…...

Java Fork/Join框架:三大核心组件深度解析

ForkJoinTask、ForkJoinWorkerThread 和 ForkJoinPool 构成了 Java 中 Fork/Join 框架的三个核心组件,它们之间形成了紧密的协作关系,共同提供了高效的并行计算能力。 三者关系概述 ForkJoinPool:执行环境,管理工作线程和任务调…...