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、
class 类名(): pass
方式2:
由于所有类都是有type类造出来的,所以我们也可以使用type类造出来一个新类
type(object_or_name, bases, dict) # 这三个条件就是造出来类的三个要素. type("类名", "父类", "类的名称空间")
4、元类type和默认继承的基类object类的关系
元类(metaclass)是用于创建类的类。类是对象的蓝图,而元类则是类的蓝图。类定义了对象的属性和行为。
元类定义了类的属性和行为。
类的默认元类是type
,它是Python中所有类的元类。当我们使用class
关键字定义一个类时,实际上是通过type
元类来创建该类的。
类的默认继承类是object
,它是Python中所有类的隐式继承类。在Python 3中,如果没有显式指定基类,默认的基类是object
。object
类提供了一些通用的方法和属性,例如__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__()
方法打印了args
和kwargs
的值,并对传参方式进行了限制。args
代表位置参数,kwargs
代表关键字参数。
当你创建实例obj
时,传入了关键字参数name='kevin'
,因此args
为空,kwargs
为{'name': 'kevin'}
。
因此,输出结果有一个() {'name': 'kevin'}
中的()
代表空的位置参数,{'name': 'kevin'}
代表关键字参数name
的值为'kevin'
。
总结起来,输出结果有一个() {'name': 'kevin'}
表示在执行元类MyClass
的__call__()
方法时,没有传入位置参数,而关键字参数name
的值为'kevin'
。