穿越到无限流中的女娲世界。
此世界存在两种关系,一种继承关系,子类继承父类,另一种类型实例关系,表现为某个类型的实例化。
第一:继承关系。
继承关系只发生在类型之间,而非实例。
女娲(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__,初始化战士的名字,性别等。