[Python学习日记-70] 元类

news2024/12/28 18:26:00

[Python学习日记-70] 元类

简介

什么是元类

关键字 class 创建类的流程分析

自定义元类控制类的创建

自定义元类控制类的调用

自定义元类的属性查找

自定义元类的应用与练习

简介

        在上一篇章当中我们已经了解了面向对象的各种内置函数了,本篇我们将讲述“元类”,它是 Python 面向对象编程的深层次知识,学会了元类可以做到很多神奇的姿势,这次就带大家一起来探讨一下什么是元类,我们应该如何定制自己的元类,我们应该怎么调用我们自己的元类。

什么是元类

       在介绍什么是元类之前我们先定义一个类作为我们的分析对象,如下

class Chinese:    # Python3 中默认就是新式类,即 Chinese(object)
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

c1 = Chinese('jove',28)
print(type(c1))    # 查看对象c1的类是 ——> <class '__main__.Chinese'>

代码输出如下:

        在前面的许多篇博客当中我们都提过一个特性:Python 中的一切皆为对象;而所有的对象都是实例化而得到的,就像上面的 c1 是调用类 Chinese 实例化后得到的,那对象可以怎么用呢?对象有以下四点特性:

  1. 都可以被引用,即 x = obj
  2. 都可以当作函数的参数传入
  3. 都可以作当函数的返回值
  4. 都可以当作容器类的元素,即 l = [func,time,obj,1,...]

        只要是对象就会拥有上面的四点特性,上面的 c1 很明显是一个对象了,其实我们所创建的类 Chinese 的本质也是一个对象,它也拥有以上四点特性。

        既然所有的对象都是调用类得到的,那么 Chinese 也必然是调用了一个类得到的,我们把这个被 Chinese 调用的类就称为元类,总的来说产生 Chinese 的过程一定发生了:Chinese = 元类(...),即产生类的类就是元类;我们可以通过以下代码查看 Chinese 的元类是什么,如下

print(type(Chinese))

代码输出如下:

        从输出来看 Chinese 的产生是调用了 type 这个元类,即默认的元类为 type,类与对象的产生过程如下图所示

关键字 class 创建类的流程分析

        在分析创建类的流程之前我们要先补充一下 exec 方法的用法,exec 方法在创建类时起到了关键的作用,它是用于执行动态生成的代码,并会生成相应的作用域/名称空间,exec 方法的语法如下

exec(code,globals_dic,locals_dic)

  • code:一系列python代码的字符串
  • globals_dic:全局作用域(字典形式),如果不指定,默认为globals()
  • ocals_dic:局部作用域(字典形式),如果不指定,默认为locals()

        我们可以把 exec 方法的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中,演示代码如下

g = {
    'x':1,
    'y':2
}

l = {}

exec("""
global x,m
x = 10
m = 100
z = 3
""",g,l)

print(g)
print(l)

代码输出如下:

{'x': 10, 'y': 2, ..., 'm': 100}

{'z': 3}

        补充完 exec 方法的使用后我们书接上文,前面我们说到,使用关键字 class 创建的类 Chinese 本身也是一个对象,负责产生该对象的类被我们称之为元类,而在 Python 中内置的元类就是 type。关键字 class 在帮我们创建类的时候必然会帮我们调用元类 type,即 Chinese = type(...),元类 type 进行实例化的时候会依次传入以下三个参数,这三个参数就是类的关键组成部分,分别是

  1. 类名:class_name = 'Chinese'
  2. 基类(父类)们:class_bases = (object,)
  3. 类的名称空间:class_dic,类的名称空间是执行类体代码而得到的

        总的来说,关键字 class 帮我们创建一个类分为以下四个过程:

        到这里我们知道了,其实我们用关键字 class 创建的类也只是一个用元类 type 创建的对象而已,那也就是说其实我们也可以自己用元类 type 来创建类,并不需要使用关键字 class,总的来说在 Python 中定义类有两种方式:

  • 方式一:关键字 class 创建
  • 方式二:由元类 type 创建

        为了验证我们分析的正确性,我们分别使用两种创建类的方式来创建两个类来对比一下,代码如下

# 定义类的两种方式:
# 方式一: class
class Chinese:  # Chinese = type(...)
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)


