Python 装饰器decorator 圣经

文章目录

  • 普通装饰器decorator
    • 0. 万能公式,非常重要
    • 1. 便于入门的decorator原理
    • 2. 理解函数
    • 3. 装饰器的作用:
    • 4. 装饰器的语法糖
    • 5. 装饰器顺序
    • 6. 极简的装饰器
    • 7. 装饰器的参数
      • 无参 函数装饰器
      • 有参 函数装饰器
  • 类装饰器class decorator
    • 0. 万能公式,非常重要
    • 1. 可以成为装饰器的类
      • 无参 装饰器类
      • 有参 装饰器类
    • 2. 可以装饰类的装饰器
      • 无参 可以装饰类的装饰器
      • 有参 可以装饰类的装饰器
  • 如何把装饰器放到类里面
  • @warps详解
      • 装饰器中`@wraps(view_func)`的作用
      • 不加@wraps的例子
      • 加@wraps后

普通装饰器decorator

0. 万能公式,非常重要

  • 在一个函数上添加装饰器,就等价于,这个函数名=装饰器调用这个函数

1. 便于入门的decorator原理

  • decorator是一个输入和输出都是函数的函数。请暂时这样理解,以便入门。

2. 理解函数

  • 在Python中定义一个函数,其实就是新建了一个变量,这个变量里保存了函数对象

    def double(x):return x * 2
    print(double)  # <function double at 0x10688a710>
    
  • 函数对象有一个特点就是callable,在Python中callable这个东西后面是可以跟一对小括号的,从而调用它。

    print(double(2))  # 4
    
  • 实际上在Python的语法层面,任何的东西都可以调用,只不过如果这个东西不是callable的话,会在Python的runtime时会出错。

    import dis
    # 例如我们让1进行调用,那么也是可以通过编译的,只不过会给出syntax warning,但是它的字节码表示一样可一LOAD完这个1之后再尝试call它
    dis.dis("1()")
    
  • 当我们理解了函数在Python中只是一个普通的对象后,我们就可以理解函数可以被当作参数传进其他的函数里。

    def double(x):return x * 2
    def triple(x):return x * 3
    def calc_number(func, x):print(func(x))calc_number(double, 3)  # 6
    calc_number(triple, 3)  # 9
    
  • 函数不单单可以作为变量传进其他函数,函数本身也可以成为一个返回值。

    def get_multiple_func(n):def multiple(x):# multiple函数return什么值是由get_multiple_func的n决定的return n * xreturn multipledouble = get_multiple_func(2)
    triple = get_multiple_func(3)print(double(2))  # 4
    print(triple(3))  # 9
    

    此时我们就理解了“函数的返回值可以是一个函数”,那么decorator相对来说就容易理解了。

3. 装饰器的作用:

在不改变原有功能代码的基础上,添加额外的功能,如用户验证等。

4. 装饰器的语法糖

@ 符号是装饰器的语法糖。它放在一个函数开始定义的地方(头顶),和这个函数绑定在一起。

在我们调用这个函数的时候,会先将这个函数做为参数传入它头顶,即装饰器里。

5. 装饰器顺序

一个函数可以同时定义多个装饰器,比如:

@a
@b
@c
def f ():pass

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于:

f = a(b(c(f)))

6. 极简的装饰器

  • decorator本身就是一个callable,它没有特殊的地方,那么我们可以暂时理解为decorator本身就是一个函数,@后面跟的这个名字就是函数名,我们定义了一个函数叫做dec
def dec(f):pass@dec
def double(x):return x * 2# 第4行到第6行的代码完全等价于:double = dec(double)
  • decorator是一个输入和输出都是函数的函数。当然了输入一定是函数,但是输出不一定是,下面是极端的例子,没有人会这样写代码。

    def dec(f):return 1@dec
    def double(x):return x * 2print(double)  # 1
    

    注意,我们print的是double本身,而不是对double进行调用。

    double = dec(double)
    # dec(double)返回的是1
    # 1被赋值给double变量
    # print(double)就是1
    
  • 上面的例子只是极端情况,我们还是要认为decorator就是输入和输出都是函数的函数。

