DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • Django

  • 第一次学drf

  • 第二次学drf

    • drfCBV
    • 认证
    • 权限
    • 限流
    • 版本
    • 解析器
    • 元类
      • 类定义阶段
      • 类的实例化
        • 基本使用
        • 重要结论
      • type和object
        • 专业术语
        • 内置方法
        • 验证关系
      • __call__
        • 基本使用
        • 深入探究
      • 元类
        • 创建类
        • 参数和返回值
        • 继承情况
        • 扩展
      • 示例(源码)
    • 序列化使用
    • 序列化源码
    • 验证&源码
    • 序列化+验证
    • Serializer案例
    • Serializer总结
    • 分页
    • 视图+路由+过滤
    • 练习+跨域问题
    • 博客练习
    • 源码分析汇总
  • 温故知新

  • flask

  • 后端
  • 第二次学drf
DC
2023-10-31
目录

元类

阅读此篇博文的顺序: 类定义阶段 - 类的实例化 - 元类 - 示例(源码) , 剩下的作为补充. 这样可以更顺畅的理解元类.
因为 type和object 、__call__ 这两部分的内容自己当时总结的有些许生涩难懂..复习时也想了好一会.. 不是特别重要,了解即可!”


别较真! 深究就涉及C语言结构体了. 在此阶段, 我们只需要明白:
object是所有类的基类, 其他所有的类都是由type创建的. 想要自定义创建, 得基于metaclass指定一个类, 该类继承type!!

元类是做什么的? 它是用来控制我们类的生成过程的, 默认情况下, 我们自定义的类都是由type创建的.


# 类定义阶段

定义类 类似于 `import 模块名`
导入模块会创建一个namescope. 通过 模块名.属性名 从namescope中取属性/变量.
同理! 从上往下运行到class定义的类代码,会立刻开辟一个类的namescope,将类中的变量和方法/函数往namescope中丢.
★ (类中的代码/类体代码 在定义阶段就执行啦!!)
★ 记住: "执行 py文件、执行导入模块、类定义、类的实例化/类的调用、函数调用 的代码时,会开辟namescope."
       特别注意,类中函数体的代码要在函数被调用时才会执行!
        ---------
       | 数据属性 |
类名 -->|        |
       | 函数属性 |
        ---------  类名指向类的namescope
查看类的namescope: 类名.__dict__
类名.属性名 等同于 类名.__dict__["属性名"]
★ So,对namescope的CURD的本质就是在操作字典!! 
★ (类的实例是一样的! 查看实例的namescope: 实例名.__dict__)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 类的实例化

类在实例化的时候会自动调用__init__, 但其实在调用__init__之前会先自动调用__new__!

# 基本使用

__new__: 为类实例化对象申请'开辟'一片内存 / 创建实例对象的;
__init__: 为类实例化对象设置独有的属性 / 为实例对象绑定属性;

class A:

  	# ★!!注意:该方法就是一个普通方法 print(A.__new__) --> <function A.__new__ at 0x7f9b6ba068b0>
    #        只不过会类实例化时会自动调用,并将当前类作为cls的实参传入.
    def __new__(cls, *args, **kwargs): 
        print("__new__")
        # !!!这里的参数cls就表示A这个类本身!!! ★ 若class B(A):pass,那么B()时,此处的cls就是<class '__main__.B'>
        print(cls)  # <class '__main__.A'>
        # object.__new__(cls) 便是根据cls创建cls的实例对象
        return object.__new__(cls)

    # 然后执行__init__, 里面的self指的就是实例对象
    # 在执行__init__的时候, __new__的返回值会自动作为参数传递给这里的self
    def __init__(self, *args, **kwargs):
        print("__init__")