obj = Chinese('jove',28)
print(obj,obj.name,obj.age)
# print(type(obj.talk))
# print(Chinese.__bases__)


# 方式二: type
# 定义类的三要素
class_name = 'Chinese'  # 类名
class_bases = (object,)  # 基类(父类)
# 类里的代码
class_body = """
country = 'China'

def __init__(self,name,age):
    self.name = name
    self.age = age

def talk(self):
    print('%s is talking' % self.name)
"""

class_dic = {}
exec(class_body,globals(),class_dic)  # 执行类里的代码,并把类里面的属性(非功能性代码)都放到dict --> locals() 里面
# print(class_dic)

Chinese1 = type(class_name,class_bases,class_dic)  # 最后传入所需的要素到type()当中

obj1 = Chinese1('jove',28)
print(obj1,obj1.name,obj1.age)

代码输出如下:

自定义元类控制类的创建

        经过前面一大轮的分析,我们已经清楚了 Python 当中默认的元类是 type,而我们能使用 metaclass 关键字参数为一个类指定元类,在默认的情况下如下

class Chinese(object,metaclass=type):    # 默认metaclass就等于type
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

        而我们可以通过继承 type 来自定义元类,然后使用 metaclass 关键字参数为一个类指定自定义元类即可,如下

class Mymeta(type):    # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    def __init__(self,class_name,class_bases,class_dic):
        print(class_name)
        print(class_bases)
        print(class_dic)
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)    # 重用父类的功能


class Chinese(object,metaclass=Mymeta):  # Chinese = Mymeta(class_name,class_bases,class_dic)
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

代码输出如下:

        从输出可以看出,在创建类 Chinese 的时候同时调用了自定义元类 Mymeta,从这可以看出自定义元类可以控制类的产生过程,而类的产生过程其实就是元类的调用过程,即 Chinese = Mymeta(class_name,class_bases,class_dic),在调用 Mymeta 时会先产生一个空对象 Chinese,然后连同调用 Mymeta 括号内的参数一同传给 Mymeta 下的 __init__ 方法来完成初始化,这样我们可以基于这个调用机制来做一些关于创建类的限制,例如限制类名的书写格式,代码如下

class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        if not class_name.istitle():  # 类名开头必须为大写
            raise TypeError('类名的首字母必须大写')    # 异常处理后面会有专门的篇章介绍
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():  # strip()如果为空则自带布尔值 false
            raise TypeError('类必须写注释,且不能为空')
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)


class Chinese(object,metaclass=Mymeta):    # Chinese = Mymeta(class_name,class_bases,class_dic)
    '''
    中国人的类
    '''
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

cn = Chinese('jove',28)
cn.talk()

代码输出如下:

        当代码没有按照要求类名的首字母大写时

        当代码当中没有注释说明时

        当所有要求都符合时

自定义元类控制类的调用

        在学习自定义元类的调用之前我们需要先掌握 __call__ 方法的使用,这在之前已经介绍过了,可以点击链接查看。了解完 __call__ 方法之后,我们知道调用一个对象,就是触发对象所在类中的 __call__ 方法的执行,如果把 Chinese 也当做一个对象,那么在 Chinese 这个对象的类中也必然存在一个 __call__ 方法,即 Chinese 的元类里面也应该有一个 __call__ 方法,会在 Chinese() 调用时触发,如下

class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        if not class_name.istitle():  # 类名开头必须为大写
            raise TypeError('类名的首字母必须大写')    # 异常处理后面会有专门的篇章介绍
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():  # strip()如果为空则自带布尔值 false
            raise TypeError('类必须写注释,且不能为空')
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)
    
    def __call__(self, *args, **kwargs):  # 如果没有写这个,将会找父类的__call__方法 obj = Chinese('egon', 18)
        print(self)  # self = Chinese
        print(args)  # arge = ('jove',)
        print(kwargs)  # kwarge = {'age': 28}


class Chinese(object,metaclass=Mymeta):    # Chinese = Mymeta(class_name,class_bases,class_dic)
    '''
    中国人的类
    '''
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

cn = Chinese('jove',28)      # Chinese.__call__(Chinese,'jove',28)
print(cn)