7. 装饰器的参数

无参 函数装饰器

import timedef timeit(f):def wrapper(x):start = time.time()ret = f(x)print(time.time() - start)return retreturn wrapper# 等价于:my_func = timeit(my_func)
@timeit
def my_func(x):time.sleep(x)my_func(1) # 等价于:timeit(my_func)(1)
# 这是通用写法,用可变参数来适配各种被包装的函数
import timedef timer(func):def wrapper(*args, **kwargs):start_time = time.time()func(*args, **kwargs)  # 这是函数真正执行的地方stop_time = time.time()cost_time = stop_time - start_timeprint("花费时间:{}秒".format(cost_time))return wrapper@timer
def want_sleep(sleep_time):time.sleep(sleep_time)want_sleep(3)

有参 函数装饰器

import timedef timeit(iteration):  # iteration是运行多少次。返回的是inner函数,相当于是之前没有参数的decoratordef inner(f):def wrapper(*args, **kwargs): # 里面运行了iteration次的函数fstart = time.time()for _ in range(iteration):ret = f(*args, **kwargs)print(time.time() - start)return retreturn wrapperreturn inner# 等价于:double = timeit(10)(double)
# 即:
# inner = timeit(10)
# double = inner(double)
@timeit(10)
def double(x):return x * 2double(1) # 等价于:timeit(10)(double)(1)
import timedef timer(sleep_time):def outter(func):def wrapper(*args, **kwargs):start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())print("start_time:" + str(start_time))result = func(*args, **kwargs)  # 这是函数真正执行的地方time.sleep(sleep_time)stop_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())print("stop_time:" + str(stop_time))return resultreturn wrapperreturn outter@timer(sleep_time=3)
def sleep_status(name):print(name + " is sleeping...")return name + " is wake..."r = sleep_status("zhangsan")
print(r)# 输出
# start_time:2022-09-23 23:53:16
# zhangsan is sleeping...
# stop_time:2022-09-23 23:53:19
# zhangsan is wake...

类装饰器class decorator

  • 类装饰器class decorator这个名称实际上是有一定的歧义的。

    • 在有些地方是指:“可以成为装饰器的类”。这说的是装饰器本身。用中文的语境来描述,应该是“装饰器类”,而不是“类装饰器”。
    • 在有些地方是指:“可以装饰类的装饰器”。这说的是装饰器要装饰的对象。用中文的语境来描述,应该是“类 的 装饰器”。
  • 装饰器本身既可以是函数,还可以是类。而装饰的对象同样既可以是函数也可以是类。

0. 万能公式,非常重要

  • 万能公式非常重要,只要你把它转换成等价形式,decorator就比较好读,而转换成等价形式之后,我们就知道代码如何写,它的输入应该是什么,它的输出应该是什么。

1. 可以成为装饰器的类

装饰器类 的实现,必须实现__call____init__两个内置函数。

当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

无参 装饰器类

__init__:接收被装饰函数
__call__:实现装饰逻辑。

import timeclass Timer:def __init__(self, func):# 函数add被传入__init__方法里,所以add被作为参数保存在了self.func里self.func = func# __call__魔术方法的意思,让所有这个类的实例都变成一个callable# 简单理解就是这个类的实例,都可以当作函数用,你都可以调用它 即在后面用小括号def __call__(self, *args, **kwargs):start = time.time()ret = self.func(*args, **kwargs)  # self.func就是原来的add函数print(f"Time: {time.time() - start}")return ret# 把Timer这个类本身当作一个装饰器,装饰在了add函数上
# 等价于:add = Timer(add)
# @Timer装饰器相当于把名为add的变量,其值从一个函数变成了一个Timer类的实例
@Timer
def add(a, b):return a + bprint(type(add))  # <class '__main__.Timer'>
print(add(2, 3))  # 实际上是调用了Timer类的实例add的__call__方法,此时2和3参数就被传到__call__的参数里。
"""
Time: 5.7220458984375e-06
5
"""
  • 通过上面的例子,我们可以看到和前面讲的函数decorator其实没有很大的区别。原来的函数装饰器是“函数调用一个函数返回一个函数”,更确切的说是“函数调用一个函数返回一个callable”。
  • 现在是类调用一个函数返回一个实例,这个实例依然是callable
  • 所以我们只需要把decorator在脑海中进行等价转换就非常容易理解了。
