【学习笔记】python 元类

穿越到无限流中的女娲世界。

此世界存在两种关系,一种继承关系,子类继承父类,另一种类型实例关系,表现为某个类型的实例化。

第一:继承关系。

继承关系只发生在类型之间,而非实例。

女娲(object)------->人类(human)

女娲是创世神,是女娲世界一切的源头。

其也创造了人类,而人类继承了女娲的样子,在这里,我们只强调继承关系

class human(object):
    def __init__(self,name=None):
        self.name = name
print(human.__bases__)

输出(<class 'object'>,),human继承自object。

 

第二:类型实例关系

1,  女娲世界存在顶级灵体(类型),即元体(type)。由于女娲(object)这个世界的创世神,即便元体(type)也继承自女娲(object)。

print(type.__bases__)

  输出(<class 'object'>,),type是object的子类。

 

而作为顶级灵体,元体(type)的类型,也只能是它自己。

print(type.__class__)

  输出<class 'type'>

 

2,  同样,女娲(object)作为这个世界的至高存在,显化这这个世界,自然拥有顶级灵体,元体(type)。

print(object.__class__)

输出<class 'type'>,object的类型是type,也就是说object 是 type 的一个实例。

3,之前已经创造了human这个种族,继承自object,那么它的类型是什么?

class human(object):
    def __init__(self,name=None):
        self.name = name
print(human.__class__)
print(human.__bases__)

可以看到human这个类的类型依然是type,也就是type实例

 

而human的父类自然是object。

 

 

第三:捏一个叫小明的人

女娲想要捏一个叫小明的人,该怎么操作?只要在human类中显化一个实体即可,也就是实例化human这个类。

k=human(name='小明')
print(k.__class__)
print(k.__class__.__class__)
print(k.__bases__)#实例不显示继承关系

小明的类型<class '__main__.human'>,小明是'__main__.human'的实例化。

而类型的类型自然是顶级的<class 'type'>。

 

女娲(object)想这个太麻烦了,能不能简单一点

def fnc(self,name=None):
    return name
human=type('human',(object,),dict(name1=fnc))
print(human.__class__)

k=human().name1(name='小明')
print(k)

type这语句等价于之前class human(object)语句。

k是humna这个类的实例化。

==================================================================

原型:type(类名,基类元组(可以为空,用于继承), 包含属性或函数的字典)

以下两种写法都可以:

type('Class',(object,),dict(name1=fnc))

type('Class',(object,),{"name1":fnc})

1、class的名称,字符串形式,自定义的类名称;

2、继承的父类集合,注意Python支持多重继承,如果只有一个父类,注意tuple的单元素写法;
 

3、包含属性的字典(名称和值),class的方法名称与函数绑定,这里我们把函数fnc绑定到方法名name1上

 

坑:

A , dict(name1=fnc),这里把自定义的函数fnc赋值给name1这个属性,如果fnc函数需要传入参数,那么需要这样定义的dict(name1=fnc),只传递了函数并没有执行,在实例化human().name1(name='小明')中执行;

B , 如果自定义的函数fnc,不传入参数,函数返回或者打印。语句需要加():dict(name1=fnc()),相当于把fnc函数的结果赋值给name1属性,而不是函数本身。在实例化human().name1 时,方法name1不需要加()。

def fnc():
    return '小明'
human=type('human',(object,),dict(name1=fnc()))
print(human.__class__)
k=human().name1
print(k)

以上,其实自定义的fnc()函数,相当于直接给属性name1赋值了一个常量值。

等同于以下语句:

human=type('human',(object,),dict(name1='小明'))
print(human.__class__)

k=human().name1
print(k)

==================================================================

第四:制造战斗种族

女娲世界,遭遇异世界攻击,需要创作出战斗种族,特点是技能树快速增加,动态调用。

女娲(object)按照以往套路,先基于元体(type)捏一个战斗种族这一类型,并添加技能,最后实例化。这样不能实时动态调用新技能。

