python基础35 元类、mixins机制

发布时间 2023-06-29 15:23:06作者: 初学程序员

Mixins机制

1.主类:就是大部分都是主要功能

2.辅类:就是一些辅助功能

3.辅类的类名也有讲究:一般以mixin、able、ible等结尾

4.继承的位置也有讲究,一般辅类在左边

class Vehicle:  # 交通工具
    def fly(self):
        '''
        飞行功能相应的代码        
        '''
        print("I am flying")


class CivilAircraft(Vehicle):  # 民航飞机
    pass


class Helicopter(Vehicle):  # 直升飞机
    pass


class Car(Vehicle):  # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
    pass

Mixins机制后的代码

class Vehicle:  # 交通工具
    pass


class FlyableMixin:
    def fly(self):
        '''
        飞行功能相应的代码        
        '''
        print("I am flying")


class CivilAircraft(FlyableMixin, Vehicle):  # 民航飞机
    pass


class Helicopter(FlyableMixin, Vehicle):  # 直升飞机
    pass


class Car(Vehicle):  # 汽车
    pass

元类简介

1.什么是元类?

  产生类的类

  type其实查看对象有那个类产生的

class MyClass(object):
    pass

obj = MyClass()
print(type(obj))# 查看obj是那个类产生的

你说我打印上述的type(MyClass) 它的结果应该是什么呢?

  结果就是<class 'type'>  ,那么就可以认为MyClass类就是有type类产生的

得出结论:我们之前使用class造出来的类都是有type类造出来的,就默认为type类是元类

产生类的两种方式

1.方式一:

  class 类名():

    pass

2.方式二:

  既然所有的类都是有type类产生的,那么我们也可以用type来产生类

  type(object_or_name, bases, dict)

  type("类名", "父类", "类的名称空间")

3.为什么要学习元类?

  元类是造出类的类,所以,我们可以对类进行高度的定制化

举个例子:
  我让你写出来的类名必须是首字母大写?
思考:我们的定制化代码在哪里写呢?
  类是如何产生的?类是有元类产生的type类,如果想改类的行为,应该在元类里的__init__方法中改.
  对象是如何产生的? 是执行了产生这个对象的类内部的__init__方法
推导:已知推出来的未知

  想改父类的__init__方法, 但是又不能修改源代码,所以我们可以写出来一个子类来继承父类type,在子类里面写代码,然后在从新执行一些父类的__init__方法.

class MyTypeClass(type):
    def __init__(self, cls_name, cls_bases=None, cls_dict=None):
        print(cls_name, cls_bases, cls_dict)  # C1 () {'__module__': '__main__', '__qualname__': 'C1'}
        # cls_name:它就是类名
        # 限制类名必须是首字母大写
        if not cls_name.istitle():
            raise Exception("类名必须是首字母大写")
        super().__init__(cls_name, cls_bases=None, cls_dict=None)
        
        
class C1(metaclass=MyTypeClass):
    school = 'Sh'

class a(metaclass=MyTypeClass): 类名没有大写就报错
    pass

元类进阶操作

  对象加括号会自动调用类的__call__方法,并且,__call__方法里面返回什么,那么,对象加括号的位置就是什么

推导:类名()会怎么样?
  类名(),应该是会执行产生类的类中的__call__方法,而这个类恰好是元类type

class MyClass(type):
    def __call__(self, *args, **kwargs):
        print("__call__ 执行了")
        print(args, kwargs)

        """限制传参的方式必须是关键字传参,只需要args是空就行"""
        if args:
            raise Exception("传参必须是关键字传参")

        super(MyClass, self).__call__(*args, **kwargs)


class C1(metaclass=MyClass):
    def __init__(self, name):
        print("__init__ 执行了")
        # self.name = name

看C1类里面的__init__方法和元类里面的__call__方法的执行顺序

  得出结论,其实在执行类的__init__之前,先执行了__call__方法

obj = C1(name='kevin')  # 都是位置传参,强制要求必须是关键字传参