type(class_name, base_class, attrs)
# example
NewClass = type("NewCls", (), {"name":"bob"})
a = NewClass()
a.name
我们用type成功生成了一个类,他的意义在于,我可以在程序运行的过程中,使用代码动态的去定义一个类(*区别于那种传统的先用class定义完你用的类,然后实例化使用的方式*)
既然使用type可以动态创建类,代码种可能就会存在这样一种情况
cls = {"Ncls":{"bases":(), "attrs":{}}} (格式举例) cls_list = [] for k, v in cls_dict: new_cls = type(k, v["bases"], v["attrs"]) cls_list.append(new_lcs)
这里使用type,将一个字典或者列表,动态的转化生成一个类数组
def upper_attr(class_name, class_parents, class_attr):
attrs = ((name, value)
for name, value in class_attr.items() if not name.startswith('__'))
uppercase_attrs = dict((name.upper(), value) for name, value in attrs)
return type(class_name, class_parents, uppercase_attrs)
class NewCls(metaclass=upper_attr):
name = "lanix"
sex = "male"
NewCls.NAME # lanix
NewCls.name # AttributeError: type object 'NewCls' has no attribute 'name'
很明显,类定义时通过一个metaclass可以把定义的attrs中的属性key,全部变为大写, metaclass除了可以接受一个函数,也可以介绍一个type作为基类的类。类如
class UpperAttrMetaClass(type):
def __new__(mcs, class_name, class_parents, class_attr):
attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))
uppercase_attrs = dict((name.upper(), value) for name, value in attrs)
return super(UpperAttrMetaClass, mcs).__new__(mcs, class_name, class_parents, uppercase_attrs)
class NewCls(metaclass=UpperAttrMetaClass):
name = "lanix"
sex = "male"
两者可以实现同样的效果
在py2中, 使用元类(metaclass)可以这么写, 很多介绍metaclass的文章都是这样介绍的,而且当__metaclass__ = MyMetaClass 跟类定义同级别时,会成为所有同级别的类的元类。
class NewClass:
__metaclass__ = MyMetaClass
但是在py3版本中, 并不支持__metaclass__的写法,应该
class NewClass(metaclass=MyMetaClass):
pass
最简单的方式可以
class BadMan:
def __init__(self, name):
self.name = name
self.state = ''
def run(self):
print(f'{self.name} is runing!')
self.state = "run"
def fight(self):
print(f'{self.name} is fighting')
self.state = "fight"
b = BadMan("bob")
b.run()
定义都是固定不变的,不够灵活 ,也不够优雅。这里有一个使用metaclass的例子, 可以使用metaclass写一个fsm。
class Action(object):
def __init__(self, act_desc):
self.desc = act_desc
class ManMeta(type):
def __new__(cls, name, bases, attrs):
actives = {}
for k, v in attrs.items():
if isinstance(v, Action):
cls.add_action(actives, k, v)
attrs.update(actives)
return type.__new__(cls, name, bases, attrs)
@classmethod
def add_action(cls, action_dict, active_name, action_obj):
def active(self):
self.state = active_name
print(action_obj.desc)
action_dict[active_name] = active
class Hero(object, metaclass=ManMeta):
walk = Action("from on place to another")
fight = Action("use weapon to fight")
die = Action("your hero is dying now")
sleep = Action("fall asleep")
def __init__(self):
self.state = ""
这里首先定义了一个Active动作类,用来描述各种动作,
随后定义了一个metaclass,并使用这个metaclass 改变了Hero的创建过程,Hero.walk 定义中是一个 Action 实例,在ManMeta中,对这个walk这个属性进行了修改,变为一个类方法的定义函数,经过这一步神奇的转换之后。
z = Hero()
z.fight() # use weapon to fight
z.state # 'fight'
(给Action对象添加一个__call__(self) 也可以实现fight()调用,这里为了解释metaclass, 我们并不关心这些)