女娲这时想到基于元体(type)制作增强型的灵体。这些增强型的灵体,类型依然是type,而这个增强型的灵体,被称为元类。那么怎样制作元类?

class strongMetaclass(type):
    def __new__(cls,name,bases,attrs):
        count = 0
        attrs['__strongskills__']=[]#增加一个名叫'__strongskills__'的属性,其值为强化的技能一览表
        for key,value in attrs.items():
            if 'strong_' in key:
                attrs['__strongskills__'].append(key)
                count +=1
        attrs['__strongskills_numbers__'] = count#增加一个名叫'__strongskills_numbers'的属性,其值为强化技能的数量
        return type.__new__(cls,name,bases,attrs)

元体(type)默认的配置,存在type.__new__中,有四个参数(cls,name,bases,attrs),其中cls,代表将来创建的类;name,表示将来创建类的名称;bases,表示继承关系;attrs表示将来创建的类型的属性或者方法,这里的元类,相比较type的默认属性,我们专门新创建了两个属性。此外属性,以键值对的形式存在。
 

 

很明显,创建的这个strongMetaclass元类,继承自元体(type),故其父类是type;而其只是修改了type的部分属性,所以其类型依然是type。

也即是strongMetaclass元类:父类是type,类型也是type。

 

元类已经定义好,怎么样使用元类?

 

class strong_solider(object,metaclass=strongMetaclass):
    def __init__(self,name=None):
        self.name = name
    def get_skills(self,callback):
        skills = []
        skill = eval("self.{}()".format(callback))
        skills.append(skill)
        return skills
    def strong_run(self):
        return 'runing'
    def strong_swing(self):
        return 'swimming'
    def strong_fly(self):
        return 'flying'
    def strong_eat(self):
        return 'eatting'

注意:定义的strong_方法,仅仅返回一个字符串。所以,get_skills()方法,skills列表仅仅添加对应的一个字符串,return的skills,也就是含一个字符串的列表。

实例化及调用

solider1 =strong_solider(name='小明')
for i in range(solider1.__strongskills_numbers__):
    callback=solider1.__strongskills__[i]
    z=solider1.get_skills(callback)
    print(z)

实列化的战斗士兵,名字叫小明,都包含了元体(type)之外的两个属性,__strongskills_numbers__,__strongskills__。

 

第五:来看看创造战斗个体背后到底发生了什么

           第一步,基于type创建了一个元类,其实是改写了__new__这个类方法中的,attrs属性。并返回之。

            class strongMetaclass(type):

                   def  __new__(cls,name,bases,attrs):

                    。。。。。。。。。。

                         return type.__new__(cls,name,bases,attrs)

           【最后一个语句,也可以直接改写父类的__new__方法。

                          return supper(strongMetaclass,cls).__new__(cls,name,bases,attrs)】

           第二步,基于strongMetaclass

            class strong_soldier(object,metaclass=strongMetaclass):

                   def  __init__(self): 

                      pass

            第三步,实列化一个个体

             xiaoming = strong_soldier()

==================================================================

         在第二步定义strong_soldier类的时候:

         1. python会先在strong_soldier类中搜索是否有__metaclass__,

         2.如果没有,则在strong_soldier继承的父类中搜索__metaclass__,

         3.如果在所有的父类中都没搜到到__metaclass__,则在模块层面搜索,

         4.  如果依然没搜索到,就自动调用内置type来创建这个strong_soldier类。

幸运的是,我们直接在strong_soldier类中,传入了metaclass=strongMetaclass,自动创建了strong_soldier类。而创建了strong_soldier类时候,我们自动调用了元类的__new__方法。

 

       在第三步实例化xiaoming个体的时候,会自动执行strong_soldier类中定义的初始化__init__方法。

==================================================================

       总结如下 ,

          定义一个类,calss  s():,就是定义了这个类的,也就是战斗种族的整体结构。

          选择战斗种族的体质?就需要调用元类__new__方法来建。

          选好体质,就要生成一个战士,这是要调用__INIT__,初始化战士的名字,性别等。

          

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值