Python笔记 - 函数、方法和类装饰器

news2024/11/27 16:39:38

前言

装饰器最早出现是Python2.4版本,为什么这个版本开始存在?这是因为最早标记类方法的做法是:

def foo(self):
    perform method operation
foo = classmethod(foo)

当方法体过长的时候很容易让人忽略掉最后的语句classmethod(foo),为了解决这个问题,从2.4版本引入了装饰器。

什么是装饰器?

它允许用户在不修改原有函数或方法定义的情况下,给函数或方法添加额外的功能。 装饰器本质上是一个可调用对象(比如函数),它接受一个函数作为参数,并返回一个新的函数或可调用对象。

最简单的理解就是类比代理,比如需要记录函数运行时间,我们的做法是方法执行前获取时间,执行完毕获取时间。

侵入式的做法:

def func():  
    start = time.time()  
    time.sleep(3)  
    end = time.time()  
    print(f"耗时: {end - start:.2f}")

用装饰器的做法则为:

def log_time(fn):  
    def wrapper(*args, **kwargs):  
        start = time.time()  
        fn(*args, **kwargs)  
        end = time.time()  
        print(f"耗时: {end - start:.2f}")  
    return wrapper  
  
  
@log_time  
def func():  
    time.sleep(3)

其中log_time这个函数就是装饰器

装饰器的分类

装饰器的本质是一个可执行对象,因为可执行对象包括函数和类,因此装饰器分为两种:

  1. 函数、方法装饰器
  2. 类装饰器

如果细分的话,有且只有下面四种(记住这句话有助于在使用上理清思路):

  1. 不带参数的函数装饰器
  2. 带参数的函数装饰器
  3. 不带参数的类装饰器
  4. 带参数的类装饰器

如果像上面那样def定义一个函数就是函数装饰器,如果使用class定义一个类,这个类就是类装饰器。

Note:

  1. 函数指得是普通函数,方法指的是定义在类中的函数,通常第一个参数带有(self)这种。
  2. 其实按照PEP 3129-Class Decorators类装饰器为:装饰类的函数装饰器

按照装饰器本身的分类,可以分为函数和类;按照装饰对象,可以装饰函数和类;按照装饰对象,即PEP 3129的定义我更源称其为装饰类的函数装饰器。

在这里插入图片描述

也就是说按照PEP文档描述,上图序号1才是类装饰器,而不存在序号B的概念。

但我个人更愿称序号1为装饰类的函数装饰器,而序号B才是类装饰器,至于装饰类还是函数,无关紧要;下文分类也是按照A、B分为函数装饰器和类装饰器。

函数装饰器

1. 不带参数的函数装饰器

基本格式
@dec2
@dec1
def func(arg1, arg2, ...):
    pass

上面的使用等价👇:

func = dec2(dec1(func))
具体的例子
# 定义不带参数的函数装饰器  
def dec2(fn):  
    def wrapper(*args, **kwargs):  
        print("dec2函数执行前...")  
        fn(*args, **kwargs)  
        print("dec2函数执行后...")  
    return wrapper  
  
  
def dec1(fn):  
    def wrapper(*args, **kwargs):  
        print("dec1函数执行前...")  
        fn(*args, **kwargs)  
        print("dec1函数执行后...")  
    return wrapper  
  
  
# 使用装饰器  
@dec2  
@dec1  
def func():  
    print("函数执行中...")  
  
  
if __name__ == '__main__':  
    func()

输出:
在这里插入图片描述

理解

在这里插入图片描述

dec2装饰器注释代码:

# 这里的fn = dec1(func)  
def dec2(fn):  
    # 1. wrapper是对 fn = dec1(func)的封装函数。  
    # 2. 他需要将 wrapper 这个包装后的函数返回,可以理解为代理后的函数。  
    # 3. 因此 dec2(fn) 返回的是一个装饰后的函数,本质功能还是最原始的 func 。  
    # 4. wrapper()里边的参数就是原函数的参数。  
    def wrapper(*args, **kwargs):  
        print("dec2函数执行前...")  
        fn(*args, **kwargs)  
        print("dec2函数执行后...")  
    return wrapper

