元类

元类

【一】什么是元类

  • 产生已知类的类就叫元类
def func():
#     ...
print(type(func))  # <class 'function'>
data_dict={'name':'hope'}
print(type(data_dict))
#<class 'dict'>

【二】产生类的两种方式

【1】使用关键字创建

class Person(object):
    ...
print(Person)    #<class '__main__.Person'>

【2】使用type创建

print(type('Person', (object,), {}))
#<class '__main__.Person'>

【3】type的参数

  • type(类的名字,类想要继承的父类,当前类内部的数据属性,实例化类的名称空间)

使用关键字

class Person(object):
    name='人类'
    def run(self):
        ...
print(Person)
print(Person.__bases__)
print(Person.__dict__)
#<class '__main__.Person'>
#(<class 'object'>,)
#{'__module__': '__main__', 'name': '人类', 'run': <function Person.run at 0x0000018A4279EF80>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

使用type

PersonType=type('Person',(object,), {'name':'人类','run':run})
print(PersonType)
print(PersonType.__bases__)
print(PersonType.__dict__)
#<class '__main__.Person'>
#(<class 'object'>,)
#{'__module__': '__main__', 'name': '人类', 'run': <function Person.run at 0x0000018A4279EF80>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

【3】总结type语法

  • 类名=type(类名,(父类1,父类2...),{类里面的数据属性})

【三】为什么要使用元类

  • 更高的定制我们的类的具体行为
  • 就相当于我们已经知道了具体的制作过程,我们可以在中间加点料

【四】如何使用元类

【1】需求

  • 定义一个类的时候,我这个类的名字只能大写字母开头,小写不行
# 【1】创建一个元类
# 【2】重写 type的 __init__ 方法
# 【3】类的名字、类的父类、类的名称空间
# 【4】对类的名字进行校验  调用父类 type 里面的 __init__ 方法 将需要的参数全都传进去
# 【5】创建一个自己的类 , metaclass=元类名字

【2】案例1:类的名字必须大写

class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
       super().__init__(class_name, class_bases, class_dict)
       print(f'这是 MyMeta  中的init方法被触发了')


    def __call__(self, *args, **kwargs):
        print('这是 MyMeta 中的 __call__ 方法被触发了')
        print(f'这是 MyMeta 中的{args}')
        print(f'这是 MyMeta 中的{kwargs}')
        obj=super().__call__(*args, **kwargs)
        return obj

class  MyClass(object,metaclass=MyType):
    def __init__(self,name):
        print('这是 MyClass 中的 init 方法被触发了')
        self.name=name
    def __call__(self, *args, **kwargs):
        print('这是 MyClass 中的 __call__ 方法被触发了')
        print(f'这是 MyClass 中的{args}')
        print(f'这是 MyClass 中的{kwargs}')

my_class=MyClass(name='hope')
print(my_class)
my_class()

#这是 MyMeta  中的init方法被触发了
#这是 MyMeta 中的 __call__ 方法被触发了
#这是 MyMeta 中的()
#这是 MyMeta 中的{'name': 'hope'}
#这是 MyClass 中的 init 方法被触发了
#<__main__.MyClass object at 0x000002E41C16C3D0>
#这是 MyClass 中的 __call__ 方法被触发了
#这是 MyClass 中的()
#这是 MyClass 中的{}
class_name = 'Myclass'
if not class_name.istitle():
    raise Exception("类的名字必须大写!")
else:
    class_name = type(class_name, (), {})
print(class_name)

案例2:参数只能按关键字传参

# 需求:定制初始化类的时候传参数必须是按照关键字传参,不能按位置传参

# 【1】写一个类 继承元类 type
# 【2】重写 type 的 __call__
# 【3】拦截到  __call__  带的位置参数和关键字参数
# 【4】限制你的不定长未知参数为空即可
# 【5】继承给 想使用的类
class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
       super().__init__(class_name, class_bases, class_dict)
       print(f'这是 MyMeta  中的init方法被触发了')


    def __call__(self, *args, **kwargs):
        print('这是 MyMeta 中的 __call__ 方法被触发了')
        print(f'这是 MyMeta 中的{args}')
        print(f'这是 MyMeta 中的{kwargs}')
         if args:
        	raise Exception(f'参数只能按照关键字传参')
        print(f'这是 MyMeta  中的 {kwargs}') 
        obj=super().__call__(*args, **kwargs)
        return obj

class  MyClass(object,metaclass=MyType):
    def __init__(self,name):
        print('这是 MyClass 中的 init 方法被触发了')
        self.name=name
    def __call__(self, *args, **kwargs):
        print('这是 MyClass 中的 __call__ 方法被触发了')
        print(f'这是 MyClass 中的{args}')
        print(f'这是 MyClass 中的{kwargs}')

my_class=MyClass(name='hope')
print(my_class)
my_class()
posted @ 2024-01-08 21:07  -半城烟雨  阅读(4)  评论(0编辑  收藏  举报