代码输出如下:

        从输出结果来看,调用 Chinese 对象的时候就是在调用 Chinese 类中的 __call__ 方法,然后会把 Chinese 传递给 self,而溢出的位置参数和关键字参数分别传递给 *args 和 **kwargs,最后调用 Chinese 的返回值就是调用的 __call__ 方法的返回值,这里的 __call__ 方法没有指定返回值所以打印 cn 时就是 None。

        很明显的看出,我们自定义的 __call__ 还没有实现实例化对象 cn 的功能,那应该怎么做呢?默认地,在调用 cn = Chinese('jove',28) 时 __call__ 应该做以下三件事:

  1. 产生一个空对象 obj
  2. 调用 __init__ 方法初始化对象 obj
  3. 返回初始化好的 obj

        实现代码如下

class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        if not class_name.istitle():  # 类名开头必须为大写
            raise TypeError('类名的首字母必须大写')    # 异常处理后面会有专门的篇章介绍
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():  # strip()如果为空则自带布尔值 false
            raise TypeError('类必须写注释,且不能为空')
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)
    
    def __call__(self, *args, **kwargs):  # 如果没有写这个,将会找父类的__call__方法 obj = Chinese('egon', 18)
        # 第一件事: 调用__new__造出一个空对象obj
        obj = object.__new__(self)    # 此处的self是类Chinese,必须传参,代表创建一个Chinese的对象obj

        # 第二件事: 调用__init__方法初始化空对象obj
        self.__init__(obj, *args, **kwargs)

        # 第三件事: 返回初始化好的 obj
        return obj


class Chinese(object,metaclass=Mymeta):    # Chinese = Mymeta(class_name,class_bases,class_dic)
    '''
    中国人的类
    '''
    country = 'China'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

cn = Chinese('jove',28)      # Chinese.__call__(Chinese,'jove',28)
print(cn)

代码输出如下:

         从输出结果来看已经看到 cn 已经变成了类 Chinese 的一个对象了,这个时候已经完成了实例化,而上面代码当中的 __call__ 其实只相当于一个模版而已,我们还能在此基础上改写 __call__ 的逻辑从而控制调用 Chinese 的过程,例如把 Chinese 实例化的对象的所有属性都变成私有属性,如下

class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dic):
        if not class_name.istitle():  # 类名开头必须为大写
            raise TypeError('类名的首字母必须大写')  # 异常处理后面会有专门的篇章介绍
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():  # strip()如果为空则自带布尔值 false
            raise TypeError('类必须写注释,且不能为空')
        super(Mymeta, self).__init__(class_name, class_bases, class_dic)

    def __call__(self, *args, **kwargs):  # 如果没有写这个,将会找父类的__call__方法 obj = Chinese('egon', 18)
        # 第一件事: 调用__new__造出一个空对象obj
        obj = object.__new__(self)  # 此处的self是类Chinese,必须传参,代表创建一个Chinese的对象obj

        # 第二件事: 调用__init__方法初始化空对象obj
        self.__init__(obj, *args, **kwargs)

        # 在初始化之后,obj.__dict__里就有值了
        print(obj.__dict__)
        obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in obj.__dict__.items()}

        # 第三件事: 返回初始化好的 obj
        return obj


class Chinese(object, metaclass=Mymeta):  # Chinese = Mymeta(class_name,class_bases,class_dic)
    '''
    中国人的类
    '''
    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)


cn = Chinese('jove', 28)  # Chinese.__call__(Chinese,'jove',28)
print(cn.__dict__)

代码输出如下:

自定义元类的属性查找

        到这里基本就介绍完元类了,在学习完元类之后再来看看结合了继承和元类之后的属性查找应该是怎么样的一个查找顺序呢?我们先来写一段代码,如下

class Mymeta(type):
    n=444

    def __call__(self, *args, **kwargs):
        obj=self.__new__(self)
        self.__init__(obj,*args,**kwargs)
        return obj

class Bar(object):
    n=333

class Foo(Bar):
    n=222

class Chinese(Foo,metaclass=Mymeta):
    n=111

    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)


print(Chinese.n)    # 自下而上依次注释各个类中的n=xxx,然后重新运行程序,发现n的查找顺序为Chinese -> Foo -> Bar -> object -> Mymeta -> type

代码输出如下:

        注释掉 Chinese 下的 n=111 后

