python当中的metaclass使用

python当中的metaclass

简单介绍

  • python中对象也是类,类作为一种特别的对象存在,特别之处就在于可以作为一个模板来生成对象(所有的类都是),暂且把python中的类称为类对象,类对象使用class定义。
  • 除了class定义, 我们也可以用type来创建一个类。
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,将一个字典或者列表,动态的转化生成一个类数组

  • metaclasss有什么用?type可以创建类,如果存在一个方法,返回一个type动态创建的类,在使用class定义类的时候,把这个方法赋值给metaclass,就可以实现动态的改变class的定义。代码说明一切,这里用py3语法。
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/3版本中的差别。网上搜索到的很多文章都是错的,这真让我崩溃

在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, 我们并不关心这些)

metaclass最成功的案例可以百度python orm 实现,metaclass最重要的是提供了一种灵活的类定义的方式。
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值