A()  
"""
__new__
<class '__main__.A'>
__init__
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 重要结论

★ 几个比较重要的结论!
1> **__new__ 中必须将类A的实例对象返回, 才会执行__init__, 并且执行的时候会自动将__new__ 的返回值作为参数传给self. **
2> 一个对象是什么, 取决于其类型对象的__new__返回了什么.
3> __new__ 里面的参数一定要和__init__是匹配的, 除了第一个参数之外.

参考文档: https://www.cnblogs.com/traditional/p/13593927.html 很佩服这位老哥,写得很棒!!
下面将用三段代码验证上述的三个结论!!

结论1的验证

class A:

    def __new__(cls, *args, **kwargs):
        print("__new__")

    def __init__(self):
        print("__init__")


A()  # __new__ 
# -- 我们看到只有__new__被调用了,__init__则没有!  【结论1的验证】
1
2
3
4
5
6
7
8
9
10
11

结论1和结论2的验证

class A:

    def __new__(cls, *args, **kwargs):
        print("__new__")
        # -- 这里必须返回A的实例对象, 否则__init__函数是不会执行的  【结论1的验证】
        return 123

    def __init__(self):
        print("__init__")


a = A()
print(a + 1)  
"""
__new__
124
"""
# -- 我们看到A在实例化之后得到的是一个整型, 原因就是__new__返回了123  【结论2的验证】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

结论3的验证.
object.__new__(cls)、__new__接收的name、__new__接收的age 会组合起来, 分别传给__init__的 self、name、age!!!

class A:

  	# __new__里面的参数一定要和__init__是匹配的, 除了第一个参数之外  【结论3的验证】
    def __new__(cls, name, age):
        return object.__new__(cls)

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

# A("夏色祭", -1) 这里传入了两个参数, 那么: A、"夏色祭"、-1 就会组合起来, 分别传给__new__的 cls、name、age
# 然后__new__里面返回了一个实例对象
# ★★ 那么:
#    object.__new__(cls)创建的实例、__new__接收的name、__new__接收的age 会组合起来, 分别传给__init__的 self、name、age
a = A("夏色祭", -1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# type和object

object是父子关系的顶端, 所有的数据类型的mro继承链的 继承关系 最后都是object; (type也会继承object)
type是类型 实例关系 的顶端. (object也是type的一个实例)

object提供基础的功能, type用于创建“类”. “type”由谁创建的呢? 别纠结了, 再深究就是C语言的结构体啦!!在python语法层面是解释不了的.

# 专业术语

首先我们这里把python中的对象分为三种:
1> 内建对象: Python中的内建对象、或者叫内置对象, 比如int、str、list、type、object等等;
2> class对象: 程序员通过Python中的class关键字定义的类. 当然我们往往也会把内建对象和class对象统称为类对象;
3> 实例对象: 由类对象(内建对象或者class对象)创建的实例.

而对象之间存在着以下两种关系:
1> is-kind-of: 对应面向对象理论中父类和子类之间的关系; -- 继承关系.
2> is-instance-of: 对应面向对象理论中类和实例之间的关系; -- 实例关系.

# 内置方法

继承关系
__bases__ : 查看一个 类型/类 的所有父类;
__base__ : 查看一个 类型/类 的继承的第一个类;
issubclass(sub, super) 检查sub类是否是 super类的 子类, 是, 返回True.
注意: 在python3中统一了类与类型的概念, 类就是类型.. (详见: python面向对象/0_OOP基本/类就是类型 部分的笔记)

实例关系
__class__ : 查看一个实例的类型;
type : 也可以查看一个实例的类型; (即该实例是由谁实例化得到的)
isinstance(obj,cls) : 返回True或False. 若想返回True,满足下面两个条件其中一个即可.
1> 检查obj是否是 类cls或类cls的子类 的一个实例, 是, 返回True;
2> type(obj)的类型 是否跟 cls 一致, 是, 返回True.
这里的obj可以是类对象、实例对象.

class A(object):
    pass


class B(A):
    pass


if __name__ == '__main__':
    print(type(B))  # <class 'type'>
    print(B.mro())  # [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
    
    print(B.__base__)   # <class '__main__.A'>
    print(B.__bases__)  # (<class '__main__.A'>,)
    print(issubclass(B, object))  # True
    print(issubclass(B, type))    # False
    
    # 细品!!
    # isinstance(obj,cls) 检查obj是否是 <类cls或类cls的子类> 的一个实例, 是, 返回True;
    # 这里的obj可以是类对象、实例对象.
    # - obj是实例对象
    b = B()
    print(isinstance(b, B))       # True
    print(isinstance(b, A))       # True
    print(isinstance(b, object))  # True
    print(isinstance(b, type))    # False
    # - obj是类对象
    print(isinstance(B, type))    # True -- 类默认都是type实例化得到的
    print(isinstance(B, object))  # True -- 因为type的父类是object
    print(isinstance(B, A))       # False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 验证关系

type实例关系的老大, object继承关系的老大!!

img

实线表示继承关系 该类父类是谁/该类是谁的子类; 虚线表示实例关系 该对象是通过谁实例化得到的/该对象是什么类型..
(类就是类型, python处处皆对象 So, 图中的<type 'list'> 既表示它是list类型,也表示它是list类.. 当然它也是一个对象! )

虚线是跨列产生关系, 而实线只能在一列内产生关系. 除了type和object两者外.

验证上图中所画的关系:

>>> object
<class 'object'>
>>> type
<class 'type'>
>>> object.__bases__  # object 无父类,因为它是链条顶端
()
>>> type.__bases__    # type是object的子类
(<class 'object'>,)
>>> type(object)      # object的类型是type
<class 'type'>
>>> type(type)        # type的类型是自己
<class 'type'>


# -- list, dict, tuple 这些内置数据类型,他们的父类都是object, 类型都是type/都是由type实例化得到的.
>>> list.__bases__
(<class 'object'>,)
>>> list.__class__
<class 'type'>


# -- list实例化得到了mylist对象,该对象类型是<type 'list'>, 但该对象没有父类
>>> mylist = [1,2,3]
>>> mylist.__bases__
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    mylist.__bases__
AttributeError: 'list' object has no attribute '__bases__'
>>> mylist.__class__
<class 'list'>


# -- 自定义的类
>>> c = C()
>>> C.__bases__
(<class 'object'>,)
>>> C.__class__
<class 'type'>
>>> c.__bases__
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    c.__bases__
AttributeError: 'C' object has no attribute '__bases__'
>>> c.__class__
<class '__main__.C'>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# __call__

一个对象能否被调用, 取决于它的类型对象中是否定义了__call__ 函数

# 基本使用

若想让类实例化对象可以被调用, 则需要在类中定义 __call__ 方法!

class Foo:

    def __call__(self, *args, **kwargs):
        print(self)    # <__main__.Foo object at 0x7f99cc986760>
        print(args)    # (1, 2, 3)
        print(kwargs)  # {'x': 4, 'y': 5}
        return "Hello"


print(Foo)  # <class '__main__.Foo'>
      
obj = Foo()
print(obj)  # <__main__.Foo object at 0x7f99cc986760>
# -- 要想让obj这个类实例化对象变成一个可调用的对象,需要在该对象的类中定义一个__call__方法
#    该实例方法会在调用实例化对象obj时自动触发,调用obj的返回值就是__call__方法的返回值
print(obj(1, 2, 3, x=4, y=5))  # Hello  --  obj的调用会触发Foo中__call__方法的执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 深入探究

>>> a = 1
>>> a()
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    a()
TypeError: 'int' object is not callable
  
>>> print(hasattr(int, "__call__"))
True
1
2
3
4
5
6
7
8
9

上述代码运行结果报错, 整数对象是不可调用的,这显然意味着int这个类里面没有__call__函数.
但我们通过反射打印 print(hasattr(int, "__call__")) 的结果为True.. 这是为何?
因为hasattr反射和类属性查找的规则是一样的.
So, int的类型是type, 而type里面有__call__, 因此即便int里面没有,hasattr(int, "__call__")依旧是True

内心OS: 以往我们的记忆都是, hasattr、类属性、实例属性的查找都是基于继承链的, 大体没错, 这里做一点补充!!

class A:
    foo = "in A"


class B(A):
    temp = "in B"


if __name__ == '__main__':
    # ▲ 类属性查找顺序/查找类是否具有某个属性:
    #   类-父类-...-顶级父类object- 若继承链中没有,还会自动到对应的类型对象(即谁实例化出的该类,此处是type)里面去找
    print(hasattr(B, "temp"))
    print(hasattr(B, "foo"))

    print(hasattr(B, "__call__"))
    print(hasattr(type, "__call__"))

    # ▲ 实例属性查找顺序: 
    #   自身-类-父类-...-顶级父类object - 若继承链中没有,就真没有了.
    # ps: object内部没有__call__函数
    print(hasattr(B(), "temp"))
    print(hasattr(B(), "foo"))
    print(hasattr(B(), "__call__"))  # ★★★ 继承链中没有,就不会去元类中找啦!!
    
"""
True
True
True
True
True
True
False
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