dec1装饰器注释代码

# 这里的fn = func  
def dec1(fn):  
    # 1. wrapper是对 fn = func的封装函数。  
    # 2. dec2(dec1(func)) 需要理解dec2的参数,即当前这个wrapper函数。  
    # 3. 因此对于存在两个装饰器的例子,本质是嵌套,即:封装 “封装后的函数”  
    def wrapper(*args, **kwargs):  
        print("dec1函数执行前...")  
        fn(*args, **kwargs)  
        print("dec1函数执行后...")  
    return wrapper

2. 带参数的函数装饰器

基本格式
@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
    pass

上面的使用等价👇:

func = decomaker(argA, argB, ...)(func)
具体的例子
def attrs(**kwargs):  
    def decorate(fn):  
        # 为函数添加属性  
        for k, v in kwargs.items():  
            setattr(fn, k, v)  
        return fn  
    return decorate  
  
  
@attrs(name="test", age=18)  
def func():  
    print("函数执行中...")  
  
  
if __name__ == '__main__':  
    func()  
    print(func.__dict__)

输出:
在这里插入图片描述

理解
@attrs(name="test", age=18)  
def func():  
    print("函数执行中...") 

这部分代码等价于:

attrs(name="test", age=18)(func)

# 而attrs(name="test", age=18) 的返回值是 decorate 装饰器
# 装饰器 decorate 的参数才是原本的函数,在装饰器内对函数添加了属性

要点总结:

  1. 带参数的函数装饰器返回一个装饰器
  2. 真正的装饰器参数为目标函数
  3. 封装的函数参数等同目标函数参数
加深理解例子
基本格式
@accepts(int, int)  
@returns(int)  
def func(a, b):  
    return a + b  

上面的使用等价👇:

accepts(int,int)(returns(int)(func))

完整代码

def accepts(*types):  
    def check_accepts(f):  
        def wrapper(*args):  
            if not all(isinstance(arg, types) for arg in args):  
                raise TypeError("Argument %s is not of type %s" % (args, types))  
            return f(*args)  
  
        return wrapper  
  
    return check_accepts  
  
  
def returns(return_type):  
    def check_returns(f):  
        def wrapper(*args):  
            result = f(*args)  
            if not isinstance(result, return_type):  
                raise TypeError("Return value is not of type %s" % return_type)  
            return result  
        return wrapper  
  
    return check_returns  
  

@accepts(int, int)  
@returns(int)  
def func(a, b):  
    return a + b  
  
  
if __name__ == '__main__':  
    print(func(1, 1))
理解

先不看 @accepts(int, int)

@returns(int)  
def func(a, b):  
    return a + b  

Q1:上面的执行结果是什么?

上面的使用等价👇:

returns(int)(func)

returns函数注释如下:

# 1. return_type 就是 @returns(int)的入参,即 int
def returns(return_type):  
# 2. 带参数的函数装饰器,需要返回一个装饰器函数,即 check_returns   
# 3. 装饰器函数的参数就是目标函数,即 f = func    
# 4. 装饰器函数的返回值是包装函数,即 wrapper    
# 5. 包装函数等价目标函数,其参数为目标返回参数,返回值等于目标函数返回值  
	def check_returns(f):  
	    def wrapper(*args):  
	        result = f(*args)  
	        if not isinstance(result, return_type):  
	            raise TypeError("Return value is not of type %s" % return_type)  
	        return result  
	    return wrapper  
	return check_returns

Q2:returns(int)的执行结果是什么?

返回的是新的装饰器,上面的例子即check_returns函数,这部分完全可以不用看内部实现:

def returns(return_type):
	def check_returns(f):
		# 其他代码
	return check_returns

returns(int) 就是函数的调用,他的输入是:int 这是一个class对象,他的输出是:check_returns函数。

Q3:returns(int)(func)的执行结果是什么?

返回的是新的目标函数,上面的例子即wrapper函数,我们已经知道returns(int)返回的是check_returns函数,这里实际则是将目标函数func作为参数传递并且调用

def check_returns(f):  
    def wrapper(*args):  
        # 其他代码
    return wrapper

而这整个执行结果返回的是啥?就是新的目标函数,或者称包装函数 wrapper

Q4:这个包装函数有什么讲究?

包装函数的入参和返回值都和目标函数保持一致。

@returns(int)
def func(a,b):
	return a + b

上面的结果等价**定义一个函数(注意是定义不是调用)**👇:

def wrapper(*args):
	result = f(*args)  
if not isinstance(result, return_type):  
    raise TypeError("Return value is not of type %s" % return_type)  
return result

所以,完整的调用就等价下面的形式:

@accepts(int,int)
@returns(int)
def func(a,b):
	return a + b

等价

accepts(int,int)(returns(int)(func))

等价

accepts(int,int)(wrapper)

那剩下的分析,就完全一样的,只是函数装饰器accepts的目标函数是原先函数的包装函数wrapper

accepts函数注释代码:

def accepts(*types):  
    # 1. 这是一个带参数的函数装饰器,因此需要返回一个装饰器,即 return check_accepts    
    # 2. 装饰器(check_accepts)的参数是目标函数,即 f,这里的目标函数f 是被@returns装饰后的函数 wrapper    
    # 3. 装饰器的返回值是包装后的函数,即 return wrapper    
    def check_accepts(f):  
        # 4. 包装函数等价函数本身,他的参数就是目标函数的参数,即 *args 为@returns装饰后的函数 wrapper参数 *args        
        def wrapper(*args):  
            if not all(isinstance(arg, types) for arg in args):  
                raise TypeError("Argument %s is not of type %s" % (args, types))  
            return f(*args)  
        return wrapper  
    return check_accepts

Q5:最后执行的返回结果是什么?

@accepts(int,int)
@returns(int)
def func(a, b):
	return a + b

上面的执行结果是返回一个进行二次包装的函数,上面的代码是定义函数,而不是调用。

Q6:什么时候调用?

if __name__ == '__main__':  
    print(func(1, 1))

当执行这行代码的时候,实际上是调用accepts内部定义的wrapper函数,参数是(1,1)

def wrapper(*args):  
            if not all(isinstance(arg, types) for arg in args):  
                raise TypeError("Argument %s is not of type %s" % (args, types))  
            return f(*args) 

而这个函数的返回值是 f(*args) ,也就是原本函数返回啥,这里就返回啥。

到这里,整个分析就结束了;上面装饰器(@returns(int)和@accepts(int,int)) 的作用没有侵入原函数的情况下,对原函数的参数和返回值都进行了校验。

类装饰器

前置知识

在Python中,如果一个类 class A 没有定义 __init__ 方法、__call__ 方法或者 __new__ 方法,那么当你尝试直接实例化这个类(即使用 A())时,会发生以下情况:

  1. __new__ 方法
    • 实际上,每个类都有一个 __new__ 方法,它是用来创建类实例的。
    • 如果你没有显式地定义 __new__ 方法,那么Python会使用从它的父类(通常是 object)继承的默认 __new__ 方法。
    • 默认 __new__ 方法负责分配内存并返回一个实例(通常是通过调用 super().__new__(cls) 来实现的,但在没有继承关系时,直接使用 object.__new__(cls))。
  2. __init__ 方法
    • 如果没有定义 __init__ 方法,那么实例被创建后,不会有任何初始化代码被执行。
    • 这意味着实例将仅包含从其父类继承的属性和方法(如果有的话)。
  3. __call__ 方法
    • __call__ 方法与直接实例化类无关。它是当类的实例被当作函数调用时(例如 instance())才会被调用的。
    • 因此,在 A() 的上下文中,__call__ 方法不会被考虑。