·        注释掉 Foo 下的 n=222 后

        注释掉 Bar 下的 n=333 后

        最后注释掉 Mymeta 下的 n=444 后直接报错找不到了

        在前面我们学习过继承的实现原理,如果把类当成对象去看,上面代码的继承关系是:对象 Chinese 继承对象 Foo,对象 Foo 继承对象 Bar,对象 Bar 继承对象 object。我们应该把属性的查找分成两层,一层是对象层的查找,即基于 c3 算法的 MRO 方法调用顺序;另一层则是类层的查找,即对元类层的查找,查找顺序如下

当对对象中的属性进行查找时会按以下顺序进行查找:

  1. 对象层:Chinese -> Foo -> Bar -> object
  2. 元类层:Mymeta -> type

        通过上面的分析,我们现在知道在属性查找的时候元类也会参与其中,我们在之前使用 __call__ 方法实现实例化的时候用到了 self.__new__,下面我们来分析一下这个 __new__ 到底是调用了哪里的,我们先写下一段代码运行看看,如下

class Mymeta(type):
    n=444

    def __call__(self, *args, **kwargs):
        obj=self.__new__(self)
        print(self.__new__ is object.__new__)   # 当前面的__new__都注释掉之后这个就是True了

class Bar(object):
    n=333
    # def __new__(cls, *args, **kwargs):
    #     print('Bar.__new__')

class Foo(Bar):
    n=222
    # def __new__(cls, *args, **kwargs):
    #     print('Foo.__new__')

class Chinese(Foo,metaclass=Mymeta):
    n=111

    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)

    # def __new__(cls, *args, **kwargs):
    #     print('Chinese.__new__')


Chinese('jove',28)

代码输出如下:

        上面代码中注释的 __new__ 方法可以自己运行一下,这样可以更加清楚的看到 self.__new__ 的查找情况 。一番操作后发现 Mymeta 下的 __call__ 里的 self.__new__ 的查找顺序是 Chinese -> Foo -> Bar -> object,而且经过 self.__new__ 和 object.__new__ 的比对之后发现这两个是一样的,那就是说 self.__new__ 的查找并没有找到元类当中,而是会去找 object 里的 __new__,而 object 下默认就有一个 __new__,所以即便是之前的类均未实现 __new__,也一定会在 object 中找到一个,根本不会再去找元类 Mymeta 和 type 中查找 __new__。

        那我们是否可以在元类的 __call__ 中用 object.__new__(self) 代替 self.__new__(self) 去造对象呢?原则上是可以的,因为通过属性查找最终还是会找到 object.__new__,但是并不推荐这样做,因为直接使用 object.__new__ 会直接跳过之前的 Chinese、Foo 和 Bar 三个类的检索,如果后期在他们当中想做 __new__ 的自定义的话会造成一定的麻烦。

        那什么情况下才会去元类层查找 __new__ 呢?在产生类 Chinese 的过程就是在调用 Mymeta,而 Mymeta 也是 type 类的一个对象,那么 Mymeta 之所以可以调用,一定是在元类 type 中也有一个 __call__ 方法,而这个 __call__ 方法也同样需要做至少三件事,如下

class type:
    def __call__(self, *args, **kwargs):    # self=<class '__main__.Mymeta'>
        obj=self.__new__(self,*args,**kwargs)    # 产生Mymeta的一个对象
        self.__init__(obj,*args,**kwargs) 
        return obj

        这个时候 type 中的 self.__new__ 进行检索的时候就会先对 Mymeta 进行检索,然后再对 type 进行检索,所以我们可以通过这个逻辑来定制我们的自定义元类 Mymeta,如下

class Mymeta(type):
    n=444

    def __new__(cls, *args, **kwargs):
        obj=type.__new__(cls,*args,**kwargs) # 必须按照这种传值方式
        print(obj.__dict__)
        return obj  # 只有在返回值是type的对象时,才会触发下面的__init__
        # return 123

    def __init__(self,class_name,class_bases,class_dic):
        print('run。。。')


class Chinese(Foo,metaclass=Mymeta):
    n=111

    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print('%s is talking' % self.name)


print(type(Mymeta))

代码输出如下:

        当返回 type 的对象时

        当返回的不是 type 的对象时

自定义元类的应用与练习

一、单例模式

        在详细介绍完元类之后我们再来讲讲元类的一些实际应用——单例模式。什么是单例模式呢?在 Python 当中我们定义两个不同的变量,但是值是一样的,如下

obj1 = int(1)    # obj1 = 1
obj2 = int(1)    # obj2 = 1
print(obj1 is obj2)

代码输出如下:

        obj1 和 obj2 两个对象是指向相同的内存地址的,而单例模式要做的事就是把相同特征的对象只产生一个内存地址,从而节约内存空间,下面我们会用两种方式来实现单例模式,如下

配置文件 setting.py:

HOST = '127.0.0.1'
PORT = 1000

实现方式一:不使用元类

import settings

class MySQL:
    __instance = None

    def __init__(self,host,port):
        self.host = host
        self.port = port

    @classmethod
    def singleton(cls):
        if not cls.__instance:  # 这样的赋值方法只适用于self的特征写死的情况下
            obj = cls(settings.HOST,settings.PORT)
            cls.__instance = obj
        return cls.__instance

    def conn(self):
        pass

    def execute(self):
        pass

# 对象的特征(属性)不同,内存地址不同
obj1 = MySQL('1.1.1.2',3306)
obj2 = MySQL('1.1.1.3',3307)
print(obj1 is obj2)

# 对象的特征(属性)相同,内存地址相同
obj1 = MySQL.singleton()
obj2 = MySQL.singleton()
print(obj1 is obj2)

代码输出如下:

实现方式二:使用元类来实现

import settings

class Mymeta(type):
    def __init__(self,name,bases,dic): #定义类Mysql时就触发

        # 事先先从配置文件中取配置来造一个Mysql的实例出来
        self.__instance = object.__new__(self)  # 产生对象
        self.__init__(self.__instance, settings.HOST, settings.PORT)  # 初始化对象
        # 上述两步可以合成下面一步
        # self.__instance=super().__call__(*args,**kwargs)


        super().__init__(name,bases,dic)

    def __call__(self, *args, **kwargs): #Mysql(...)时触发
        if args or kwargs: # args或kwargs内有值
            obj=object.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj

        return self.__instance




class Mysql(metaclass=Mymeta):
    def __init__(self,host,port):
        self.host=host
        self.port=port



obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,所有的实例应该指向一个内存地址
obj2=Mysql()
obj3=Mysql()

print(obj1 is obj2 is obj3)

obj4=Mysql('1.1.1.4',3307)
print(obj4 is obj1)

代码输出如下:

二、在元类中控制把自定义类的数据属性都变成大写

class Mymeta(type):
    def __new__(cls, class_name, class_base, class_dict):
        update_class_dict = {}
        ''.endswith('__')
        for k in class_dict:
            if not callable(class_dict[k]) and not k.startswith('__') and not k.startswith('_'):
                update_class_dict[k.upper()] = class_dict[k]
            else:
                update_class_dict[k] = class_dict[k]
        return type.__new__(cls, class_name, class_base, update_class_dict)


class Chinese(metaclass=Mymeta):
    country = 'China'
    tag = 'Legend of the Dragon'  # 龙的传人
    __ismarry = 'yes'

    def __init__(self):
        self.name = 'Zou'

    def walk(self):
        print('%s is walking' % self.name)


print(Chinese.__dict__)

代码输出如下:

{'__module__': '__main__', 'COUNTRY': 'China', 'TAG': 'Legend of the Dragon', '_Chinese__ismarry': 'yes', '__init__': <function Chinese.__init__ at 0x000001A082A48B80>, 'walk': <function Chinese.walk at 0x000001A082A499E0>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}

三、在元类中控制自定义的类无需 __init__ 方法

  1. 元类帮其完成创建对象,以及初始化操作
  2. 要求实例化时传参必须为关键字形式,否则抛出异常 TypeError: must use keyword argument
  3. key 作为用户自定义类产生对象的属性,且所有属性变成大写
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError('must use keyword argument for key function')
        obj = object.__new__(self)
        for k in kwargs:
            obj.__dict__[k.upper()] = kwargs[k]
        return obj


