请稍候,加载中....

元类与元编程

object类

object类是python中大多数类的祖先类.

class A:
    pass

print(A.__mro__)
print(object.__class__)

type类

type类是一个元类(元始的意思), 用于创建类的类.

元类就是创建与管理类的类,type是默认的元类

print(type.__class__)
# 这就是为什么很多内置的类型__class__都是type 
print(int.__class__) 
print(bool.__class__) 
print(tuple.__class__)
print(list.__class__)

元编程

通过元类可以在程序运行过程中动态创建类,这种编程方式称为元编程

type不但可以查看对象的类, 也可以创建类(所以称为元类)

# type(name, bases, attr)
# name - 类名
# bases - 元组形式的基类
# attr - 字典形式的类的属性

A = type("A", (), {"name":"luxp"})
# type与class语法其实是一回事情, type可以让我们拥有动态创建类的能力
# 相当于
# class MyClass:
#    name = "luxp"

# A是一个变量,指向新建的MyClass
print(A.__name__)
a = A()
print(a)
print(a.name)

自定义元类

在类定义的时候, 可以通过metaclass关键字指定元类

自定义元类示例1

这里使用一个函数作为元类(任何可调用对象都可以作为元类)

# 利用type动态创建类, 所有没有__前缀的属性名必须大写
def uppercase_attributes(name, bases, attrs):
    uppercase_attrs = {}
    for attr_name, attr_value in attrs.items():
        if not attr_name.startswith('__'):
            uppercase_attrs[attr_name.upper()] = attr_value
    return type(name, bases, uppercase_attrs)

# 元类
def MyMetaFunction(name, bases, attrs):
        print(name, bases, attrs)
        return uppercase_attributes(name, bases, attrs)

class MyClass(metaclass=MyMetaFunction):
    name = 'john'
    age = 30

在这个示例中, 通过元类可以控制创建的类的属性名保持大写

type子类元类

可以通过继承type类来自定义元类

type子类

# 普通类,没有指定元类,默认为type 
class A: 
    pass

print(A.__class__)

# 新元类
class NewMetaClass(type):
    pass

# 普通类,指定了元类 
class B(metaclass=NewMetaClass): 
    pass

print(B.__class__)

类的__class__属性指向他的元类,或者其最近的父类的元类

重写__new__方法示例

在这个例子中, 通过对__new__方法重写在元类中添加了对类属性的控制

# 自定义一个元类继承type
# 创建类时,会执行元类的__new__方法

class Coord3D(type):
    def __new__(cls, name, bases, attrs):
        # 只接受_x、_y、_z
        new_attrs = {"_x": attrs.get('_x', None),
                     "_y": attrs.get('_y', None),
                     "_z": attrs.get('_z', None)}
        # 调用父类的__new__方法创建类
        return super().__new__(cls, name, bases, new_attrs)

# 通过metaclass指定Coor3D是元类
# 在创建EarthCoord3D类时多余的_a\_b\_c会被过滤
class EarthCoord3D(metaclass=Coord3D):
    _x = 10
    _y = 10
    _z = 10
    _a = 100
    _b = 200
    _c = 300

print(EarthCoord3D.__dict__)
print(type(EarthCoord3D)

自定义元类应用示例2

根据环境变量不同, 创建不同的类

# 标准表单类
class NormalForm:
    input_field = "input"

# 安全表单类
class SafeForm:
    input_field = "safe_input"

# 环境变量
safe_status = "safe"

# 表单创建元类
class MetaForm(type):
    def __new__(cls, *args, **kwargs):
        name, bases, attrs = args
        # 修改了基类
        if safe_status == "safe" and NormalForm in bases:
            bases = (SafeForm,)
        return super().__new__(cls, name, bases, attrs)

# 不同环境变量下 
# safe_status = ""
class Form(NormalForm, metaclass=MetaForm):
    pass

print(Form.__mro__)
print(Form.input_field)
# 不同环境变量下
# safe_status = "safe" 
class Form(NormalForm, metaclass=MetaForm): 
    pass
print(Form.__mro__)
print(Form.input_field)

__subclasscheck__方法

issubclass 依赖于元类的__subclasscheck__方法

# A为元类
class A(type):
    def __subclasscheck__(self, subclass):
        print(self)
        if subclass in self.__subclasses__():
            print(f"{subclass} is {self}'s subclass")
            return True

class B(metaclass=A):
    pass

class C(B):
    pass

issubclass(B, C)
issubclass(C, B)

__instancecheck__方法

isinstance 依赖于类的__instancecheck__方法

class A(type):
    def __instancecheck__(self,  instance):
        print(self)
        print(instance)
        classes = instance.__class__.__mro__
        if self in classes:
            print(f"{instance} is {self}'s instance")
            return True

class B(metaclass=A):
    pass

class C(B):
    pass


c = C()
isinstance(c, C)
isinstance(c, B)

type类与object类关系

type类是用于创建类的类

object类是所有类的基类(所有对象的基类)

object类从类型上来属于type类

type类从对象继承关系上属于object类(type类也是一个对象)

# 从mro顺序上看type是object的子类
print(object.__mro__)
# (object,)

print(type.__mro__)
# (type, object)

# 通过bases属性查看
# 从__bases__属性(直接父类组成的元组)观察
# type是object子类
print(type.__bases__)
print(object.__bases__)

# 查看type是不是object的子类
issubclass(type, object)
# True

# object又是type的实例
isinstance(object, type)
# True

# type也是object的实例
isinstance(type, object)
# True

# 更狠的其实,他们也是各自自己的实例
isinstance(type, type)
isinstance(object, object)

# 那他们会不会是一个对象
print(type is object)

# 看上去type与object纠缠不清,甚至出现了先有鸡还是先有蛋的恍惚
# 其实type与object只是python类的两条线顶端
# type用于创建类,决定类长什么样
# object用于确定继承关系
# 出现这样的结果,是由于一些特殊方法得到的结果,这些方法可以控制结果
# __class__: 设定自己的元类类型(实例是类的情况)
# __bases__: 类型的基类-父类
# __instancecheck__: 检查是否是类的实例
# __subclasscheck__: 检查是否是类的子类

Python学习手册-