当我们使用类装饰器的时候,通常意味着这个类实例是可调用对象,也就是说声明了__call__方法。

比如:

class A:
	def __call__(self, *args, **kwargs):  
	    print("__call__方法...")  

if __name__ == '__main__':  
    a = A()  
    a()

类装饰器的重点在于:实例化之后再通过()调用。

1. 不带参数的类装饰器

基本格式
@Deco
class Demo:
	pass

上面的使用等价👇:

Deco(Demo)

上面执行完返回的是Deco这个类实例对象。

具体的例子
class Deco:  
    def __init__(self, cls):  
        self.cls = cls  
  
    def __call__(self, *args, **kwargs):  
        return self.cls(*args, **kwargs)
  
  
@Deco  
class Demo:  
    pass  
  
  
if __name__ == '__main__':  
    print(Demo())
理解
@Deco  
class Demo:  
    pass  

上面的代码实际上是等价Deco(Demo),也就是说实例化Deco这个类,并且参数为Demo这个类对象。也就是执行__init__方法,因此参数cls就是目标类Demo这个类对象。

Q1:那么正常调用Demo()获取实例对象怎么办?

因此@Deco对Demo类的装饰,导致此声明返回的是一个Deco实例对象,也就是说,Demo()实际上是instance(),其中instance是Deco类对象。

前置知识说了,要让一个类实例可以通过()调用,需要声明__call__方法,因此在__call__方法内部,需要把原本Demo()返回的实例对象进行返回,即:

def __call__(self, *args, **kwargs):  
    return self.cls(*args, **kwargs)

要点总结:

  1. 用类装饰器装饰后返回的是一个类装饰器对象。
  2. 这个类装饰器对象必须定义call方法才能作为可调用对象返回原本的类实例。
加深理解的例子
基本格式
@Deco2
@Deco1
class A:
	pass

上面的使用等价👇:

Deco2(Deco1(A))

上面的代码执行完返回的是:Deco2这个类实例对象。

具备注释的完整代码
# 1. @Deco2 等价 Deco2() 由于参数即 @Deco1 装饰后返回的是 Deco1 实例对象  
class Deco2:  
    # 2. 执行Deco2() 时候会调用 __init__ 方法,而此处的参数为 Deco1 实例对象,即可调用的对象  
    def __init__(self, callable_obj):  
        self.callable_obj = callable_obj  
  
    # 3. 当使用 Demo() 的时候,最终是调用这里的 __call__ 方法  
    def __call__(self, *args, **kwargs):  
        return self.callable_obj(*args, **kwargs)  
  

	# 1. @Deco1 等价 Deco1() 且参数为类 Demo
class Deco1:  
    # 2. 执行Deco1(Demo) 时候会调用 __init__ 方法,所以__init__方法的参数就是目标类 Demo    
    def __init__(self, cls):  
        self.cls = cls  
  
    # 3. 由于返回的是类实例对象,因此一定要定义__call__方法,实例对象才是可调用对象,并且返回目标类实例对象  
    def __call__(self, *args, **kwargs):  
        return self.cls(*args, **kwargs)  
  
  
@Deco2  
@Deco1  
class Demo:  
    pass  
  
  
if __name__ == '__main__':  
    print(Demo())

2. 带参数的类装饰器

基本格式
@Deco(name="Tom")  
class Demo:  
    pass

上面的使用等价👇:

Deco(name="Tom")(Demo)
具体的例子
class Deco:  
    def __init__(self, name):  
        self.name = name  
  
    def __call__(self, cls):  
        setattr(cls, "name", self.name)  
        return cls  
  
  
@Deco(name="Tom")  
class Demo:  
    pass  
  
  