class Logger(object):def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print("[INFO]: the function {func}() is running..." \.format(func=self.func.__name__))return self.func(*args, **kwargs)@Logger
def say(something):print("say {}!".format(something))say("hello")# 输出
# [INFO]: the function say() is running...
# say hello!

有参 装饰器类

带参数和不带参数的类装饰器有很大的不同。

__init__ :不再接收被装饰函数,而是接收传入参数。
__call__:接收被装饰函数,实现装饰逻辑。

import timeclass Timer:def __init__(self, prefix):self.prefix = prefixdef __call__(self, func):def wrapper(*args, **kwargs):start = time.time()ret = func(*args, **kwargs)print(f"{self.prefix} {time.time() - start}")return retreturn wrapper# 等价于:add = Timer(prefix="curr_time: ")(add)
# 那么此时add就是wrapper了
@Timer(prefix="curr_time: ")
def add(a, b):return a + bprint(add(2, 3))
"""
curr_time:  1.9073486328125e-06
5
"""
class Logger(object):def __init__(self, level='INFO'):self.level = leveldef __call__(self, func):  # 接受函数def wrapper(*args, **kwargs):print("[{level}]: the function {func}() is running..." \.format(level=self.level, func=func.__name__))func(*args, **kwargs)return wrapper  # 返回函数@Logger(level='WARNING')
def say(something):print("say {}!".format(something))say("hello")# 输出
# [WARNING]: the function say() is running...
# say hello!

2. 可以装饰类的装饰器

无参 可以装饰类的装饰器

  • 在Python里,自定义的class类的实例,如果我们直接打印实例,是不会打印出任何有价值的信息的,只会打印出这个实例对象是一个什么类。

    class MyObject:def __init__(self, a, b):self.a = aself.b = bo = MyObject(1, 2)
    print(o)  # <__main__.MyObject object at 0x109447fd0>
    
  • 那么我们可以通过重载其__str__方法,来改变print出来的结果

    class MyObject:def __init__(self, a, b):self.a = aself.b = bdef __str__(self):return str(self.__dict__)o = MyObject(1, 2)
    print(o)  # {'a': 1, 'b': 2}
    
  • 当然,如果每一个对象都改的话也挺麻烦的。此时“装饰类的装饰器”就派上了用场。

# add_str函数是一个参数是class,返回值也是class 的函数
def add_str(cls):"""这个decorator本质就是重载了一下这个class的__str__方法"""def __str__(self):  # 自定义了一个名为__str__的函数,当然这个函数也可以叫任意名,但是为了规范我们不要随意起名return str(self.__dict__)# 将接收的class对象的__str__方法给替代成了add_str自己定义的__str__函数cls.__str__ = __str__return cls# 等价于:MyObject = add_str(MyObject)
@add_str
class MyObject:def __init__(self, a, b):self.a = aself.b = bo = MyObject(1, 2)
print(o)  # {'a': 1, 'b': 2}
  • 所以,给类写装饰器也没有什么难的,就是输入一个类返回一个类,然后在这个装饰器里面对传入的类动动手脚,完成我们需要的事情。

有参 可以装饰类的装饰器

# add_str函数是一个参数为greet的函数,返回一个参数为cls的inner函数
def add_str(greet):def inner(cls):print(greet)def say(self):return str(self.__dict__)# 将inner接收的class对象的__str__方法给替代成了inner自己定义的say函数cls.__str__ = sayreturn clsreturn inner# 等价于:MyObject = add_str("hello")(MyObject)
# 也就是:
# inner = add_str("hello")
# MyObject = inner(MyObject)
@add_str("hello")
class MyObject:def __init__(self, a, b):self.a = aself.b = b"""
什么都不写,也会打印出hello,因为inner(MyObject)的时候,会执行inner函数,打印出hello
"""
o = MyObject(1, 2)
print(o)  # {'a': 1, 'b': 2}

