python基础day35 Mixins机制和元类

发布时间 2023-06-29 16:29:02作者: 追逐的小白

Mixins机制

class Vehicle:  # 交通工具
    pass

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

'''
1. 主类:就是大部分都是主要的功能
2. 辅类:就是一些辅助的功能
3. 辅类的类名也有讲究:一般以mixin、able、ible等结尾
4. 继承的位置也有讲究:一般辅类在左边,主类在右边
'''
class CivilAircraft(FlyMinix, Vehicle):  # 民航飞机
    pass


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

元类简介

# 什么是元类?
    # 即产生类的类
'''type其实查看的就是对象是由哪个类产生的'''
class MyClass(object):
    pass

obj = MyClass()

# <class '__main__.MyClass'>
print(type(obj)) # 可以查看出obj对象是有哪个类产生的

'''打印type(MyClass)结果会是什么呢?'''
class type(object):
print(type(MyClass))  # <class 'type'>  我就可以认为MyClass类就是有type类产生的

class Student():
    pass

# print(type(Student)) # <class 'type'>


class C1():
    pass

print(type(C1))  # <class 'type'>

'''
得出结论:我们之前使用class造出来的类都是由type类造出来的
所以说默认情况下,所有的类的元类都是type
'''

产生类的两种方式

1. class 类名():

  pass

2. 由于所有的类都是由type类造出来的,所以我们也可以使用type类造出来一个新类

type(object_or_name, bases, dict)
    # 这三个条件就是造出来类的三个要素.
    # type("类名", "父类", "类的名称空间")

3. 为什么要学习元类?

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

eg:

  限定写出的类名必须是首字母大写的

  思考:定制化代码在哪里写?

     类是如何产生的?类是由元类产生的type类,如果想改类的行为,应该在元类里的__init__方法中改。

        对象是如何产生的?是执行了产生这个对象的类内部的__init__方法

推导:已知推出来的未知

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

ps:元类不能直接继承

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__方法里面返回神恶魔,那么对象加括号的位置就是什么
# 推导:类名()会怎么样?
'''类名(),应该会执行产生类的类中的__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')  # 都是位置传参,强制要求必须是关键字传参