class Chinese(metaclass=Mymeta):
    country = 'China'
    tag = 'Legend of the Dragon'  # 龙的传人
    __ismarry = 'yes'

    def walk(self):
        print('%s is walking' % self.name)


obj1 = Chinese(name = 'jove',age = 28)
print(obj1.__dict__)

代码输出如下:

四、在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        # 控制Chinese对象的创建过程
        if args:
            raise TypeError('must use keyword argument for key function')
        obj = object.__new__(self)
        for k in kwargs:
            obj.__dict__['_%s__%s' % (self.__name__, k)] = kwargs[k]
        return obj


class Chinese(metaclass=Mymeta):
    country = 'China'
    tag = 'Legend of the Dragon'  # 龙的传人
    __ismarry = 'yes'

    def walk(self):
        print('%s is walking' % self.name)


p = Chinese(name = 'jove',age = 28)
print(p.__dict__)

代码输出如下:

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

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

相关文章

【前端】浏览器输入url到页面呈现发生了什么?

前言 在此总结记录下浏览器输入url到页面呈现期间的流程。 浏览器输入url发生了什么&#xff1f; 从浏览器地址栏上输入url到页面渲染主要分为以下流程&#xff1a; 解析请求url&#xff0c;建立连接发送请求浏览器渲染页面 在输入url地址后&#xff0c;浏览器识别输入的是…

深入云电脑PC Farm技术探讨,以阿里云、华为云、ToDesk为例

&#x1f31d;引言 近年来&#xff0c;云计算技术的飞速发展为各行各业的数字化转型带来了全新机遇&#xff0c;其中云电脑作为一种虚拟化桌面解决方案&#xff0c;逐渐成为个人用户与企业的核心选择。从远程办公、在线教育到高性能计算需求&#xff0c;云电脑通过为用户提供随…

Windows中MySQL8.3.4 MSI版本——详细安装教程

一、下载MySQL安装文件。 下载地址&#xff1a;MySQL官网 进入后点击下面的MySQL社区版下载 点击MySQL Comunity Server。 我这里选择的是版本8.4.3LTS版本&#xff0c;在线对应的msi文件。 点击No thanks,直接下载。 二、安装MySQL 2.1、双击刚刚下载好的msi文件&#xff0c;…

Appium:安装uiautomator2失败

目录 1、通过nmp安装uiautomator2&#xff1a;失败 2、通过 Appium 的平台直接安装驱动程序 3、通过pip 来安装 uiautomator2 1、通过nmp安装uiautomator2&#xff1a;失败 我先是通过npm安装的uiautomator2&#xff0c;也显示已经安装成功了&#xff1a; npm install -g …

计算机网络-IPSec VPN基本概念

企业分支之间经常有互联的需求&#xff0c;企业互联的方式很多&#xff0c;可以使用专线线路或者Internet线路。部分企业从成本和需求出发会选择使用Internet线路进行互联&#xff0c;但是使用Internet线路存在安全风险&#xff0c;如何保障数据在传输时不会被窃取&#xff1f;…

【Linux】环境ChatGLM-4-9B 模型之 openai API 服务

一、摘要 最近看到 Function Call 比较感兴趣,它的核心是赋予大模型能够调用外部API的能力,能够解决大模型功能扩展性问题,允许模型调用外部数据库或API,提供特定领域的详细信息;解决信息实时性问题,模型可以实时获取最新数据;解决数据局限性问题,大模型训练数据虽多但…

实践教程|Transformer Decoder-Only 模型批量生成 Trick

导读 本文给出了一个用单Transformer decoder&#xff08; GPT&#xff09;模型进行批量生成时的解决方法。 发现用单 Transformer decoder &#xff08;Aka GPT&#xff09;模型进行生成时&#xff0c;因为位置对齐等问题&#xff0c;进行批量生成时十分麻烦。 训练时&#…

【NoSQL数据库】MongoDB数据库——文档的查询操作(多条件查询、聚合aggregate、管道)

往期文章&#xff1a; ​​​​​​【NoSQL数据库】MongoDB数据库的安装与卸载-CSDN博客 【NoSQL数据库】MongoDB数据库——集合和文档的基本操作&#xff08;创建、删除、更新、查询&#xff09;-CSDN博客 目录 一、MongoDB文档查询原理 1、使用 find() 方法进行文档基本…