一丢丢题外话.

所有的类都是可以调用的,因为type是它们的类型对象,而type内部是有__call__函数的.

但是默认情况下实例对象是不可调用的. 
实例对象加括号执行时,会去找__call__方法!
如果实例对象的类型对象、以及该类型对象所继承的类中没有定义__call__函数的话,会继续沿着继承链挨个进行搜索
直到搜索到object时发现还没有__call__函数的话,那么就报错了.
所以一个整数对象是不可调用的,而整数类型是可调用的,我们发现这并不是在编译的时候就能够检测出来的错误,而是在运行时才能检测出来!
1
2
3
4
5
6
7

# 元类

我们一步步由浅到深的分析.. 只分析drf序列器源码中所需要用到的知识点.

# 创建类

- type可以创建类.默认.
   class type:
       def __new__():
           创建类/开辟一个类的空间
       def __init__():
           给创建的类进行初始化/往类空间放一些东西
   # ★ 类加括号实例化,会先调用类中的new,再调用init
   Foo = type("Foo", (object,), {'v1': 123, 'func': lambda self: 999})
- 自定义类来创建类,但该自定义类需继承type类.因为得将type类的所有功能拿过来,在它基础上进行扩展定制.
   class MyType(type):
       # 重写了type类中的__new__方法.会优先调用这里的new,有很多扩展空间,此处该方法最后用了super.
       def __new__():
           super().__new__()