如何把装饰器放到类里面

# 简单的装饰器,作用就是在函数运行之前打印start,在函数运行结束打印end
def log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@log_function
def fib(n):"""斐波那契函数"""if n <= 1:return 0return fib(n - 1) + fib(n - 2)fib(3)
"""
function start!
args: (3,)
function start!
args: (2,)
function start!
args: (1,)
function end!
function start!
args: (0,)
function end!
function end!
function start!
args: (1,)
function end!
function end!
"""

可以看到装饰器虽然用处不大,但是确实是工作了的,勉强算是能帮助我们理解递归。

我们一般写装饰器的时候,通常是把装饰器的代码定义在py文件的最外层,然而并不是所有的函数都适合放到全局空间里的。

如果我们就是想把装饰器放到类里面,或者说我们有若干个功能相似的装饰器,就是希望将其归类到同一个类里面,下面就让我们介绍一下如何把装饰器放到类里。

# 这是我们最容易想到的一种实现
class Decorators:def log_function(self, func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapperd = Decorators()  # <__main__.Decorators object at 0x10dab7fd0>@d.log_function
def fib(n):if n <= 1:return 0return fib(n - 1) + fib(n - 2)fib(3)

本质上就是把一个函数变成类的方法,所以这里我们仅仅是把函数加上self argument然后扔到类里面。

当我们使用这种方式的时候,你一定要意识到:一个类的方法,必须由这个类的实例对象所调用。所以当我们想使用这个装饰器的时候,我们首先要建立一个Decorators这个class的object,也就是12行代码,创建实例对象。

后面我们就可以用@d.log_function来装饰这个斐波那契函数。这种方式得到的结果和之前是一样的。

但是这样用是有问题的:

  • 非常明显的,我们为了使用这个装饰器,迫不得已的要建立一个新的对象。
  • 其次,我们这个装饰器里面莫名其妙的出现了self argument,然后我们这个装饰器压根就没有用到它。

为了解决问题:

  • 我们可以把类里面定义的方法变成class method,也就是把这个方法从对象调用变成一个类就可以调用的方法,我们使用@classmethod装饰器,那么在12行的时候就不需要新建一个对象才能使用这个装饰器了。我们可以直接在14行@Decorators.log_function来调用这个装饰器。

    • 但是这个class method的第一个argument依然是cls,我们依旧没有用到这个变量。

    • 如果我们这个装饰器会根据这个class或者这个object的变化而变化,从而改变装饰器自己的功能,那么在这种情况下,我们当然是可以这样写的。

    • 但是,如果我们只是单纯的想把装饰器放到类里面做一个封装,我们就可以考虑把class method变成一个static method。

    • 所以当你仅仅需要把一个装饰器封装到一个类里面的时候,下面的代码就是一个非常不错的方式:

      # 仅仅需要把一个装饰器封装到一个类里面的时候,这里的代码就是一个非常不错的实现
      class Decorators:@staticmethoddef log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@Decorators.log_function
      def fib(n):if n <= 1:return 0return fib(n - 1) + fib(n - 2)fib(3)
      
  • 然而。。。还没完。如果我想用我类里面定义的属于这个类的装饰器去装饰我这个类里面的其他方法时,我应该怎么做?如下所示,怎么做?

    # 把fib函数移到了Decorators类里
    class Decorators:@staticmethoddef log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@log_functiondef fib(self, n):  # 在Python3.9中会报错TypeError: 'staticmethod' object is not callable;而在Python3.10中不会if n <= 1:return 0return self.fib(n - 1) + self.fib(n - 2)d = Decorators()
    d.fib(3)
    
  • 让我说的再明确点:我有一个类,类里面有很多的方法都希望用装饰器给它们装饰一下,但是我这个装饰器只会在这个类里面用,我又想把这个装饰器给封装到这个类里来。

正确的用法是:直接把log_function这个函数原封不动的放到这个Decorators class里

# 正确的做法,把fib函数原封不动的移到Decorators类里
class Decorators:def log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@log_functiondef fib(self, n):if n <= 1:return 0return self.fib(n - 1) + self.fib(n - 2)d = Decorators()
d.fib(3)

相信你,已经懵了。。你:“我从来没在Python里见到过长成这样的类的方法”。但是当你运行的时候你会神奇的发现这是可以运行的哦~

原因很简单:“当我们在定义一个新的class的时候,本质上是把class里面的code block在另外一个命名空间里运行了一下”。只不过我们非常不习惯看到这种没有self的method,但实际上这个log_function也不是一个method,你可以认为它是在我们定义这个类的时候里面的一个辅助函数或者是一个辅助的decorator。

意思就是说当我们尝试在这个类的定义之外 使用@d.log_function的时候,会报错。因为Python会尝试把这个log_funciton当成一个正常的对象方法去解读。

# 在类的定义之外使用d.log_function时报错
class Decorators:def log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@log_functiondef fib(self, n):if n <= 1:return 0return self.fib(n - 1) + self.fib(n - 2)d = Decorators()
@d.log_function
def f():  # TypeError: Decorators.log_function() takes 1 positional argument but 2 were givenpass
f()

当然,我们我们直接使用@Decorators.log_function,则是可以工作的,因为@Decorators.log_function就是一个正常的函数。

# 直接使用 @Decorators.log_function 则是可以正常运行
class Decorators:def log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@log_functiondef fib(self, n):if n <= 1:return 0return self.fib(n - 1) + self.fib(n - 2)@Decorators.log_function
def f():pass
f()

最后,到底有没有一种方式,可以把我这个装饰器封装到类里,在这个类里可以正常使用;而在这个类之外,无论是通过实例对象调用、还是通过类调用都可以正常使用呢?

答案是有的!!!你只需要在类定义的最后加上log_function = staticmethod(log_function)这行代码即可

# 最终、最正确的实现方式
class Decorators:def log_function(func):def wrapper(*args, **kwargs):print("function start!")print(f"args: {args}")ret = func(*args, **kwargs)print(f"function end!")return retreturn wrapper@log_functiondef fib(self, n):if n <= 1:return 0return self.fib(n - 1) + self.fib(n - 2)# 加上下面的代码,这行代码的本质和在log_function的定义上加一个@staticmethod这个装饰器是一样的,这两种方式是等价的# 注意区别:下面的方式在Python3.9中就不会报TypeError的错误了!# 只不过用@staticmethod装饰器的语法只能在定义log_function的同时去装饰它,而当我们使用@staticmethod装饰器的等价语法的时候,我们可以先定义log_function成为一个正常的函数,然后在class的definition里面把log_function当成一个正常的装饰器去使用,最后再通过log_function=staticmethod(log_function)把这个log_function变成一个static methodlog_function = staticmethod(log_function)@Decorators.log_function
def f1():pass
f1()d = Decorators()
@d.log_function
def f2():pass
f2()

通过上面的代码,现在无论我们是使用Decorators.log_function还是使用它的对象d.log_function,都能正确的执行这个装饰器的功能了。

@warps详解

__name__用来显示函数的名称,__doc__用来显示文档字符串也就是(“”“文档字符串”“”)这里面的内容。

文档字符串用于解释文档程序,帮助程序文档更加简单易懂。

可以在函数体的第一行使用一对三个单引号 ‘’’ 或者一对三个双引号 “”" 来定义文档字符串。

使用__doc__(注意双下划线)调用函数中的文档字符串属性。

装饰器中@wraps(view_func)的作用

不改变使用装饰器原有函数的结构(如name, doc)。

装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)。