if __name__ == '__main__':  
    print(Demo.name)  
    print(Demo())
理解

无论是函数装饰器还是类装饰器,带参数和不带参数的本质区别是使用了()表示立即调用。

由于上面的使用等价:

Deco(name="Tom")(Demo)

Deco(name="Tom")已经返回了Deco类实例对象,因此实例对象(Demo)的时候,实际调用的就是__call__方法,因此这种情况下,目标类Demo,在__call__方法内进行传递,而不是__init__方法。

加深理解的例子
基本格式
@Deco2(name="Tom")
@Deco1(age=18)
class Demo:
	pass

上面的使用等价👇:

Deco2(name="Tom")(Deco1(age=18)(Demo))
具备注释的完整代码
# 1. 由于上一步返回的就是目标类对象,因此这里的使用完全等价 Deco1
class Deco2:  
    def __init__(self, name):  
        self.name = name  
  
    def __call__(self, cls):  
        setattr(cls, "name", self.name)  
        return cls  
  
  
# 1. @Deco1(age=18) 等价 Deco1(age=18)(Demo) 
# 2. 由于 Deco1(age=18) 已经是实例化对象了,因此 Deco1(age=18)(Demo) 实际上是调用 __call__方法  
# 3. 所以装饰后的结果返回的是 __call__ 方法的返回值!  
class Deco1:  
    def __init__(self, age):  
        self.age = age  
  
    def __call__(self, cls):  
        setattr(cls, "age", self.age)  
        return cls  
  
  
@Deco2(name="Tom")  
@Deco1(age=18)  
class Demo:  
    pass  
  
  
if __name__ == '__main__':  
    print(Demo)  
    print(Demo.name)  
    print(Demo.age)

要点总结

  1. @语法糖,就可以理解当前装饰器后面加一个()表示立即调用,其参数为装饰的目标对象(类、函数或者可调用的实例对象)
  2. 装饰器的本质是一个可调用对象(函数,类)
  3. 装饰器的输入是一个可调用对象(函数,类,可调用的实例对象)
  4. 装饰器的输出是一个可调用对象(函数,类,可调用的实例对象)

使用场景例子

1. 不带参数的函数装饰器

@abstractmethod

用于标记一个类方法为抽象方法。

源码如下:

def abstractmethod(funcobj):  
    funcobj.__isabstractmethod__ = True  
    return funcobj

Note:不带参数的函数装饰器返回函数本身(或者包装后的函数),通常只是对原有函数做一些封装。

2. 带参数的函数装饰器

@attrs

用于为目标函数添加属性。

源码如下:

def attrs(**kwargs):  
    def decorate(fn):  
        # 为函数添加属性  
        for k, v in kwargs.items():  
            setattr(fn, k, v)  
        return fn  
    return decorate  

使用:

@attrs(author="tough",version="1.0")
def add(a, b)
	return a + b

Note:带参数的函数装饰器通常可以更灵活的利用参数设置一些我们期望的信息。

3. 不带参数的类装饰器

类装饰器一个经典的用法是,利用类仅做容器作用,真正的装饰器还是函数装饰器,即定义在类内部的函数。

class Decorator:  
    def info(self, fn):  
        print(fn.__name__)  
        return fn  
  
  
decorator = Decorator()  
  
  
@decorator.info  
def add(a, b):  
    return a + b  
  
  
if __name__ == '__main__':  
    add(1, 1)

另外常见的如:@staticmethod, @classmethod 均为不带参数的类装饰器。

4. 带参数的类装饰器

比如Flask框架中的使用:

app = Flask(__name__)
@app.route('/')
def hello_world():
   return 'This Index Page'

利用带参数的类装饰器实现元注解功能:

import types  
from enum import Enum  
  
  
class Annotation:  
    class ElementType(Enum):  
        class Type:  
            def __init__(self, name, value, label):  
                self.name = name  
                self.value = value  
                self.label = label  
  
        TYPE = Type('type', type, '类')  
        METHOD = Type('method', types.FunctionType, '函数')  
  
    def __init__(self, elementType: ElementType):  
        self.elementType = elementType  
  
    def __call__(self, cls):  
        cls.elementType = self.elementType  
        return cls  
  
  
@Annotation(Annotation.ElementType.METHOD)  
class AliaFor:  
    def __init__(self, cls):  
        self.cls = cls  
  
    def __call__(self, *args, **kwargs):  
        if not isinstance(self.cls, self.elementType.value.value):  
            raise TypeError(f"{self.cls.__name__} 不是一个{self.elementType.value.label},其类型为{type(self.cls).__name__},@AliaFor只能装饰{self.elementType.value.label}。")  
        return self.cls(*args, **kwargs)  
  
  
@AliaFor  
class A:  
    pass  
  
  
if __name__ == '__main__':  
    print(A())

上面的代码功能为@Annotation(Annotation.ElementType.METHOD)标记一个类为注解类,只能作用在方法上,如果作用在类上则报错。

输出:
在这里插入图片描述


🔗参考链接

[1]:官方文档函数装饰器 PEP 318
[2]:官方文档类装饰器 PEP 3129
[3]:博客 # 小白了解Python中类装饰器,看这篇就够了
[4]:博客 # Python笔记 - 利用装饰器设计注解体系

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

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

相关文章

