Python之Mixins机制

发布时间 2023-07-03 16:20:45作者: Way*yy

Mixins机制

class Vehicle:  # 交通工具
    pass


class FlyMinix:
    """
        将主类中有多个子类要继承的方法单独拿出来,重新定义一个类,将这个有给有需要的子类继承,在主类中不再写这个方法
    """
    def fly(self):
        """
            跟飞行相关的功能
        :return: 
        """
        print("I am flying")


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


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


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


"""
1. 主类:就是大部分都是主要的功能
2. 辅类:就是一些辅助的功能
3. 辅类的类名也有讲究:一般以mixin、able、ible等结尾
4. 继承的位置也有讲究:一般辅类在主类的左边,
"""

元类的介绍

在了解元类之前我们做一些推理
1、什么是对象呢?
	'对象是不是就是调用了类产生了对象'
2、那么类又是怎么产生的呢?
	'按照对象产生的逻辑,那么“我们创建的类”是不是就是通过调用另一个类所产生的新类'
3、既然我们知道了类是如何产生的以后,那么我们再说说什么是元类?
	'元类就是产生了类的类就是元类,即“type”'
    说到这里可能就奇怪了,type不是查看数据类型的吗
    比如 : print(type(123))  # <class 'int'>
    其实在没有学类之前,type的功能确实质数查看数据类型,但是当我们学完类以后就应该知道,type查看的其实是"""对象是有哪个类产生的!"""
Eg:
    class Myclass:
        pass


    obj = Myclass()
    print(type(obj))  # <class '__main__.Myclass'> 说明obj这个对象是由Myclass产生的

    # 如果打印Myclass呢
    print(type(Myclass))  # <class 'type'>
    #  那我们是不是就可以理解为Myclass这个类是由type这个类产生的
    
"""得出结论:我们之前使用class造出来的类都是有type类造出来的"""
"""我们说默认情况下,所有的类的元类就是type"""

产生类的两种方式

1. class 类名
	pass

2. 由于所有类的元类都是type,那么我们是不是也可以使用type创建类
	type(object_or_name, bases, dict)
    # 这三个参数是造出类的三个要素
    type("类名","父类","类的名称空间")
    
3.为什么要学习元类?
"""
	元类就是造出类的类,所以,我们使用type创建类可以为类定制化,一些办法
	
	举个例子:
			我让你写出来的类名必须是首字母大写?
		
		思考:我们的定制化代码在哪里写呢?
			类是如何产生的?类是有元类产生的type类,如果想改类的行为,应该在元类里的__init__方法中改.
			
			对象是如何产生的? 是执行了产生这个对象的类内部的__init__方法
			
	推导:已知推出来的未知.
"""
	# 想改父类的__init__方法, 但是又不能修改源代码,所以我们可以写出来一个子类来继承父类type,在子类里面写代码,然后在从新执行一些父类的__init__方法.

Eg:
    class Myclass(type):
        def __init__(cls, cls_name, cls_bases=None, cls_dict=None):
            # print(cls_name, cls_bases, cls_dict)
            #  A () {'__module__': '__main__', '__qualname__': 'A'}
            if not cls_name.istitle():
                raise Exception('首字母必须是大写')
            super().__init__(cls_name, cls_bases, cls_dict)


    # 元类不能直接被继承需要使用metaclass
    class A(metaclass=Myclass):
        pass


    a = A()


    class b(metaclass=Myclass):
        pass


    c = b()
    # Exception: 首字母必须是大写

元类的进阶操作

__call__方法

# 对象加括号会自动调用类的__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')  # 都是位置传参,强制要求必须是关键字传参