python type 与 metaclass理解

简介

众所周知,type在一般情况下,我们都会去获取一个对象的类型,然后进行类型的比较;除此之外,type还有一个不为人知的作用:动态的创建类。在了解这个之前,首先了解以下type和isinstance之间的关系或者说是区别,这两个方法都可以判断类型,但又有所区别

type与isinstance

class Person:
    def __init__(self) -> None:
        pass

    def sleep(self):
        print("sleep")


class Male(Person):
    def __init__(self) -> None:
        pass

    def sleep(self):
        print("sleep")


print(type(Person))
print(type(Male))
print(isinstance(Person, type))
print(isinstance(Male, type))
p = Person()
m = Male()
print(type(p))
print(type(m))
print(type(p) == type(m))
print(isinstance(p, Person))
print(isinstance(m, Male))
print(isinstance(m, Person))

<class 'type'>
<class 'type'>
True
True
<class '__main__.Person'>
<class '__main__.Male'>
False
True
True
True

由结果<class 'type'>可以看出,所有的类默认是继承自type类,也就是说type默认是所有类的元类;由isinstancetype之间的对比来看,isinstance会考虑到继承关系,但是type不会考虑到继承关系,通俗点讲就是,对于子类与父类的对象类型比较时,isinstance会认为是相同的,但是type会认为不是相同的。
因此建议在比较对象类型时最好使用isinstance方法。

如何动态创建一个类?

由上述可知,type默认是所有类的元类,因此我们可以使用type创建一个简单的类:

type(__name: str, __bases: tuple[type, ...], __dict: dict[str, Any])
  • __name:类的名称
  • __bases:继承的类,以元组形式,注意单个元素时需要在后面添加逗号
  • __dict:类中的属性或者方法
    详细代码如下:
def run(self):
    print("run"


class_name = "Test"
base_name = object
name = "tom"
Person2 = type(
    class_name,
    (base_name,),
    {"run": run, "name": name},
)

print(type(Person2))
p = Person2()
print(type(p))
p.run()

<class 'type'>
<class '__main__.Test'>
run

metaclass作用

当我们需要对一种类型的类批量添加某些属性或者方法时,使用metaclass创建元类的派生类,从而添加属性或者方法

class FirstMetaClass(type):
    # cls代表动态修改的类
    # name代表动态修改的类名
    # bases代表被动态修改的类的所有父类
    # attr代表被动态修改的类的所有属性、方法组成的字典
    def __new__(cls, name, bases, attrs):
        # 动态为该类添加一个name属性
        attrs['name'] = "C语言中文网"
        attrs['say'] = lambda self: print("调用 say() 实例方法")
        return super().__new__(cls, name, bases, attrs)


class Test(metaclass=FirstMetaClass):
    def __init__(self) -> None:
        pass

    def __call__(self, *args, **kwds):
        pass


t = Test()
print(t.name)
t.say()

C语言中文网
调用 say() 实例方法

由上述看出,当指定了元类后,添加的属性可以直接调用,类似于子类可以直接调用父类的方法一样,其实元类就相当于时每个类的父类,因此修改元类属性或者方法,可以影响到子类,父类与子类的关系和元类与普通类的关系是类似的。
image

重点

1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法

type、类、对象的关系

type的关系就像是对象的关系。
image

posted @   形同陌路love  阅读(135)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示