为了不影响,Python的functools包中提供了一个叫**@wraps**的装饰器来消除这样的副作用。

写一个装饰器的时候,最好在实现之前加上functools中的wraps,它能保留原有函数的名称和文档字符串(DocStrings)。

不加@wraps的例子

def my_decorator(func):def wrapper(*args, **kwargs):"""decorator"""print("Decorated function...")return func(*args, **kwargs)return wrapper@my_decorator
def t():"""TestWord"""print("Test function")t()
# 输出:
# Decorated function...
# Test functionprint(t.__name__)  # wrapper
print(t.__doc__)  # decorator

执行的整个过程:在调用t()函数时,首先会调用装饰器(将t作为参数传入到装饰器中),执wrapper函数,再执行t函数。

但我们可以看到t函数的名字:__name__为wrapper,__doc__为decorator,已经不是原来的test函数了。

加@wraps后

from functools import wrapsdef my_decorator(func):@wraps(func)def wrapper(*args, **kwargs):"""decorator"""print("Decorated function...")return func(*args, **kwargs)return wrapper@my_decorator
def t():"""TestWord"""print("Test function")t()
# 输出:
# Decorated function...
# Test functionprint(t.__name__)  # t
print(t.__doc__)  # TestWord

会发现,test函数的__name____doc__还是原来的,即函数名称和属性没有变换。

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

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

相关文章

判断一个整数是不是2的阶次方

boolean check(){int sum 50;boolean flag true;while(sum > 1){if (sum % 2 0){sum sum % 2;}else {flag false;break;}}return flag;}

uView ScrollList 横向滚动列表

该组件一般用于同时展示多个商品、分类的场景&#xff0c;也可以完成左右滑动的列表。 #平台差异说明 App&#xff08;vue&#xff09;App&#xff08;nvue&#xff09;H5小程序√√√√ #基本使用 通过slot传入内容 <template><u-scroll-list><view v-for…

echarts line绘制机组开关状态折线图

2024.3.12今天我学习了如何用echarts line实现设备开关状态的效果。 代码如下&#xff1a; option {xAxis: {type: time,},yAxis: {type: value,splitNumber:2,// axisLine: {// show: true,// lineStyle: {// color:#808080// }// },axisLabel:{formatt…

管控员工上网行为(让老板管理更省心更高效)

很多老板都有这样一种顾虑&#xff1a; 员工到底有没有认真工作&#xff0c;工作是不是做到了全身心投入。 为什么会有担心员工工作状态的问题发生&#xff1f; 无疑是员工在上班时间浏览与工作无关的网站、下载私人文件、甚至是泄露公司机密等行为&#xff0c;让老板不放心了…

Elasticsearch:在本地使用 Gemma LLM 对私人数据进行问答

在本笔记本中&#xff0c;我们的目标是利用 Google 的 Gemma 模型开发 RAG 系统。 我们将使用 Elastic 的 ELSER 模型生成向量并将其存储在 Elasticsearch 中。 此外&#xff0c;我们将探索语义检索技术&#xff0c;并将最热门的搜索结果作为 Gemma 模型的上下文窗口呈现。 此外…

【Python】探索PyPinyin 库:Python 中的中文拼音转换工具

花未全开月未圆&#xff0c; 半山微醉尽余欢。 何须多虑盈亏事&#xff0c; 终是小满胜万全。 —— 《对抗路—吕布》 PyPinyin 是一个功能强大的 Python 库&#xff0c;用于将中文文本转换为拼音。它提供了丰富的功能&#xff0c;能够满足各种中文文本处理的需求。在本文中&am…

岭回归:优化预测的利器

在数据科学和机器学习的领域&#xff0c;构建准确、稳定的预测模型是一项至关重要的任务。岭回归作为一种强大的工具&#xff0c;被设计用来应对数据集中存在多重共线性的问题&#xff0c;并通过引入正则化来缩小预测误差。 1. 岭回归的原理&#xff1a; 岭回归是线性回归的一…

js使用canvas实现图片鼠标滚轮放大缩小拖拽预览

html代码 todo 实现画矩形框&#xff0c;圆形roi <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title&…

【国产】API接口管理平台的产品设计与搭建讲解