Win10之解决:设置静态IP后,为什么自动获取动态IP问题(七十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【…

域内密码喷洒 Password Spray 实验

password spray 1. 实验网络拓扑 kali: 192.168.72.128win2008: 192.168.135.129 192.168.72.139win7: 192.168.72.149win2012:(DC) 192.168.72.131 2. 简单原理 Kerberos针对同一个用户,多次的密码尝试请求有锁定保护策略。 但是我们可以切换用户,…

【Streamlit案例】制作销售数据可视化看板

目录 一、案例效果 二、数据分析 三、加载数据 四、网站前端 (一)网页标题和图标 (二)侧边栏和多选框 (三)主页面信息 ​(四)主页面图表 (五)隐藏部…

基于四种网络结构的WISDM数据集仿真及对比:Resnet、LSTM、Shufflenet及CNN

在上节中,我们已经详细介绍了WISDM数据集及如何使用CNN网络训练,得到了六个维度的模型仿真指标及五个维度的可视化分析,那么现在我们将训练模型推广到其他网路结构中去,通过仿真实验来对比一下不同网络之间对于WISDM数据集的训练效…

【docker笔记8-镜像推送】

docker笔记8-镜像推送 一、基本命令二、案例1.Java demo2.打包镜像 一、基本命令 (1)推送镜像到远程仓库 docker tag local-image:tagname new-repo:tagname docker push new-repo:tagname这里首先要登录到docker,然后需要输入登录用户名和…

构建electron项目

1. 使用electron-vite构建工具 官网链接 安装构建工具 pnpm i electron-vite -g创建electron-vite项目 pnpm create quick-start/electron安装所有依赖 pnpm i其他 pnpm -D add sass scss1. 启动项目 2. 配置 package.json "dev": "electron-vite dev --…

【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错

1. 运行项目 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Appl…

Chromium 修改UA的几种办法方法c++

第一种方式 启动浏览器添加命令行 格式 --user-agent"自定义的UA" 1、C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe --user-agent"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome…

vgg19提取特征

一般来说,大家使用VGG16,用的是第四列的网络架构,而使用VGG19,使用的就是第六列的网络架构。 使用vgg进行提取特征,在这个项目中,使用的就是每一块卷积层的第一层。 import torch.nn as nn from torchvis…

T10:数据增强

T10周:数据增强 **一、前期工作**1.设置GPU,导入库2.加载数据 **二、数据增强****三、增强方式**方法一:将其嵌入model中方法二:在Dataset数据集中进行数据增强 **四、训练模型****五、自定义增强函数****六、总结** 🍨 本文为&am…

idea使用ant源码运行tomcat8.5

1 安装ant 下载ant 下载地址 使用apache-ant-1.10.15版本 将压缩包放到/Library/Java/ant解压 设置ant环境变量 打开finder到用户根目录 按下shiftcmd.显示隐藏文件 打开隐藏文件.zprofile 按照以下格式设置环境变量 #ant export ANT_HOME/Library/Java/ant/apache-a…

数据丢失怎么办?2024四款恢复工具帮你忙!

数据是我们日常生活和工作中不可或缺的一部分,然而,由于误操作、硬件故障或其他原因导致的数据丢失却是常有的事情。这时候,一款可靠的数据恢复工具就显得尤为重要。 福昕数据恢复 直达链接:www.pdf365.cn/foxit-restore/ 假设…

Linux命令:用于显示 Linux 发行版信息的命令行工具lsb_release详解

目录 一、概述 二、用法 1、基本用法 2、选项 3、获取帮助 三、示例 1. 显示所有信息 2. 只显示发行版名称 3. 只显示发行版版本号 4. 只显示发行版代号 5. 只显示发行版描述 6. 只显示值,不显示标签 四、使用场景 1、自动化脚本 2、诊断问题 3、环…

【KVM】虚拟化技术及实战

一,KVM简介 KVM全称为QEMU-KVM。 KVM可以模拟内存,cpu的虚拟化,不能模拟其他设备虚拟化。 QEMU可以模拟I/O设备(网卡,磁盘等) 两者结合,实现真正意义上的虚拟化。 从rhel6版本开始&#xff0c…

Elasticsearch——数据聚合、数据同步与集群搭建

目录 1.数据聚合1.1.聚合的种类1.2.DSL实现聚合1.2.1.Bucket 聚合语法1.2.2.聚合结果排序1.2.3.限定聚合范围1.2.4.Metric 聚合语法1.2.5.小结 1.3.RestAPI 实现聚合1.3.1.API 语法1.3.2.业务需求1.3.3.业务实现 2.自动补全2.1.拼音分词器2.2.自定义分词器2.3.自动补全查询2.4.…

YOLOv8 结合设计硬件感知神经网络设计的高效 Repvgg的ConvNet 网络结构 ,改进EfficientRep结构

一、理论部分 摘要—我们提出了一种硬件高效的卷积神经网络架构,它具有类似 repvgg 的架构。Flops 或参数是评估网络效率的传统指标,这些网络对硬件(包括计算能力和内存带宽)不敏感。因此,如何设计神经网络以有效利用硬件的计算能力和内存带宽是一个关键问题。本文提出了一…

Chromium 使用安全 DNS功能源码分析c++

一、选项页安全dns选项如下图: 二、那么如何自定义安全dns功能呢? 1、先看前端部分代码调用 shared.rollup.jsclass PrivacyPageBrowserProxyImpl {.................................................................getSecureDnsResolverList() {re…

25货拉拉校园招聘面试经验 面试最常见问题总结

货拉拉校园招聘面试经验 目录 【面试经历】 问题+详细答案 面试全流程 【面试经历】 发面经,攒人品。 项目问题: 1.AOP日志落库到数据库,为什么不用一些现成的方案? 2.邀请链接的id怎么用redis生成的? 3.乐观锁保证了奖励的正确发放,请你说说乐观锁的原理。 4.奖…

TCN模型实现电力数据预测

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有:中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等,曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝,拥有2篇国家级人工智能发明专利。 社区特色&a…

AI少女/HS2甜心选择2 仿天刀人物卡全合集打包

内含AI少女/甜心选择2 仿天刀角色卡全合集打包共21张 下载地址:https://www.51888w.com/408.html 部分演示图: