Python基础(二十): 元类

192 阅读3分钟

一、概念

  • 在Python中, 有一个概念, 那就是万物皆对象, 意思就是说, 在Python中, 所有的数据全部都是对象, 包括数据类型10和字符串"abc"

  • 可以使用__class__属性, 查看10"abc"的类型

num = 10
print(num.__class__)        # 打印: <class 'int'>

s = "abc"
print(s.__class__)        # 打印: <class 'str'>
  • 我们自己定义的类, 实例化的对象也可以使用__class__查看类型
class Person:
    pass
p = Person()
print(p.__class__)          # 打印: <class '__main__.Person'>
  • 现在我们知道, 上面的intstrPerson都是类

  • 实际上, 在Python中, 这些类本身也是一种对象, 我们称之为类对象

  • 我们可以使用类对象的__class__属性, 查看对象属于哪一个类

print(int.__class__)            # 打印: <class 'type'>
print(str.__class__)            # 打印: <class 'type'>
print(Person.__class__)         # 打印: <class 'type'>
  • 由打印可知, intstrPerson这三个类对象, 都是被type创建出来的

  • 我们再看看type__class__属性

print(type.__class__)           # 打印: <class 'type'>
  • 可以发现类对象type, 是由它本身类type创建出来的

  • type: Python中最底层的类, 我们称它为元类, 是一个能够创建出类对象的类

二、类对象的创建方式以及创建流程

  • 我们知道, 可以通过下面的方法定义一个类对象
class Dog:
    def run(self):
        print("奔跑吧" --- self)
  • 同时, 我们还可以使用元类type创建一个类对象

1、类的创建方式

  • 已知, 可以使用type(对象), 来查看对象的类型
num = 10
print(type(num))        # 打印: <class 'int'>
  • 实际上, type()函数还有另外一个使用方法, 那就是创建一个类对象

  • type("类名", (父类), {属性方法})

    • 类名: 要创建类的名称
    • (父类): 指定所创类对象的父类, 为空时表示没有父类
    • {属性方法}: 指定类对象有哪些类属性和方法
    • 返回值: 类对象
# 定义函数 run
def run(self):
    print("奔跑吧" --- self)

type("Dog", (), {"count" : 1, "run" : run})
  • 上面的代码就是创建了一个Dog类对象
  • 不过这段代码所创建的类对象并没有被任何变量引用, 所以我们无法使用, 想要使用必须使用一个变量接收
# 定义函数 run
def run(self):
    print("奔跑吧 --- ", self)

xxx = type("Dog", (), {"count" : 1, "run" : run})
  • 打印xxx, 查看它的类型
print(xxx)          # 打印: <class '__main__.Dog'>
  • 通过xxx创建一个属于Dog类的实例化对象
d = xxx()
print(d)            # 打印: <__main__.Dog object at 0x104a1f7f0>
  • 直接调用count属性和run方法
print(d.count)      # 打印: 1
d.run()             # 打印: 奔跑吧 ---  <__main__.Dog object at 0x10451f7f0>

2、类的创建流程

  • 上面已经给出了使用type创建一个类的方式, 实际上, 要创建一个类的时候, 并不是必须使用元类type, 我们也可以自己定义一个元类, 然后使用这个元类创建类

  • 在定义类的时候, 可以使用__metaclass__属性, 指定创建该类的元类

  • 假设, 现在有一个元类, 名字叫xxx, 我们可以使用下面的两种方法, 以xxx为元类创建类对象

class Person:
    __metaclass__ = xxx    
class Person(metaclass = xxx):
    pass
  • 默认情况下__metaclass__属性的值是空的, 创建类时, 会根据下面的流程查找创建类所需的元类
1. 查看自身是否有明确的__metaclass__属性
2. 查看父类是否存在__metaclass__属性
3. 查看模块是否存在__metaclass__属性
4. 通过内置的type这个元类, 来创建这个类对象
  • 当自身没有明确的__metaclass__属性时, 使用父类的__metaclass__创建类对象
class Animal:
    __metaclass__ = xxx
    
class Person(Animal):
    pass
  • 当父类也没有__metaclass__属性时, 使用模块中的__metaclass__属性创建类对象
__metaclass__ = xxx

class Person:
    pass
  • 如果连模块中也没有明确的__metaclass__属性, 此时就会使用Python内置的type元类, 创建类对象
class Person:
    pass