1
2
3
4
5
6
7
8
9
10
11
12
13

创建类: 方式一 通过class关键字 "本质上就是通过type创建的"

class Foo(object):
    v1 = 123

    def func(self):
        return 999
1
2
3
4
5

创建类: 方式二 通过type类  等同于 方式一

# type要么接收一个参数,要么接收三个参数.接收一个参数查看类型,接受三个参数创建一个类.
# 类名 = type("类名",(父类,),{成员})
Foo = type("Foo", (object,), {'v1': 123, 'func': lambda self: 999})
print(Foo)            # <class '__main__.Foo'>
print(Foo.__name__)   # Foo
print(Foo.__bases__)  # (<class 'object'>,)
print(Foo.v1)         # 123
1
2
3
4
5
6
7

基于自定义类MyType创建类: 方式一

class MyType(type):
    def __new__(mcs, *args, **kwargs):
        xx = super().__new__(mcs, *args, **kwargs)
        return xx  # <class '__main__.Foo'>  -- xx是创建的类
      
Foo = MyType("Foo", (object,), {'v1': 123, 'func': lambda self: 999})
1
2
3
4
5
6

基于自定义类MyType创建类: 方式二

class MyType(type):
    def __new__(mcs, *args, **kwargs):
        """
        mcs     <class '__main__.MyType'>
        args    ('Foo', (<class 'object'>,), {'v1': 123, 'func': <function <lambda> at 0x7fdcd35bb310>})
        kwargs  {}
        """
        xx = super().__new__(mcs, *args, **kwargs)
        return xx


