一、Mixins机制
Mixins机制是一种在面向对象编程中用于代码复用的灵活机制,通过将特定功能的代码块注入到类中,增强了类的功能,同时保持了类的层次结构的简洁性和灵活性。
案例:
定义一个交通工具类,民航飞机和直升飞机、汽车都属与交通工具,继承交通工具类。
但是汽车不会飞,将fly的方法从交通工具类中提出来,做一个新类。
民航飞机和直升飞机继承多个类,汽车只继承交通工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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
1 2 3 4 5 6 7 8 9 |
class Vehicle: # 交通工具
pass
class Car(Vehicle): # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
pass
qiche = Vehicle()
print ( type (qiche)) # <class '__main__.Vehicle'>
print ( type (Vehicle)) # <class 'type'>
|
3、产生类的两种方式
方式1:
1 2 |
class 类名():
pass
|
方式2:
由于所有类都是有type类造出来的,所以我们也可以使用type类造出来一个新类
1 2 3 |
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用于指定元类
1 2 3 4 5 6 7 8 9 10 11 12 |
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__方法。
元类实例化类和类实例化对象的过程差不多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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'
。