git pull error: cannot lock ref

Git: cannot lock ref ‘refs/remotes/origin/feature/xxx’: refs/remotes/origin/feature/xxx/car’ exists; cannot create refs/remotes/origin/feature/xxx git remote prune origin重新整理服务端和本地的关联关系即可

Harnessing Large Language Models for Training-free Video Anomaly Detection

标题&#xff1a;利用大型语言模型实现无训练的视频异常检测 原文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2024/papers/Zanella_Harnessing_Large_Language_Models_for_Training-free_Video_Anomaly_Detection_CVPR_2024_paper.pdf 源码链接&#xff1a;ht…

Flutter解压文件并解析数据

Flutter解压文件并解析数据 前言 在 Flutter 开发中&#xff0c;我们经常需要处理文件的读取和解压。 这在处理应用数据更新、安装包、存档文件等场景中尤为常见。 本文将介绍如何在Flutter中使用archive插件来解压文件并解析数据。 准备 在开始之前&#xff0c;我们需要…

论文阅读:Single-cell transcriptomics of 20 mouse organs creates a Tabula Muris

The Tabula Muris Consortium., Overall coordination., Logistical coordination. et al. Single-cell transcriptomics of 20 mouse organs creates a Tabula Muris. Nature 562, 367–372 (2018). 论文地址&#xff1a;https://doi.org/10.1038/s41586-018-0590-4 代码地址…

【算法】模拟

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;替换所有的问号 二&#xff1a;提莫攻击 三&#xff1a;z字形变换 四&#xff1a;外观…

MongoDB整合SpringBoot

MongoDB整合SpringBoot 环境准备 1.引入依赖 <!--spring data mongodb--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> 2.配置yml spr…

【简洁明快】使用python读取数据建立pptx (python-pptx图文调整案例)

使用python自动读取数据建立pptx 前言如何使用 Python 自动生成 PPTX第一步&#xff1a;安装所需库第二步&#xff1a;创建一个新的 PPTX第三步&#xff1a;添加幻灯片第四步&#xff1a;添加内容添加文本添加图片第五步&#xff1a;保存 PPTX 图文实操案例&#xff08;自动读取…

三维扫描检测在汽车制造中的应用

三维扫描&#xff0c;通过先进三维扫描技术获取产品和物体的形面三维数据&#xff0c;建立实物的三维图档&#xff0c;满足各种实物3D模型数据获取、三维数字化展示、3D多媒体开发、三维数字化存档、逆向设计、产品开发、直接3D打印制造或辅助加工制造等一系列的应用。 三维扫描…

flyway执行sql遇到变量执行报错解决

前两天在公司使用flyway工具执行sql时&#xff0c;开发写的sql里面有变量&#xff0c;于是这个flyway工具不识别这个变量直接报错&#xff0c;不接着往下执行了。报错信息如下&#xff1a; flyway工具执行sql报错 information: No value provided for placeholder: ${ep1} 于是…

go语言的sdk项目搭建与git 操作标签tag并推送至远程仓库

在搭建 SDK 项目并结合 Git 操作标签&#xff08;Tag&#xff09;时&#xff0c;通常会涉及项目初始化、版本管理、Git 标签的创建与管理等内容。以下是一个完整的步骤指南&#xff0c;帮助您搭建 SDK 项目并学习如何使用 Git 标签。 ### 1. **搭建 SDK 项目** 首先&#xff…

机器学习算法的核心理论小总结

机器学习算法的核心在于利用数据构建模型以解决实际问题&#xff0c;而理解其理论基础是高效应用的关键。本文从机器学习的基本概念出发&#xff0c;详细解析监督学习中的几种经典算法&#xff0c;如逻辑回归、决策树和支持向量机&#xff08;SVM&#xff09;。同时&#xff0c…

3.STM32通信接口之SPI通信---SPI实战(W25Q64存储模块介绍)《精讲》

上一节介绍了SPI的通信过程和方法&#xff0c;接下来就要进行STM32与外围模块通信了&#xff0c;这个模块是一块非易失型存储芯片&#xff0c;能够提供8MB的存储空间。接下来跟着Whappy脚步&#xff0c;进行探索新大陆吧&#xff01;【免费】W25Q64(中英文数据手册)资源-CSDN文…