class Foo(object, metaclass=MyType):
    v1 = 123

    def func(self):
        return 999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 参数和返回值

元类和类之间的关系 和 类与实例对象的关系, 之间是很相似的, 完全可以把类对象看成是元类的实例对象.
Foo既然指定了metaclass为MyType, 表示Foo这个类由MyType创建, 那么MyType的__new__函数返回了什么, Foo就是什么!

class MyType(type):
    """
		我们看到一个类在创建的时候会向元类的__new__中传递三个值
		分别是类名、继承的基类、类的属性
    """
    def __new__(mcs, names, bases, attrs):
        print("mcs:", mcs)  # mcs: <class '__main__.MyType'> 当前类MyType!!
        print("names:", names)
        print("bases:", bases)
        print("attrs:", attrs)


"""
Foo指定metaclass, 表示Foo这个类由MyType创建
在前面,我们说类实例化过程中,__new__是为实例对象开辟内存的,那么MyType的实例对象是谁呢? 显然就是这里的Foo
简而言之, 因为Foo指定了metaclass为MyType, 所以Foo的类型就是MyType

但在这个例子中,Foo并没有被创建出来!!为何?
在前面我们已经说了,__new__一定要将创建的实例对象返回才可以,这里的MyType是元类
类对象Foo等于MyType的实例对象, MyType的__new__就负责为类对象Foo分配空间
但显然我们这里并没有分配, 而且返回的还是一个None, 如果我们返回的是123, 那么print(Foo)就是123
因为元类MyType里的__new__方法返回的值是None,So,Foo的类型是<class 'NoneType'>
"""
class Foo(object, metaclass=MyType):  # -- 指定元类MyType来创建Foo这个类
    pass


if __name__ == '__main__':
    print("===")
    print(Foo)
    print(type(Foo))

