Mixins机制和元类

一、Mixins机制

Mixins机制是一种在面向对象编程中用于代码复用的灵活机制,通过将特定功能的代码块注入到类中,增强了类的功能,同时保持了类的层次结构的简洁性和灵活性。

案例:

定义一个交通工具类,民航飞机和直升飞机、汽车都属与交通工具,继承交通工具类。

但是汽车不会飞,将fly的方法从交通工具类中提出来,做一个新类。

民航飞机和直升飞机继承多个类,汽车只继承交通工具类

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

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

二、元类

1、什么是元类

产生类的类

2、查看元类type

class Vehicle:  # 交通工具
    pass

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

qiche = Vehicle()
print(type(qiche))  # <class '__main__.Vehicle'>
print(type(Vehicle)) # <class 'type'>

3、产生类的两种方式

方式1:

class 类名():
    pass

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

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

4、元类type和默认继承的基类object类的关系

元类(metaclass)是用于创建类的类。类是对象的蓝图,而元类则是类的蓝图。类定义了对象的属性和行为。

元类定义了类的属性和行为。

类的默认元类是type,它是Python中所有类的元类。当我们使用class关键字定义一个类时,实际上是通过type元类来创建该类的。

类的默认继承类是object,它是Python中所有类的隐式继承类。在Python 3中,如果没有显式指定基类,默认的基类是objectobject类提供了一些通用的方法和属性,例如__str__()__eq__()等。

元类和类的默认继承类object之间的关系是:

元类type用于创建类,而默认继承类object是所有类的基类。

元类定义了类的行为和属性,而默认继承类提供了一些通用的方法和属性。

5、元类不能被类直接继承

案例1:

自己定义一个元类,自定义元类继承type元类。实现类名首字母必须大写的自定义操作

metaclass用于指定元类

class MyTypeClass(type):
    def __init__(self, cls_name, cls_bases, cls_dict):
        # print(cls_name, cls_bases, cls_dict)
        if not cls_name.istitle():
            raise Exception("类名必须是首字母大写")
        super().__init__(cls_name, cls_bases, cls_dict)

class C1(metaclass=MyTypeClass):
    school = 'Sh'

class a(metaclass=MyTypeClass):
    pass

案例2:

元类里面也有__call__方法,当类加括号触发__call__方法。

元类实例化类和类实例化对象的过程差不多

class MyClass(type):  # 此处Mycalss是一个自定义元类,C1加括号触发下面的__call__方法
    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):
        self.name = name
        print("__init__ 执行了")
        # self.name = name


"""看C1类里面的__init__方法和元类里面的__call__方法的执行顺序"""
# 得出结论,其实在执行类的__init__之前,先执行了__call__方法

obj = C1(name='kevin')  # 都是位置传参,强制要求必须是关键字传参
# obj1 = C1(name='kevin1')
# __call__ 执行了
# () {'name': 'kevin'}
# __init__ 执行了

注解:

当创建C1类的实例obj时,会触发元类MyClass__call__()方法。该方法用于控制实例化过程,并在实例化之前执行一些自定义的逻辑。

在这段代码中,__call__()方法打印了argskwargs的值,并对传参方式进行了限制。args代表位置参数,kwargs代表关键字参数。

当你创建实例obj时,传入了关键字参数name='kevin',因此args为空,kwargs{'name': 'kevin'}

因此,输出结果有一个() {'name': 'kevin'}中的()代表空的位置参数,{'name': 'kevin'}代表关键字参数name的值为'kevin'

总结起来,输出结果有一个() {'name': 'kevin'}表示在执行元类MyClass__call__()方法时,没有传入位置参数,而关键字参数name的值为'kevin'

 

posted @ 2023-06-29 15:26  凡人半睁眼  阅读(35)  评论(0编辑  收藏  举报