【国产接口管理平台】PhalApi Pro (π框架专业版) PhalApi Pro (发音&#xff1a;π框架专业版)&#xff0c;是一款国产企业级API接口管理平台&#xff0c;可以零代码、快速搭建API接口开发平台、接口开放平台、接口管理平台。基于PhalApi开源接口开发框架&#xff0c;通过低代…

在java的类中即可以有main方法也可以没有main方法

原理: 在Java中&#xff0c;一个类可以没有main方法。main方法是Java程序的入口点&#xff0c;它是程序执行的起始点。如果一个类没有main方法&#xff0c;那么该类无法直接作为可执行程序运行。 然而&#xff0c;一个Java程序可以包含多个类&#xff0c;其中只需要一个类包含…

【gpt实践】李某的AI课程值199吗

先说个人的答案&#xff1a;不值。但也不是说毫无价值&#xff0c;只是他的价值没那么高。 文末分享该课程&#xff0c;大家有兴趣可以看看&#xff0c;该课程是否有价值。 “清华博士”推出的199元的AI课程销售额竟然突破了5000万。这一数字让人惊叹&#xff0c;也引发了人们…

亚马逊、速卖通卖家如何做好测评让店铺销量稳定增长?

近期有刚入驻跨境电商的新买家咨询珑哥&#xff0c;店铺上的产品有人浏览&#xff0c;就是没有人下单&#xff0c;新店铺很正常因为很多人去购买东西&#xff0c;首先看的是评价&#xff0c;没有评价一般人不敢直接去下单。就像我们去淘宝买东西&#xff0c;都要看下评价&#…

一次性插入10万条数据,该如何操作?

参考:10万条数据批量插入&#xff0c;到底怎么做才快&#xff1f; - 知乎 (zhihu.com) 首先一般有两种方式&#xff1a;1.使用jdbc批处理模式 2.使用insert into values方式 第一种方式&#xff1a;他的优势是jdbc会帮我们进行预编译&#xff0c;然后把预编译结果缓存起来&a…

题解:P9176 [COCI2022-2023#4] Vrsta

什么是线段树&#xff0c;超详细讲解 思路 考虑以每个身高作为下标&#xff0c;维护每个身高的数量&#xff0c;很显然不同的身高最多有 2 1 0 5 2\times 10^5 2105 个&#xff0c;考虑离散化&#xff0c;代码如下&#xff1a; for (int i 1; i < n; i ) {int x a[i]…

测试用例的设计(2)

目录 1.前言 2.正交排列(正交表) 2.1什么是正交表 2.2正交表的例子 2.3正交表的两个重要性质 3.如何构造一个正交表 3.1下载工具 3.1构造前提 4.场景设计法 5.错误猜测法 1.前言 我们在前面的文章里讲了测试用例的几种设计方法,分别是等价类发,把测试例子划分成不同的类…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Web)上篇

提供具有网页显示能力的Web组件&#xff0c;ohos.web.webview提供web控制能力。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。示例效果请以真机运行为准&#xff0c;当前IDE预览器不支持。 需要权…

Java项目:基于springboot实现的OA协同办公系统(源码+数据库+毕业论文)

一、项目简介 本项目是一套基于Springbootvue实现的付费自习室系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

从零开始利用MATLAB进行FPGA设计(一):建立脉冲检测模型的Simulink模型2

目录 1.模块的总体结构 1.1从工作空间导入输入信号 1.2FIR滤波器 2.Subsystem 3.MATLAB Function 文章灵感来源于MATLAB官方免费教程&#xff1a;HDL Coder Self-Guided Tutorial 考虑到MATLAB官网的英文看着慢&#xff0c;再加上视频讲解老印浓浓的咖喱味&#xff0c;我…

【CSP】2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度(思想是离散化)

2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度&#xff08;思想是离散化&#xff09;2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度&#xff08;思想是离散化&#xff09; 2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度&am…

python面向对象练习一

假设我们正在开发一个学生管理系统&#xff0c;我们需要创建一个Student类来表示学生对象。 每个学生都有学号、姓名和年龄属性。我们还希望能够打印学生的信息&#xff0c;并在删除学生对象时输出一条提示消息。 要求使用__str__()管理学生信息的打印 要求使用__del__()管理删…