"""
mcs: <class '__main__.MyType'>
names: Foo
bases: (<class 'object'>,)
attrs: {'__module__': '__main__', '__qualname__': 'Foo'}
===
None
<class 'NoneType'>
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

创建类之前,可对类中的成员做点操作!!

class MyType(type):
    def __new__(mcs, names, bases, attrs):
        # ★ 创建类之前,可对类中的成员做点操作
        del attrs['v1']
        attrs['say'] = "Hello"
        # 等价于return type.__new__(MyType, names, bases, attrs) 表示类由MyType创建
        return super().__new__(mcs, names, bases, attrs)  # 创建类
        """注意:
        此处不能写成 type(name, bases, attr), 因为这样的话类还是由type创建的
        这样想就解释通了(´▽`)
        type(name, bases, attr) 等价于 type.__new__(type, name, bases, attr)
        """


class Foo(object, metaclass=MyType):
    v1 = 123

    def func(self):
        return 999


if __name__ == '__main__':
    print("===")
    for item in ["v1", "say"]:
        if hasattr(Foo, item):
            print(item, ":>>", getattr(Foo, item))

"""
===
say :>> Hello
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 继承情况

一个类在没有指定的metaclass的时候, 如果它的父类指定了, 那么这个类的metaclass等于父类的metaclass!!

class MyType(type):

    def __new__(mcs, name, bases, attr):
        name = name * 2
        return super().__new__(mcs, name, bases, attr)


class B(metaclass=MyType):
    pass


class A(B):
    pass


print(A.__class__)  # <class '__main__.MyType'> 等同于 type(A)
print(A.__name__)  # AA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 扩展

上面阐述的有关元类的知识点, 用于看drf序列器的源码已经足够了.. 在这里, 再做一点元类知识的扩展.

class MyType(type):
    def __new__(mcs, name, bases, attrs):
        print("创建类.")
        return super().__new__(mcs, name, bases, attrs)


class Base(object, metaclass=MyType):
    def __new__(cls, *args, **kwargs):
        print("创建类实例化对象.")
        return object.__new__(cls)

    def __init__(self, *args, **kwargs):
        print("类实例化对象初始化.")


if __name__ == '__main__':
    print("===")
    obj = Base()
    
"""
创建类.
===
创建类实例化对象.
类实例化对象初始化.
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

上述代码中 Base类实例化时,先new后init, 是如何触发的呢? 是由MyType中的call方法来触发的!!
★★★下面的程序能理清, 那元类就可以暂时毕业啦!! (⁎⁍̴̛ᴗ⁍̴̛⁎)

★注意思考清楚下述代码中的mcs、cls是啥! + 前面类的实例化小节那三条很重要的结论!!

class MyType(type):
    def __new__(mcs, name, bases, attrs):  # mcs --:> <class '__main__.MyType'>
        print("创建类.")
        return super().__new__(mcs, name, bases, attrs)

    def __call__(cls, *args, **kwargs):    # cls --:> <class '__main__.Base'>
        # 结合类的实例化小节那三条很重要的结论的验证示例,就能很快明白此处的__call__方法为何要这样写!!
        print("执行元类MyType的call方法.")
        obj = cls.__new__(cls, *args, **kwargs)
        print("---")
        cls.__init__(obj, *args, **kwargs)
        return obj


class Base(object, metaclass=MyType):
    def __new__(cls, *args, **kwargs):     # cls --:> <class '__main__.Base'>
        print("创建类实例化对象.")
        return object.__new__(cls)

    def __init__(self, *args, **kwargs):
        print("类实例化对象初始化.")

    def __call__(self, *args, **kwargs):
        return "Base.call"


if __name__ == '__main__':
    print("===")
    obj = Base()
    print(obj())

    
"""
创建类.
===
执行元类MyType的call方法.
创建类实例化对象.
---
类实例化对象初始化.
Base.call
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

Q: 思考个问题.为啥会触发元类MyType中的call方法呢?
A: 你这样想:
     如果我说,类实例化得到的对象加括号会触发类中的call方法,相当于 类()(), 没问题吧?! 嗯.这是call方法的常识.
     python处处皆对象.
     代入元类中,MyType()类实例化得到 Base类这个对象, Base这个对象再加括号. 相当于 MyType()()
     So, Base() 会触发MyType类中的call方法!!
     当然Base类实例化创建的对象加括号就会触发Base类里的call方法. ok, 这个解释闭环啦.


# 示例(源码)

1> UserSerializer类根据继承关系是由元类SerializerMetaclass创建的.
2> list(attrs.items()) 是浅拷贝, 之所以拷贝, 是因为对迭代对象循环的同时剔除迭代对象里面的元素,会遗漏一些元素!!

class SerializerMetaclass(type):
    def __new__(mcs, name, bases, attrs):
        # 在创建类之前做了一点小操作,细品. -- attrs是name中的成员,此处的name是UserSerializer.
        data_dict = {}
        for k, v in list(attrs.items()):
            if isinstance(v, int):
                data_dict[k] = attrs.pop(k)
        attrs['_declared_fields'] = data_dict
        return super().__new__(mcs, name, bases, attrs)


class BaseSerializer(object):
    pass


class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
    pass


class ModelSerializer(Serializer):
    pass


class UserSerializer(ModelSerializer):
    v1 = 111
    v2 = 222
    v3 = "world"


if __name__ == '__main__':
    print(UserSerializer._declared_fields)  # {'v1': 111, 'v2': 222}
    print(UserSerializer.v3)  # world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

解析器
序列化使用

← 解析器 序列化使用→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式