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

Python装饰器

什么是python装饰器?

顾名思义,从字面意思就可以理解,它是用来"装饰"Python的工具,使得代码更具有Python简洁的风格。换句话说,它是一种函数的函数,因为装饰器传入的参数就是一个函数,然后通过实现各种功能来对这个函数的功能进行增强。

为什么要使用装饰器?

装饰器是通过某种方式来增强函数的功能。当然,我们可以通过很多方式来增强函数的功能,只是装饰器有一个无法替代的优势--简洁。只需要在每个函数上方加一个@就可以对这个函数进行增强。

装饰器(Decorator)是Python中一个重要部分,它本质上是一个函数,不同于普通函数,装饰器的返回值是一个函数对象。通过利用装饰器,我们可以让其他函数在不做任何代码改动的情况下增加额外的功能,同时也能够让代码更加简洁。

装饰器

装饰器是Python的一种高级函数,它可以接受一个函数作为参数,并返回一个新的函数。通过使用装饰器,我们可以在不修改原函数代码的情况下,为函数添加额外的功能或行为。

基本定义

装饰器的定义格式如下:

def decorator_function(original_function):def wrapper_function(*args, **kwargs):# 在调用原函数之前的额外操作result = original_function(*args, **kwargs)# 在调用原函数之后的额外操作return resultreturn wrapper_function

在上述示例中,decorator_function是装饰器函数,它接受一个原函数original_function作为参数,并返回一个新的函数wrapper_function。wrapper_function内部可以执行一些在调用原函数之前或之后的额外操作。‍

def a_new_decorator(a_func):def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunctiondef a_function_requiring_decoration():print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()

上面的例子演示了装饰器的工作过程,Python提供了语法糖来简化装饰器,在函数定义时加上@装饰器,在函数被调用时,自动会调用装饰器返回的函数

@a_new_decorator
def a_function_requiring_decoration():"""Hey you! Decorate me!"""print("I am the function which needs some decoration to ""remove my foul smell")a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

原函数参数

如果被装饰器包装的函数带有参数,需要通过*args, **kwargs来传递参数,*args, **kwargs可以传递任意数量的位置参数和关键字参数。

def do_twice(func):def wrapper_do_twice(*args, **kwargs):func(*args, **kwargs)func(*args, **kwargs)return wrapper_do_twice@do_twice
def say_hello(name):print(f'Hello {name}!')say_hello('Jack’)‘’’
Hello Jack!
Hello Jack!
’‘’

装饰器返回值

装饰器如果要返回原函数的返回值,需要用一个返回变量接收原函数的返回值

def log_foo(func):def wrapper(*args, **kwargs):print(f'func() start...')result = func(*args, **kwargs)print(f'func() end.')return resultreturn wrapper@log_foo
def say_hello(name):print(f'Hello {name}!')say_hello('Jack’)‘’'
func() start...
Hello Jack!
func() end.
‘''

保留原函数信息

函数携带的一些基本信息,例如函数名、函数文档等,我们可以通过func.__name__获取函数名、可以通过func.__doc__获取函数的文档信息,用户也可以通过注解等方式为函数添加元信息。

由于包装后的函数是wrapper,函数名的等信息都修改为wrapper的信息。

def log_foo(func):def wrapper(*args, **kwargs):'''自定义日志装饰器'''print(f'func() start...')result = func(*args, **kwargs)print(f'func() end.')return resultreturn wrapper@log_foo
def say_hello(name):'''say_hello函数'''print(f'Hello {name}!')print(say_hello.__name__) 
print(say_hello.__doc__) 
print(help(say_hello)) ‘’’
wrapper自定义日志装饰器Help on function wrapper in module __main__:wrapper(*args, **kwargs)自定义日志装饰器None
’‘’

为了解决这个问题,使用functools.wraps修饰修饰器,这将保留有关原始功能的信息。

import functools
def log_foo(func):@functools.wraps(func)def wrapper(*args, **kwargs):'''自定义日志装饰器'''print(f'func() start...')result = func(*args, **kwargs)print(f'func() end.')return resultreturn wrapper@log_foo
def say_hello(name):'''say_hello函数'''print(f'Hello {name}!')print(say_hello.__name__)
print(say_hello.__doc__)
print(help(say_hello))‘’’
say_hellosay_hello函数Help on function say_hello in module __main__:say_hello(name)say_hello函数None
’‘’

多个装饰器装饰

可以多个装饰器同时装饰一个函数

def dec_foo1(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f'--dec_foo1() start--')result = func(*args, **kwargs)print(f'--dec_foo1() end--')return resultreturn wrapperdef dec_foo2(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f'--dec_foo2() start--')result = func(*args, **kwargs)print(f'--dec_foo2() end--')return resultreturn wrapper@dec_foo1
@dec_foo2
def say_hello(name):'''say_hello函数'''print(f'Hello {name}!')say_hello('Rose’)‘’'
--dec_foo1() start--
--dec_foo2() start--
Hello Rose!
--dec_foo2() end--
--dec_foo1() end--
‘''

装饰器函数包装的顺序是从上往下。

 

带参数的装饰器

能将参数传递给装饰器是很有用的,比如我们可以给@dec_foo1()扩展为@dec_foo1(num_times)

注意代码多内置了一层函数传参(需要嵌套3层函数,前面的都是2层),通过闭包的形式将参数num_times传入内层函数,可以理解为dec_foo1(num_times)返回的函数再来装饰func

def dec_foo1(num_times):def decorator_repeat(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f'--dec_foo1() start--')for _ in range(num_times):result = func(*args, **kwargs)print(f'--dec_foo1() end--')return resultreturn wrapperreturn decorator_repeat@dec_foo1(4)
def say_hello(name):print(f'Hello {name}!')say_hello('Rose’)‘’'
--dec_foo1() start--
Hello Rose!
Hello Rose!
Hello Rose!
Hello Rose!
--dec_foo1() end--
‘''

装饰器类

前面介绍类对象只要实现了__call__也可以作为函数对象被调用,函数对象也可以用来作为装饰器。

类的装饰器在@声明的时候需要使用cls()来声明,因为这样才能正确的生成一个函数对象,不能简单的使用类名来声明装饰器,那样会出错TypeError

from functools import wrapsclass logit(object):def __init__(self, logfile='out.log'):self.logfile = logfiledef __call__(self, func):@wraps(func)def wrapped_function(*args, **kwargs):log_string = func.__name__ + " was called"print(log_string)# 打开logfile并写入with open(self.logfile, 'a') as opened_file:# 现在将日志打到指定的文件opened_file.write(log_string + '\n')# 现在,发送一个通知self.notify()return func(*args, **kwargs)return wrapped_functiondef notify(self):# logit只打日志,不做别的pass@logit()   #将类实例化
def myfunc1():passmyfunc1()

并且通过函数对象实现装饰器,有一个优势,便是可以提供更多的预置的变量。

给 logit 创建子类,来添加 email 的功能。

class email_logit(logit):'''一个logit的实现版本,可以在函数调用时发送email给管理员'''def __init__(self, email='admin@myproject.com', *args, **kwargs):self.email = emailsuper(email_logit, self).__init__(*args, **kwargs)def notify(self):# 发送一封email到self.email# 这里就不做实现了pass

@email_logit() 将会和 @logit() 产生同样的效果,但是在打日志的基础上,还会多发送一封邮件给管理员。

常见用法

类的装饰器

from dataclasses import dataclass@dataclass
class PlayingCard:rank: strsuit: str

类方法装饰器

类中修饰器的一种用法是装饰类中的函数,有一些常用的python内置的修饰器。

@property

修饰函数可以作为属性使用,与所定义的属性配合使用,这样可以防止属性被修改。

class House:def __init__(self, price):self._price = price@propertydef price(self):return self._price@price.setterdef price(self, new_price):if new_price > 0 and isinstance(new_price, float):self._price = new_priceelse:print("Please enter a valid price")@price.deleterdef price(self):del self._price

按照惯例,在python中当在变量名前加一个下划线时,意味着告诉其他开发人员不应直接在类外访问或者修改改变量。

  • @property 获取属性。
  • @price.setter 属性设定,可以用来限制属性的范围等等。
  • @price.deleter 定义属性的删除,在del house.price时被执行。

@abstractmethod

抽象方法表示基类的一个方法,没有实现,所以基类不能实例化,子类实现了该抽象方法才能被实例化

@classmethod

classmethod声明方法为类方法,直接通过 类或者实例.类方法()调用。经过@classmethod修饰的方法,不需要self参数,但是需要一个标识类本身的cls参数。

class T:@classmethoddef class_test(cls):#必须有cls参数print "i am a class method"
if __name__ == "__main__":T.class_test()T().class_test()

@staticmethoed

声明方法为静态方法,直接通过 类或者实例.静态方法()调用。经过@staticmethod修饰的方法,不需要self参数,其使用方法和直接调用函数一样。

记录状态的装饰器

装饰器可以跟踪函数的状态,如下是一个记录函数调用次数的装饰器,通过函数属性来计数。

import functoolsdef count_calls(func):@functools.wraps(func)def wrapper_count_calls(*args, **kwargs):wrapper_count_calls.num_calls += 1print(f"Call {wrapper_count_calls.num_calls} of {func.__name__!r}")return func(*args, **kwargs)wrapper_count_calls.num_calls = 0return wrapper_count_calls@count_calls
def say_whee():print("Whee!")

记录状态的最好的方式是使用类作为装饰器,只需要实现__init__()__call__()。使用functools.update_wrapper(self, func)保留信息。

import functoolsclass CountCalls:def __init__(self, func):functools.update_wrapper(self, func)self.func = funcself.num_calls = 0def __call__(self, *args, **kwargs):self.num_calls += 1print(f"Call {self.num_calls} of {self.func.__name__!r}")return self.func(*args, **kwargs)@CountCalls
def say_whee():print("Whee!")

@timer

@timer装饰器,记录函数执行的时间。

import functools
import timedef timer(func):"""Print the runtime of the decorated function"""@functools.wraps(func)def wrapper_timer(*args, **kwargs):start_time = time.perf_counter()    # 1value = func(*args, **kwargs)end_time = time.perf_counter()      # 2run_time = end_time - start_time    # 3print(f"Finished {func.__name__!r} in {run_time:.4f} secs")return valuereturn wrapper_timer@timer
def waste_some_time(num_times):for _ in range(num_times):sum([i**2 for i in range(10000)])waste_some_time(999)
#Finished 'waste_some_time' in 1.6487 secs

@debug

@debug装饰器,输出调试信息,帮助程序员分析问题。

import functoolsdef debug(func):"""Print the function signature and return value"""@functools.wraps(func)def wrapper_debug(*args, **kwargs):args_repr = [repr(a) for a in args]                      # 1kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]  # 2signature = ", ".join(args_repr + kwargs_repr)           # 3print(f"Calling {func.__name__}({signature})")value = func(*args, **kwargs)print(f"{func.__name__!r} returned {value!r}")           # 4return valuereturn wrapper_debug@debug
def make_greeting(name, age=None):if age is None:return f"Howdy {name}!"else:return f"Whoa {name}! {age} already, you are growing up!">>> make_greeting("Benjamin")
Calling make_greeting('Benjamin')
'make_greeting' returned 'Howdy Benjamin!'
'Howdy Benjamin!'

授权

装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中。这里是一个例子来使用基于装饰器的授权:

from functools import wrapsdef requires_auth(f):@wraps(f)def decorated(*args, **kwargs):auth = request.authorizationif not auth or not check_auth(auth.username, auth.password):authenticate()return f(*args, **kwargs)return decorated

日志

日志是装饰器运用的另一个亮点

rom functools import wrapsdef logit(func):@wraps(func)def with_logging(*args, **kwargs):print(func.__name__ + " was called")return func(*args, **kwargs)return with_logging@logit
def addition_func(x):"""Do some math."""return x + xresult = addition_func(4)
# Output: addition_func was called

另外一个例子:

import logging
from functools import partial
​
def wrapper_property(obj, func=None):if func is None:return partial(wrapper_property, obj)setattr(obj, func.__name__, func)return func
​
def logger_info(level, name=None, message=None):def decorate(func):logmsg = message if message else func.__name__def wrapper(*args, **kwargs):log.log(level, logmsg)return func(*args, **kwargs)
​@wrapper_property(wrapper)def set_level(newlevel):nonlocal levellevel = newlevel
​@wrapper_property(wrapper)def set_message(newmsg):nonlocal logmsglogmsg = newmsg
​return wrapper
​return decorate
​
​
@logger_info(logging.WARNING)
def main(x, y):return x + ymain(3, 3)
​
# 输出
# WARNING:Test:main
# 6main.set_level(logging.ERROR)
main(5, 5)# 输出
# ERROR:Test:main
# 10

这里面最重要的是wrapper_property这个函数,它的功能是把一个函数func变成一个对象obj的属性,然后通过调用wrapper_property,给装饰器添加了两个属性set_messageset_level,分别用于改变输出日志的内容和改变输出日志的等级。

 

Registering Plugins

装饰器不必包装他们正在装饰的功能,它们还可以简单地注册一个函数的存在,并将其解封返回。如下是创建轻量级插件架构的代码。

import random
PLUGINS = dict()def register(func):"""Register a function as a plug-in"""PLUGINS[func.__name__] = funcreturn func@register
def say_hello(name):return f"Hello {name}"@register
def be_awesome(name):return f"Yo {name}, together we are the awesomest!"def randomly_greet(name):greeter, greeter_func = random.choice(list(PLUGINS.items()))print(f"Using {greeter!r}")return greeter_func(name)

创建单例(Singletons)

单例是一种设计模式,单例模式保证了在程序的不同位置都可以且仅可以取到同一个对象实例。通过保存实例使得每次返回的是同一个对象实例。

import functoolsdef singleton(cls):"""Make a class a Singleton class (only one instance)"""@functools.wraps(cls)def wrapper_singleton(*args, **kwargs):if not wrapper_singleton.instance:wrapper_singleton.instance = cls(*args, **kwargs)return wrapper_singleton.instancewrapper_singleton.instance = Nonereturn wrapper_singleton@singleton
class TheOne:pass

实现缓存和记忆机制

通过记录状态来保存之前的计算结果。

import functools
from decorators import count_callsdef cache(func):"""Keep a cache of previous function calls"""@functools.wraps(func)def wrapper_cache(*args, **kwargs):cache_key = args + tuple(kwargs.items())if cache_key not in wrapper_cache.cache:wrapper_cache.cache[cache_key] = func(*args, **kwargs)return wrapper_cache.cache[cache_key]wrapper_cache.cache = dict()return wrapper_cache@cache
@count_calls
def fibonacci(num):if num < 2:return numreturn fibonacci(num - 1) + fibonacci(num - 2)

添加额外的信息

通过在装饰函数时给函数附加属性来添加信息。

def set_unit(unit):"""Register a unit on a function"""def decorator_set_unit(func):func.unit = unitreturn funcreturn decorator_set_unitimport math@set_unit("cm^3")
def volume(radius, height):return math.pi * radius**2 * height>>> volume(3, 5)
141.3716694115407>>> volume.unit
'cm^3'

相关文章:

Python装饰器

什么是python装饰器&#xff1f; 顾名思义&#xff0c;从字面意思就可以理解&#xff0c;它是用来"装饰"Python的工具&#xff0c;使得代码更具有Python简洁的风格。换句话说&#xff0c;它是一种函数的函数&#xff0c;因为装饰器传入的参数就是一个函数&#xff0…...

【Spring】使用自定义注解方式实现AOP鉴权

AOP&#xff0c;是一种面向切面编程&#xff0c;可以通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 在软件开发中&#xff0c;鉴权&#xff08;Authentication&#xff09;是一项非常重要的安全措施&#xff0c;用于验证用户身份和权限。在应用程序中&…...

Go几种读取配置文件的方式

比较有名的方案有 使用viper管理配置[1] 支持多种配置文件格式&#xff0c;包括 JSON,TOML,YAML,HECL,envfile&#xff0c;甚至还包括Java properties 支持为配置项设置默认值 可以通过命令行参数覆盖指定的配置项 支持参数别名 viper[2]按照这个优先级&#xff08;从高到低&am…...

每日一题(反转链表)

每日一题&#xff08;反转链表&#xff09; 206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 可以定义一个新的newhead结构体指针。再定义cur指针和next指针互相配合&#xff0c;将原链表中的节点从头到尾依次头插到newhead链表中&#xff0c;同时更…...

某人事系统架构搭建设计记录

首发博客地址 https://blog.zysicyj.top/ 先大致列一下基础情况 架构必须是微服务 场景上涉及大量查询操作&#xff0c;分析操作 存在临时大量写入的场景 并发并不高 对高可用要求较高&#xff0c;不能挂掉 对安全要求高 要能过等保测试等三方测试 使用人数并不多&#xff0c;十…...

uniapp 实现切换tab锚点定位到指定位置

1.主要使用uniapp scroll-view 组件的scroll-into-view属性实现功能 2.代码如下 <scroll-view:scroll-into-view"intoView"><u-tabsclass"tabs-list"change"tabChange":list"tabList"></u-tabs><view id"1&…...

华纳云:ssh登录22号端口拒绝连接Ubuntu?

如果您在尝试使用SSH登录Ubuntu服务器的时候遇到了22号端口拒绝连接的问题&#xff0c;您可以尝试以下几个步骤来解决问题&#xff1a; 确认SSH服务已启动&#xff1a; 确保Ubuntu服务器上的SSH服务已经正确启动。您可以在服务器上运行以下命令来检查SSH服务的状态&#xff1a…...

python conda实践 sanic框架gitee webhook实践

import subprocess import hmac import hashlib import base64 from sanic.response import text from sanic import Blueprint from git import Repo# 路由蓝图 hook_blue Blueprint(hook_blue)hook_blue.route(/hook/kaifa, methods["POST"]) async def kaifa(req…...

LeetCode——无重复的最长子串(中等)

题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为…...

【SQL】关系模型与查询和更新数据

一、关系模型 1.1 主键 主键是关系表中记录的唯一标识。主键的选取非常重要&#xff1a;主键不要带有业务含义&#xff0c;而应该使用BIGINT自增或者GUID类型。主键也不应该允许NULL。 可以使用多个列作为联合主键&#xff0c;但联合主键并不常用。 1.2 外键 FOREIGN KEY …...

【Centos8_配置单节点伪分布式Spark环境】

安装centos8 jdk部署伪分布式spark环境 安装Centos8 环境下的JDK 下载jdk linux版本 下载链接&#xff1a; jdk-8u381-linux-x64.tar.gz 将该文件上传到Centos8 主机 部署配置jdk&#xff08;java8&#xff09; # 解压到指定路径 [lhangtigerkeen Downloads]$ sudo tar …...

【软考】系统集成项目管理工程师(三)信息系统集成专业技术知识①【16分】

一、系统集成的特点 官方解释&#xff1a; 1、信息系统建设的内容主要包括设备采购、系统集成、软件开发和运维服务等&#xff1b; 2、信息系统集成是指将计算机软件、硬件、网络通信、信息安全等技术和产品集成为能够满足用户特定需求的信息系统&#xff1b;显著特点如下&am…...

揭秘特权账号潜在风险,你中招了吗?

什么是特权账号&#xff1f; 特权账号指在企业运营过程中&#xff0c;为相关业务运营、系统管理、系统运维等人员赋予的系统维护、权限增加、数据修改删除、导出等高级权限的系统账号。这些账号多数连接企业核心资源&#xff0c;保障企业内部各项业务正常运作。然而&#xff0…...

线性代数的学习和整理13: 定义域,值域,到达域 和单射,满射,双射,反函数,逆矩阵

目录 1 函数与 向量/矩阵 2 初等数学的函数 2.1 函数 2.2 函数的定义&#xff1a;定义域 →映射→ 值域 3 高等数学里的函数&#xff1a;定义域和陪域/到达域&#xff08;非值域&#xff09;的映射关系 3.1 函数 3.2 单射&#xff0c;满射&#xff0c;双射等都是针对…...

深入MaxCompute -第十一弹 -QUALIFY

简介&#xff1a; MaxCompute支持QUALIFY语法过滤Window函数的结果&#xff0c;使得查询语句更简洁易理解。Window函数和QUALIFY语法之间的关系可以类比聚合函数GROUP BY语法和HAVING语法。 MaxCompute&#xff08;原ODPS&#xff09;是阿里云自主研发的具有业界领先水平的分…...

Mysql定时备份事件

创建了一个名为backup_database的定时任务&#xff0c;每天自动在当前时间的后一天开始执行。备份数据库的代码使用mysqldump命令将数据库导出为sql文件保存在指定的备份目录中。 需要注意的是&#xff0c;上述代码中的用户名 (username)、密码 (password)、主机名 (hostname) …...

探索ClickHouse——安装和测试

我们在Ubuntu 20 Server版虚拟机上对ClickHouse进行探索。 安装 检测环境 grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"SSE 4.2 supported 可以看到我们的环境支持编译版本的。如果不支持的环境…...

常用的css样式

1&#xff1a;flex布局 .flex-between {display: flex;justify-content: space-between; }.flex-evenly {display: flex;justify-content: space-evenly; }.flex-end {display: flex;justify-content: flex-end; }.flex {display: flex; }.flex-center {display: flex;justify…...

小兔鲜儿 - 微信登录

目录 微信登录​ 登录方式 静态结构​ 获取登录凭证​ 获取手机号码​ 微信登录接口(生产环境) 模拟手机登录(开发环境) 用户信息持久化存储​ 涉及知识点&#xff1a;微信授权登录&#xff0c;文件上传&#xff0c;Store 状态管理等。 微信登录​ 微信小程序的开放…...

C++ Primer阅读笔记--对象移动(右值引用、移动迭代器和引用限定符的使用)

目录 1--右值引用 2--std::move 3--移动构造函数 4--移动赋值运算符 5--移动迭代器 6--引用限定符 1--右值引用 右值引用必须绑定到右值的引用&#xff0c;通过 && 获得右值引用&#xff1b; 右值引用只能绑定到临时对象&#xff08;即将被销毁的对象&#xff09…...

Graphormer在放射性药物中的应用:螯合剂分子稳定常数与配位能力预测

Graphormer在放射性药物中的应用&#xff1a;螯合剂分子稳定常数与配位能力预测 1. 项目概述 Graphormer是一种基于纯Transformer架构的图神经网络模型&#xff0c;专门为分子图(原子-键结构)的全局结构建模与属性预测而设计。该模型在OGB、PCQM4M等分子基准测试中表现优异&a…...

音频合并避坑指南:为什么你的MP3拼接总有杂音?附FFmpeg解决方案

音频合并避坑指南&#xff1a;为什么你的MP3拼接总有杂音&#xff1f;附FFmpeg解决方案 当你尝试将多个MP3文件拼接成一个时&#xff0c;是否经常遇到以下问题&#xff1a;拼接处出现刺耳的杂音、音频卡顿或时间戳错乱&#xff1f;这并非你的操作失误&#xff0c;而是MP3格式本…...

超高压输电线路空载运行时的电压升高现象解析

1. 为什么空载时线路末端电压会升高&#xff1f; 第一次接触超高压输电线路时&#xff0c;很多工程师都会对这个现象感到困惑&#xff1a;明明没有接任何用电设备&#xff0c;为什么线路末端的电压反而比始端更高&#xff1f;这就像往一根长长的水管里注水&#xff0c;结果发现…...

YOLO-v5实战:用预训练模型快速检测图片中的物体

YOLO-v5实战&#xff1a;用预训练模型快速检测图片中的物体 1. 引言&#xff1a;为什么选择YOLO-v5 在计算机视觉领域&#xff0c;物体检测是一项基础而重要的任务。YOLO&#xff08;You Only Look Once&#xff09;系列模型因其速度快、精度高的特点&#xff0c;成为工业界和…...

全民养虾潮背后:智能体产业的产业化困局

2026年3月&#xff0c;如果你在科技园区看到有人抱着电脑排长队&#xff0c;或者听到“养虾了吗”的问候&#xff0c;不必感到奇怪。这只“虾”正是开源AI智能体——OpenClaw。从社交平台刷屏的“养龙虾”攻略到GitHub星标数突破27万&#xff0c;超越Linux登顶全球开源项目榜首…...

Amlogic S9XXX Armbian刷机完全指南:从入门到进阶的5个关键问题

Amlogic S9XXX Armbian刷机完全指南&#xff1a;从入门到进阶的5个关键问题 【免费下载链接】amlogic-s9xxx-armbian Supports running Armbian on Amlogic, Allwinner, and Rockchip devices. Support a311d, s922x, s905x3, s905x2, s912, s905d, s905x, s905w, s905, s905l,…...

Node.js后端服务开发:搭建调用Lingbot-Depth-Pretrain-ViTL-14的API接口

Node.js后端服务开发&#xff1a;搭建调用Lingbot-Depth-Pretrain-ViTL-14的API接口 你是不是遇到过这样的场景&#xff1a;手头有一个很厉害的AI模型&#xff0c;比如能估算图片深度的Lingbot-Depth-Pretrain-ViTL-14&#xff0c;但不知道怎么把它变成一个方便调用的服务&…...

告别台式机没麦克风的尴尬:用SonoBus+VB-Cable把手机秒变无线麦(保姆级配置)

台式机零成本无线麦克风方案&#xff1a;SonoBus与VB-Cable实战指南 你是否遇到过这样的尴尬时刻——台式电脑突然需要语音沟通&#xff0c;却发现没有麦克风&#xff1f;无论是紧急会议、游戏开黑还是直播互动&#xff0c;这种硬件缺失带来的困扰可能让你措手不及。本文将介绍…...

终极指南:如何在NixOS上完美打包与使用SilentSDDM主题

终极指南&#xff1a;如何在NixOS上完美打包与使用SilentSDDM主题 【免费下载链接】SilentSDDM A very customizable SDDM theme that actually looks good. 项目地址: https://gitcode.com/gh_mirrors/si/SilentSDDM SilentSDDM是一款高度可定制且视觉精美的SDDM登录主…...

别再手动转格式了!用Python的docx2pdf库5行代码搞定Word转PDF(Windows/Mac通用教程)

5行代码终结格式转换焦虑&#xff1a;Python自动化Word转PDF全攻略 每次市场部门催着要电子合同时&#xff0c;你是不是还在手忙脚乱地点击"另存为PDF"&#xff1f;当运营团队需要批量生成上百份产品手册时&#xff0c;是否还在忍受重复机械的格式转换操作&#xff1…...